Skip to content Skip to sidebar Skip to footer

Render To 3d Texture Webgl2

I read here that it should be possible to render to a 3D texture in WebGL2 by using multiple render targets and attaching each layer of the 3d texture as a layer to the render targ

Solution 1:

I was trying exactly the same thing as you and finally succeeded, just to note some caveats for future readers.

2 things that don't work with TEXTURE_3D (as of Chrome 84):

  1. Binding a depth buffer to the framebuffer will screw things up, I even got browser glitches for doing this, no matter it's a single texture or texture array. So if you'd like to use TEXTURE_3D, do NOT bind any depth buffer.
  2. No float texture, which you didn't use, but it failed me so hard that I want to point it out.

If the above requirement is necessary, you might as well stick to gl.TEXTURE_2D_ARRAY

Solution 2:

AFAICT in your sample you just needed to call gl.drawArrays

Your sample though is trying to render to 8 layers. WebGL2 only requires 4 layers to be supported. You can check if 8 are supported by calling gl.getParameter(gl.MAX_DRAW_BUFFERS) so that could be another reason you code was failing.

Not required according to the spec but possibly required anyway is making the texture texture complete, which means make it renderable (even though we are not rendering with it we are rendering to it). In this case because I didn't make mips I set the TEXTURE_MIN_FILTER to LINEAR since by default it's NEAREST_MIPMAP_LINEAR which requires mips otherwise the texture is not renderable. not renderable = not usable period in at least some drivers in the past.

functionmain() {
  const gl = document.querySelector('canvas').getContext("webgl2");
  if (!gl) {
    returnalert('need webgl2');
  }
  
  const vs = `#version 300 es
  void main() {
    gl_Position = vec4(0, 0, 0, 1);
    gl_PointSize = 10.0;
  }
  `;
  const fs = `#version 300 es
  precision mediump float;
  out vec4 outColor[4];
  void main() {
    outColor[0] = vec4(.1, .2, .3, .4);
    outColor[1] = vec4(.5, .6, .7, .8);
    outColor[2] = vec4(.9, 1., .11, .22);
    outColor[3] = vec4(.33, .44, .55, .66);
  }
  `;
  
  const program = twgl.createProgram(gl, [vs, fs]);
  
  const width = 4;
  const height = 4;
  const depth = 4;
  const tex = gl.createTexture(gl.TEXTURE_3D);
  gl.bindTexture(gl.TEXTURE_3D, tex);
  gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA8, width, height, depth, 0,
                gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  
  const numAttachments = 4;
  const fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  for (let i = 0; i < numAttachments; ++i) {
    gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, tex, 0, i);
  }
  
  gl.drawBuffers([
    gl.COLOR_ATTACHMENT0, 
    gl.COLOR_ATTACHMENT1, 
    gl.COLOR_ATTACHMENT2, 
    gl.COLOR_ATTACHMENT3,
  ]);
  
  gl.viewport(0, 0, width, height);
  gl.useProgram(program);
  gl.drawArrays(gl.POINTS, 0, 1);
  
  for (let i = 0; i < numAttachments; ++i) {
    gl.readBuffer(gl.COLOR_ATTACHMENT0 + i);
    const pixel = newUint8Array(4);
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
    console.log('layer:', i, '=', Array.from(pixel).map(v => (v / 255).toFixed(2)).join(', '));
  }
}
main();
    
<scriptsrc="https://twgljs.org/dist/4.x/twgl.min.js"></script><canvas></canvas>

Post a Comment for "Render To 3d Texture Webgl2"