<h5 dir="auto">Reading data from renderTarget does not work on iOS</h5>
<p dir="auto">Example: <a href="https://jsfiddle.net/9n0bha3v/1/" rel="nofollow">https://jsfiddle.net/9n0bha3v/1/</a><br>
QR Code to Example:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/22028624/92979599-8d869a00-f493-11ea-9755-a782a625193c.png"><img src="https://user-images.githubusercontent.com/22028624/92979599-8d869a00-f493-11ea-9755-a782a625193c.png" alt="image" style="max-width: 100%;"></a></p>
<p dir="auto">What the example is supposed to do:<br>
On desktop browsers (tested on Chrome, Safari - latest MacOS) you can <strong>click on the webGL canvas</strong> and<br>
the pixels are being read into a Uint8Array.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function readPixels(renderer, scene, camera, renderTarget) {
	
  const {width, height} = renderer.getDrawingBufferSize(new THREE.Vector2());
  const buffer = new Uint8Array(width * height * 4);
  renderer.setRenderTarget(renderTarget);
  renderer.render(scene, camera);
  renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
  
  return {
  	width, height, buffer
  };
  
}"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">readPixels</span><span class="pl-kos">(</span><span class="pl-s1">renderer</span><span class="pl-kos">,</span> <span class="pl-s1">scene</span><span class="pl-kos">,</span> <span class="pl-s1">camera</span><span class="pl-kos">,</span> <span class="pl-s1">renderTarget</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	
  <span class="pl-k">const</span> <span class="pl-kos">{</span>width<span class="pl-kos">,</span> height<span class="pl-kos">}</span> <span class="pl-c1">=</span> <span class="pl-s1">renderer</span><span class="pl-kos">.</span><span class="pl-en">getDrawingBufferSize</span><span class="pl-kos">(</span><span class="pl-k">new</span> <span class="pl-c1">THREE</span><span class="pl-kos">.</span><span class="pl-c1">Vector2</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">const</span> <span class="pl-s1">buffer</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Uint8Array</span><span class="pl-kos">(</span><span class="pl-s1">width</span> <span class="pl-c1">*</span> <span class="pl-s1">height</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-s1">renderer</span><span class="pl-kos">.</span><span class="pl-en">setRenderTarget</span><span class="pl-kos">(</span><span class="pl-s1">renderTarget</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-s1">renderer</span><span class="pl-kos">.</span><span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-s1">scene</span><span class="pl-kos">,</span> <span class="pl-s1">camera</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-s1">renderer</span><span class="pl-kos">.</span><span class="pl-en">readRenderTargetPixels</span><span class="pl-kos">(</span><span class="pl-s1">renderTarget</span><span class="pl-kos">,</span> <span class="pl-c1">0</span><span class="pl-kos">,</span> <span class="pl-c1">0</span><span class="pl-kos">,</span> <span class="pl-s1">width</span><span class="pl-kos">,</span> <span class="pl-s1">height</span><span class="pl-kos">,</span> <span class="pl-s1">buffer</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  
  <span class="pl-k">return</span> <span class="pl-kos">{</span>
  	width<span class="pl-kos">,</span> height<span class="pl-kos">,</span> buffer
  <span class="pl-kos">}</span><span class="pl-kos">;</span>
  
<span class="pl-kos">}</span></pre></div>
<p dir="auto">We then draw those pixels to a 2D canvas for visual feedback using context2D.putImageData. <strong>The webGL canvas is essentially duplicated</strong>. This is working on all browsers on my desktop machine.</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function drawBufferTo2DCanvas(width, height, buffer) {

  // clone buffer data to 2d canvas
  const cvs = document.createElement('canvas');
  const ctx = cvs.getContext('2d');
  cvs.width = width;
  cvs.height = height;
  cvs.style.transform = 'scaleY(-1)'; // flip y
  
  const imageData = ctx.createImageData(width, height);
  
  for (let i = 0; i &lt; imageData.data.length; i++) {
    imageData.data[i] = buffer[i];
  }
  
  ctx.putImageData(imageData, 0, 0);
  
}"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">drawBufferTo2DCanvas</span><span class="pl-kos">(</span><span class="pl-s1">width</span><span class="pl-kos">,</span> <span class="pl-s1">height</span><span class="pl-kos">,</span> <span class="pl-s1">buffer</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>

  <span class="pl-c">// clone buffer data to 2d canvas</span>
  <span class="pl-k">const</span> <span class="pl-s1">cvs</span> <span class="pl-c1">=</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">createElement</span><span class="pl-kos">(</span><span class="pl-s">'canvas'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-s1">ctx</span> <span class="pl-c1">=</span> <span class="pl-s1">cvs</span><span class="pl-kos">.</span><span class="pl-en">getContext</span><span class="pl-kos">(</span><span class="pl-s">'2d'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-s1">cvs</span><span class="pl-kos">.</span><span class="pl-c1">width</span> <span class="pl-c1">=</span> <span class="pl-s1">width</span><span class="pl-kos">;</span>
  <span class="pl-s1">cvs</span><span class="pl-kos">.</span><span class="pl-c1">height</span> <span class="pl-c1">=</span> <span class="pl-s1">height</span><span class="pl-kos">;</span>
  <span class="pl-s1">cvs</span><span class="pl-kos">.</span><span class="pl-c1">style</span><span class="pl-kos">.</span><span class="pl-c1">transform</span> <span class="pl-c1">=</span> <span class="pl-s">'scaleY(-1)'</span><span class="pl-kos">;</span> <span class="pl-c">// flip y</span>
  
  <span class="pl-k">const</span> <span class="pl-s1">imageData</span> <span class="pl-c1">=</span> <span class="pl-s1">ctx</span><span class="pl-kos">.</span><span class="pl-en">createImageData</span><span class="pl-kos">(</span><span class="pl-s1">width</span><span class="pl-kos">,</span> <span class="pl-s1">height</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  
  <span class="pl-k">for</span> <span class="pl-kos">(</span><span class="pl-k">let</span> <span class="pl-s1">i</span> <span class="pl-c1">=</span> <span class="pl-c1">0</span><span class="pl-kos">;</span> <span class="pl-s1">i</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">imageData</span><span class="pl-kos">.</span><span class="pl-c1">data</span><span class="pl-kos">.</span><span class="pl-c1">length</span><span class="pl-kos">;</span> <span class="pl-s1">i</span><span class="pl-c1">++</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">imageData</span><span class="pl-kos">.</span><span class="pl-c1">data</span><span class="pl-kos">[</span><span class="pl-s1">i</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-s1">buffer</span><span class="pl-kos">[</span><span class="pl-s1">i</span><span class="pl-kos">]</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  
  <span class="pl-s1">ctx</span><span class="pl-kos">.</span><span class="pl-en">putImageData</span><span class="pl-kos">(</span><span class="pl-s1">imageData</span><span class="pl-kos">,</span> <span class="pl-c1">0</span><span class="pl-kos">,</span> <span class="pl-c1">0</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  
<span class="pl-kos">}</span></pre></div>
<p dir="auto">When you try to do the same <strong>on iOS Safari</strong> all of the rgba <strong>values are straight zeros</strong>.<br>
The same is true when trying to get an image from the webGL context by calling:<br>
<code class="notranslate">renderer.domElement.toDataURL()</code> (a transparent image is returned)</p>
<p dir="auto">Things I've already tried:</p>
<ul dir="auto">
<li>using WebGL1Renderer since iOS does not support webGL 2.0</li>
<li>do not read floats since iOS does not support reading from floating point textures</li>
<li>initialize renderer with preserveDrawingBuffer set to true</li>
<li>initialize renderer with premultipliedAlpha set to false</li>
<li>readPixels immediately after rendering to avoid reading from a cleared buffer</li>
</ul>
<p dir="auto"><a href="https://threejs.org/examples/#webgl_interactive_cubes_gpu" rel="nofollow">The official Three.js example for reading pixels </a> also seems to not work on iOS Safari.</p>
<p dir="auto">Any hints?</p>
<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"> Dev</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> r120</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> ...</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"> All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Chrome</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Firefox</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Internet Explorer</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Safari</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"> All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Windows</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> macOS</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Linux</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Android</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> iOS</li>
</ul>
<h5 dir="auto">Hardware Requirements (graphics card, VR Device, ...)</h5>
<p dir="auto">Tested on iOS Safari on <strong>latest iPhone 11 Pro and latest iPad Pro.</strong></p>
<h5 dir="auto">Description of the problem</h5>
<p dir="auto">I think <a href="https://github.com/mrdoob/three.js/blob/6854ad946da842dd2991d9d545150567b7cdb39d/src/renderers/webxr/WebXRManager.js#L187-L242"><code class="notranslate">setProjectionFromUnion()</code></a> in <code class="notranslate">WebXRManager</code> is for  stereoscopic rendering. But it's called even for non-stereoscopic rendering, for example mobile AR, from <a href="https://github.com/mrdoob/three.js/blob/6854ad946da842dd2991d9d545150567b7cdb39d/src/renderers/webxr/WebXRManager.js#L285"><code class="notranslate">WebXRManager.getCamera()</code></a>.</p>
<p dir="auto">Especially, <a href="https://github.com/mrdoob/three.js/blob/6854ad946da842dd2991d9d545150567b7cdb39d/src/renderers/webxr/WebXRManager.js#L299-L327">in mobile AR (view# is 1) <code class="notranslate">cameraR</code> (<code class="notranslate">cameraVR.cameras[1]</code>) won't be updated.</a> So <code class="notranslate">setProjectionFromUnion()</code> which updates projection matrix from <code class="notranslate">cameraL/R</code> may not work correctly.</p>
<p dir="auto">An easy solution may be skipping <code class="notranslate">setProjectionFromUnion()</code> if the number of views is one. But currently no way to detect it in <code class="notranslate">.getCamera()</code>. We may need to save the number of views somewhere.</p>
<p dir="auto">/cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/jsantell/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/jsantell">@jsantell</a></p>
<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>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> r111</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> ...</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=""> All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Chrome</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Firefox</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Internet Explorer</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=""> All of them</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Windows</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> macOS</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Linux</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Android</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> iOS</li>
</ul>
<h5 dir="auto">Hardware Requirements (graphics card, VR Device, ...)</h5>