<p dir="auto">In my experience most colors in 3D graphics are 4 channel colors (red, green, blue and alpha.)  It is only a subset of situations in 3D graphics where a 3 channel color is sufficient and usually that deals with solid surface shading algorithms.</p>
<p dir="auto">Many situation, such as windows with varying transparent, volume effects and particle effects often need RGBA-based colors.  Also blending algorithms where one engages in post-processing one also often needs 4 channel-based colors.</p>
<p dir="auto">Thus I propose creating a Color4 class that enables easy usage of 4-channel colors.</p>
<p dir="auto">NOTE: I am unsure of the best way to share the conversion code that is fairly common (and bulky) between Color4 and the existing Color (which I suggest renaming Color3.)</p>
<p dir="auto">Here is my proposed Color4 class:</p>
<p dir="auto"><strong>Color4</strong></p>
<p dir="auto">properties:</p>
<ul dir="auto">
<li>r as Scalar</li>
<li>g as Scalar</li>
<li>b as Scalar</li>
<li>a as Scalar // a is last so that it matches OpenGL/WebGL style: <a href="http://goo.gl/GKuD8" rel="nofollow">http://goo.gl/GKuD8</a></li>
</ul>
<p dir="auto">methods:</p>
<ul dir="auto">
<li>set( value )</li>
<li>setRGBA( r, g, b, a )</li>
<li>setHSV( h, s, v ) // centralize in helper as HSV doesn't have alpha</li>
<li>setStyle( style as string ) // centralize in helper</li>
<li>setHex( hex as Integer )</li>
<li>copy( color as Color4 )</li>
<li><em>copyGammaToLinear( color as Color4 )</em> // I think we don't need this on either Color/Color3 or Color4, just use copy(..).convertGammaToLinear()</li>
<li><em>copyLinearToGamma( color as Color4 )</em> // I think we don't need this on either Color/Color3 or Color4, just use copy(..).convertLinearToGamma()</li>
<li>convertGammaToLinear()</li>
<li>convertLinearToGamma()</li>
<li>getHex() // centralize in helper ?</li>
<li>getHexString() // centralize in helper</li>
<li>getStyle() // centralize in helper</li>
<li>getHSV() // centralize in helper as HSV doesn't include alpha</li>
<li>lerpSelf( color as Color4, alpha as Scalar )</li>
<li>clone()</li>
<li>bool equals( color as Color4 ) // this needs to be added to Color/Color3</li>
</ul>
<p dir="auto">In order to load an object it is required to first load the material <code class="notranslate">MTLoader</code> and then load the object <code class="notranslate">OBJLoader</code><br>
Because the name of the .mtl is written in the .obj (eg <code class="notranslate">mtllib male02.mtl</code>), I'd expect the OBJLoader to automatically load the material</p>
<p dir="auto"><a href="https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_obj_mtl.html#L75">https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_obj_mtl.html#L75</a></p>
<p dir="auto">Currenlty I have to do :</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="  var materials = await new MTLLoader()
    .loadAsync(&quot;https://example.com/obj/male02.mtl&quot;)
  materials.preload() //load imgs
  var group = await new OBJLoader()
    .setMaterials(materials)
    .loadAsync(&quot;https://example.com/obj/male02.obj&quot;)"><pre class="notranslate">  <span class="pl-k">var</span> <span class="pl-s1">materials</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-k">new</span> <span class="pl-v">MTLLoader</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
    <span class="pl-kos">.</span><span class="pl-en">loadAsync</span><span class="pl-kos">(</span><span class="pl-s">"https://example.com/obj/male02.mtl"</span><span class="pl-kos">)</span>
  <span class="pl-s1">materials</span><span class="pl-kos">.</span><span class="pl-en">preload</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c">//load imgs</span>
  <span class="pl-k">var</span> <span class="pl-s1">group</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-k">new</span> <span class="pl-v">OBJLoader</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
    <span class="pl-kos">.</span><span class="pl-en">setMaterials</span><span class="pl-kos">(</span><span class="pl-s1">materials</span><span class="pl-kos">)</span>
    <span class="pl-kos">.</span><span class="pl-en">loadAsync</span><span class="pl-kos">(</span><span class="pl-s">"https://example.com/obj/male02.obj"</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">but I'd like to do</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="  var group = await new OBJLoader()
    .loadAsync(&quot;https://example.com/obj/male02.obj&quot;)"><pre class="notranslate">  <span class="pl-k">var</span> <span class="pl-s1">group</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-k">new</span> <span class="pl-v">OBJLoader</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
    <span class="pl-kos">.</span><span class="pl-en">loadAsync</span><span class="pl-kos">(</span><span class="pl-s">"https://example.com/obj/male02.obj"</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">To avoid complexifing too much OBJLoader, we could think having OBJMTLLoader something like :</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class OBJMTLLoader extends OBJLoader {
  load(url, onLoad, onProgress, onError) {
   // make sure that path is set
    if(!this.path) { //if the url provided is full url not fn
      this.setPath(url.substr(0,url.lastIndexOf('/'))) //FIXME dirname
      url = url.substr(url.lastIndexOf('/')) //url is fn
    }

    const scope = this
    const loader = new FileLoader(this.manager)
    loader.setPath(this.path)
    loader.setRequestHeader(this.requestHeader)
    loader.setWithCredentials(this.withCredentials)
    loader.load(url, text =&gt; {
      this.parseMtlAndLoad(text,  () =&gt;{
        try {
          onLoad(scope.parse(text))
        } catch (e) {
          if (onError) {
            onError(e)
          } else {
            console.error(e)
          }
          scope.manager.itemError(url)
        }
      })
    }, onProgress, onError)
  }

  parseMtlAndLoad(text, onLoadMtl) {
    if(!this.materials) { //do not load a material if already provided
      let idxStart = text.indexOf(&quot;mtllib &quot;)
      let idxEnd = text.indexOf(&quot;.mtl&quot;)
      if (idxStart !== -1 &amp;&amp; idxEnd !== -1 &amp;&amp; idxEnd - idxStart &gt; 7) {
        var mtlFn = text.substring(idxStart + 7, idxEnd + 4); //to be improved, regex with end/start line; if has multiple mtl?
        new MTLLoader().loadAsync(this.path + &quot;/&quot; + mtlFn).then(materials =&gt; {
          materials.preload()
          this.setMaterials(materials)
          onLoadMtl()
        })
      }
    } else {
      onLoadMtl()
    }
  }
}"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">OBJMTLLoader</span> <span class="pl-k">extends</span> <span class="pl-v">OBJLoader</span> <span class="pl-kos">{</span>
  <span class="pl-en">load</span><span class="pl-kos">(</span><span class="pl-s1">url</span><span class="pl-kos">,</span> <span class="pl-s1">onLoad</span><span class="pl-kos">,</span> <span class="pl-s1">onProgress</span><span class="pl-kos">,</span> <span class="pl-s1">onError</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-c">// make sure that path is set</span>
    <span class="pl-k">if</span><span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">path</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-c">//if the url provided is full url not fn</span>
      <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">setPath</span><span class="pl-kos">(</span><span class="pl-s1">url</span><span class="pl-kos">.</span><span class="pl-en">substr</span><span class="pl-kos">(</span><span class="pl-c1">0</span><span class="pl-kos">,</span><span class="pl-s1">url</span><span class="pl-kos">.</span><span class="pl-en">lastIndexOf</span><span class="pl-kos">(</span><span class="pl-s">'/'</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-c">//FIXME dirname</span>
      <span class="pl-s1">url</span> <span class="pl-c1">=</span> <span class="pl-s1">url</span><span class="pl-kos">.</span><span class="pl-en">substr</span><span class="pl-kos">(</span><span class="pl-s1">url</span><span class="pl-kos">.</span><span class="pl-en">lastIndexOf</span><span class="pl-kos">(</span><span class="pl-s">'/'</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-c">//url is fn</span>
    <span class="pl-kos">}</span>

    <span class="pl-k">const</span> <span class="pl-s1">scope</span> <span class="pl-c1">=</span> <span class="pl-smi">this</span>
    <span class="pl-k">const</span> <span class="pl-s1">loader</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">FileLoader</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">manager</span><span class="pl-kos">)</span>
    <span class="pl-s1">loader</span><span class="pl-kos">.</span><span class="pl-en">setPath</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">path</span><span class="pl-kos">)</span>
    <span class="pl-s1">loader</span><span class="pl-kos">.</span><span class="pl-en">setRequestHeader</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">requestHeader</span><span class="pl-kos">)</span>
    <span class="pl-s1">loader</span><span class="pl-kos">.</span><span class="pl-en">setWithCredentials</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">withCredentials</span><span class="pl-kos">)</span>
    <span class="pl-s1">loader</span><span class="pl-kos">.</span><span class="pl-en">load</span><span class="pl-kos">(</span><span class="pl-s1">url</span><span class="pl-kos">,</span> <span class="pl-s1">text</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
      <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">parseMtlAndLoad</span><span class="pl-kos">(</span><span class="pl-s1">text</span><span class="pl-kos">,</span>  <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span><span class="pl-kos">{</span>
        <span class="pl-k">try</span> <span class="pl-kos">{</span>
          <span class="pl-s1">onLoad</span><span class="pl-kos">(</span><span class="pl-s1">scope</span><span class="pl-kos">.</span><span class="pl-en">parse</span><span class="pl-kos">(</span><span class="pl-s1">text</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
        <span class="pl-kos">}</span> <span class="pl-k">catch</span> <span class="pl-kos">(</span><span class="pl-s1">e</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
          <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">onError</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
            <span class="pl-s1">onError</span><span class="pl-kos">(</span><span class="pl-s1">e</span><span class="pl-kos">)</span>
          <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span>
            <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">error</span><span class="pl-kos">(</span><span class="pl-s1">e</span><span class="pl-kos">)</span>
          <span class="pl-kos">}</span>
          <span class="pl-s1">scope</span><span class="pl-kos">.</span><span class="pl-c1">manager</span><span class="pl-kos">.</span><span class="pl-en">itemError</span><span class="pl-kos">(</span><span class="pl-s1">url</span><span class="pl-kos">)</span>
        <span class="pl-kos">}</span>
      <span class="pl-kos">}</span><span class="pl-kos">)</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-s1">onProgress</span><span class="pl-kos">,</span> <span class="pl-s1">onError</span><span class="pl-kos">)</span>
  <span class="pl-kos">}</span>

  <span class="pl-en">parseMtlAndLoad</span><span class="pl-kos">(</span><span class="pl-s1">text</span><span class="pl-kos">,</span> <span class="pl-s1">onLoadMtl</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">if</span><span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">materials</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-c">//do not load a material if already provided</span>
      <span class="pl-k">let</span> <span class="pl-s1">idxStart</span> <span class="pl-c1">=</span> <span class="pl-s1">text</span><span class="pl-kos">.</span><span class="pl-en">indexOf</span><span class="pl-kos">(</span><span class="pl-s">"mtllib "</span><span class="pl-kos">)</span>
      <span class="pl-k">let</span> <span class="pl-s1">idxEnd</span> <span class="pl-c1">=</span> <span class="pl-s1">text</span><span class="pl-kos">.</span><span class="pl-en">indexOf</span><span class="pl-kos">(</span><span class="pl-s">".mtl"</span><span class="pl-kos">)</span>
      <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">idxStart</span> <span class="pl-c1">!==</span> <span class="pl-c1">-</span><span class="pl-c1">1</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">idxEnd</span> <span class="pl-c1">!==</span> <span class="pl-c1">-</span><span class="pl-c1">1</span> <span class="pl-c1">&amp;&amp;</span> <span class="pl-s1">idxEnd</span> <span class="pl-c1">-</span> <span class="pl-s1">idxStart</span> <span class="pl-c1">&gt;</span> <span class="pl-c1">7</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">var</span> <span class="pl-s1">mtlFn</span> <span class="pl-c1">=</span> <span class="pl-s1">text</span><span class="pl-kos">.</span><span class="pl-en">substring</span><span class="pl-kos">(</span><span class="pl-s1">idxStart</span> <span class="pl-c1">+</span> <span class="pl-c1">7</span><span class="pl-kos">,</span> <span class="pl-s1">idxEnd</span> <span class="pl-c1">+</span> <span class="pl-c1">4</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">//to be improved, regex with end/start line; if has multiple mtl?</span>
        <span class="pl-k">new</span> <span class="pl-v">MTLLoader</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">loadAsync</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">path</span> <span class="pl-c1">+</span> <span class="pl-s">"/"</span> <span class="pl-c1">+</span> <span class="pl-s1">mtlFn</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">then</span><span class="pl-kos">(</span><span class="pl-s1">materials</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
          <span class="pl-s1">materials</span><span class="pl-kos">.</span><span class="pl-en">preload</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
          <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">setMaterials</span><span class="pl-kos">(</span><span class="pl-s1">materials</span><span class="pl-kos">)</span>
          <span class="pl-s1">onLoadMtl</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
        <span class="pl-kos">}</span><span class="pl-kos">)</span>
      <span class="pl-kos">}</span>
    <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span>
      <span class="pl-s1">onLoadMtl</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>