<h5 dir="auto">Description of the problem</h5>
<p dir="auto">I noticed that there was a significant slowdown in the app I'm developing. I narrowed it down to being caused by initMaterial being called each frame under certain very specific conditions</p>
<p dir="auto">. The minimum requirements to reproduce the bug (afaik) are:</p>
<ul dir="auto">
<li>Create two meshes which share the same MeshLambertMaterial.</li>
<li>Create two scenes and add the meshes to them.</li>
<li>Create a single DirectionalLight in one of the scenes, not both.</li>
<li>Create an OrthographicCamera overlooking the objects (not a perspective camera).</li>
<li>Call render twice, once for each scene.</li>
</ul>
<p dir="auto">If you don't notice the slowdown, use the performance tab in Firefox to measure the performance and you should see WebGLShader at the top of the call tree.</p>
<ul dir="auto">
<li><a href="https://codepen.io/Donitz/pen/BPjyJN" rel="nofollow">Live sample</a></li>
</ul>
<h5 dir="auto">Three.js version</h5>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Dev</li>
</ul>
<h5 dir="auto">Browser</h5>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Firefox</li>
</ul>
<h5 dir="auto">OS</h5>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Windows</li>
</ul>
<p dir="auto"><code class="notranslate">WebGLLights</code> is used to store lighting state.<br>
<code class="notranslate">WebGLLights.hash</code> property is used to determine whether or not a material needs to be re-built.</p>
<p dir="auto"></p><div class="Box Box--condensed my-2">
  <div class="Box-header f6">
    <p class="mb-0 text-bold">
      <a href="https://github.com/mrdoob/three.js/blob/bd63a6cc8dd7fe11b530410fab9f67a9de359be8/src/renderers/WebGLRenderer.js#L1479-L1482">three.js/src/renderers/WebGLRenderer.js</a>
    </p>
    <p class="mb-0 color-fg-muted">
        Lines 1479 to 1482
      in
      <a data-pjax="true" class="commit-tease-sha" href="/mrdoob/three.js/commit/bd63a6cc8dd7fe11b530410fab9f67a9de359be8">bd63a6c</a>
    </p>
  </div>
  <div itemprop="text" class="Box-body p-0 blob-wrapper blob-wrapper-embedded data">
    <table class="highlight tab-size mb-0 js-file-line-container" data-tab-size="8" data-paste-markdown-skip="">

        <tbody><tr class="border-0">
          <td id="L1479" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="1479"></td>
          <td id="LC1479" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-k">if</span> <span class="pl-kos">(</span> <span class="pl-s1">materialProperties</span><span class="pl-kos">.</span><span class="pl-c1">lightsHash</span> <span class="pl-c1">!==</span> <span class="pl-s1">lights</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">.</span><span class="pl-c1">hash</span> <span class="pl-kos">)</span> <span class="pl-kos">{</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L1480" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="1480"></td>
          <td id="LC1480" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
        </tr>

        <tr class="border-0">
          <td id="L1481" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="1481"></td>
          <td id="LC1481" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> 	<span class="pl-s1">properties</span><span class="pl-kos">.</span><span class="pl-en">update</span><span class="pl-kos">(</span> <span class="pl-s1">material</span><span class="pl-kos">,</span> <span class="pl-s">'lightsHash'</span><span class="pl-kos">,</span> <span class="pl-s1">lights</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">.</span><span class="pl-c1">hash</span> <span class="pl-kos">)</span><span class="pl-kos">;</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L1482" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="1482"></td>
          <td id="LC1482" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> 	<span class="pl-s1">programChange</span> <span class="pl-c1">=</span> <span class="pl-c1">false</span><span class="pl-kos">;</span> </td>
        </tr>
    </tbody></table>
  </div>
</div>
<p></p>
<p dir="auto">The way <code class="notranslate">hash</code> is built, it includes unique reference to <code class="notranslate">WebGLLights</code> instance:<br>
</p><div class="Box Box--condensed my-2">
  <div class="Box-header f6">
    <p class="mb-0 text-bold">
      <a href="https://github.com/mrdoob/three.js/blob/efeb95f10790ab4755171584139d5344177f2713/src/renderers/webgl/WebGLLights.js#L319">three.js/src/renderers/webgl/WebGLLights.js</a>
    </p>
    <p class="mb-0 color-fg-muted">
         Line 319
      in
      <a data-pjax="true" class="commit-tease-sha" href="/mrdoob/three.js/commit/efeb95f10790ab4755171584139d5344177f2713">efeb95f</a>
    </p>
  </div>
  <div itemprop="text" class="Box-body p-0 blob-wrapper blob-wrapper-embedded data">
    <table class="highlight tab-size mb-0 js-file-line-container" data-tab-size="8" data-paste-markdown-skip="">

        <tbody><tr class="border-0">
          <td id="L319" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="319"></td>
          <td id="LC319" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-s1">state</span><span class="pl-kos">.</span><span class="pl-c1">hash</span> <span class="pl-c1">=</span> <span class="pl-s1">state</span><span class="pl-kos">.</span><span class="pl-c1">id</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">directionalLength</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">pointLength</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">spotLength</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">rectAreaLength</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">hemiLength</span> <span class="pl-c1">+</span> <span class="pl-s">','</span> <span class="pl-c1">+</span> <span class="pl-s1">shadows</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">;</span> </td>
        </tr>
    </tbody></table>
  </div>
</div>
<p></p>
<p dir="auto">constructor:<br>
</p><div class="Box Box--condensed my-2">
  <div class="Box-header f6">
    <p class="mb-0 text-bold">
      <a href="https://github.com/mrdoob/three.js/blob/efeb95f10790ab4755171584139d5344177f2713/src/renderers/webgl/WebGLLights.js#L103-L111">three.js/src/renderers/webgl/WebGLLights.js</a>
    </p>
    <p class="mb-0 color-fg-muted">
        Lines 103 to 111
      in
      <a data-pjax="true" class="commit-tease-sha" href="/mrdoob/three.js/commit/efeb95f10790ab4755171584139d5344177f2713">efeb95f</a>
    </p>
  </div>
  <div itemprop="text" class="Box-body p-0 blob-wrapper blob-wrapper-embedded data">
    <table class="highlight tab-size mb-0 js-file-line-container" data-tab-size="8" data-paste-markdown-skip="">

        <tbody><tr class="border-0">
          <td id="L103" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="103"></td>
          <td id="LC103" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">var</span> <span class="pl-s1">count</span> <span class="pl-c1">=</span> <span class="pl-c1">0</span><span class="pl-kos">;</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L104" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="104"></td>
          <td id="LC104" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
        </tr>

        <tr class="border-0">
          <td id="L105" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="105"></td>
          <td id="LC105" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">function</span> <span class="pl-v">WebGLLights</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L106" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="106"></td>
          <td id="LC106" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
        </tr>

        <tr class="border-0">
          <td id="L107" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="107"></td>
          <td id="LC107" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> 	<span class="pl-k">var</span> <span class="pl-s1">cache</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">UniformsCache</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L108" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="108"></td>
          <td id="LC108" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
        </tr>

        <tr class="border-0">
          <td id="L109" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="109"></td>
          <td id="LC109" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> 	<span class="pl-k">var</span> <span class="pl-s1">state</span> <span class="pl-c1">=</span> <span class="pl-kos">{</span> </td>
        </tr>

        <tr class="border-0">
          <td id="L110" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="110"></td>
          <td id="LC110" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
        </tr>

        <tr class="border-0">
          <td id="L111" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="111"></td>
          <td id="LC111" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> 		<span class="pl-c1">id</span>: <span class="pl-s1">count</span> <span class="pl-c1">++</span><span class="pl-kos">,</span> </td>
        </tr>
    </tbody></table>
  </div>
</div>
<p></p>
<p dir="auto">this means that if you have 2 instances of <code class="notranslate">WebGLLights</code> and they are identical, except for <code class="notranslate">id</code> - you will end up rebuilding materials as you switch between these instances - inefficient.</p>
<p dir="auto">Another problem with the current approach is that it is probabilistic, it's possible that <code class="notranslate">hash</code> remains the same even though lighting has changed.</p>
<p dir="auto">I propose following:</p>
<ul dir="auto">
<li>remove <code class="notranslate">id</code> from <code class="notranslate">hash</code> calculation</li>
<li>use a fast hashing function to compute 64bit hash(javascript <code class="notranslate">number</code> is IEEE 64-bit Float) instead of using a string</li>
<li>pass more than just number of lights into the <code class="notranslate">hash</code> (as long as that makes sense).</li>
</ul>