【问题标题】:glFramebufferTexture2D on webgl2 with mipmaps levels带有 mipmap 级别的 webgl2 上的 glFramebufferTexture2D
【发布时间】:2019-07-24 07:04:15
【问题描述】:

对于从 ES3.0 派生的 webGL2,我认为我们可以使用 mipmap levels 作为最后一个参数:

void glFramebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level);

现在来自Khronos ES3.0 官方文档指出 mipmap 级别应该可以工作:

级别: 指定要附加的纹理的 mipmap 级别。

Khronos ES2.0 改为它说 必须为 0

级别: 指定要附加的纹理图像的mipmap级别,必须为0。

现在,我无法从 WebGL2.0 上下文中找到任何关于 glFramebufferTexture2D 的文档,但 mozilla 文档指出 mipmap 层必须为 0,就像在 ES2.0 中一样,这里: Mozilla WebGL doc

级别: 一个 GLint,指定要附加的纹理图像的 mipmap 级别。必须为 0。

我认为该页面指的是 WebGL1 上下文,但其中提到了 WebGL2 功能,我在 WebGL2 文档上找不到 glFramebufferTexture2D。

总结一下,有没有办法在 WebGL2.0 上的帧缓冲区目标上使用 mipmap 级别

(我研究了分层图像,但 AFAIK 分层渲染不适用于 WebGL2.0)

【问题讨论】:

  • WebGL2 规范要求查看 OpenGL ES 3.0 规范以了解所有详细信息,然后列出该规范的一些更改,因此 WebGL2 的文档是 OpenGL ES 3.0 规范。

标签: webgl webgl2


【解决方案1】:

有没有办法在 WebGL2.0 上的帧缓冲区目标上使用 mipmap 级别

是的

我会在那里关闭答案,但我想我想知道您是否真的尝试过某些东西并且它不起作用?您必须创建一个 WebGL2 上下文才能使用 mipmap 级别作为帧缓冲区附件,否则,它可以工作。在 WebGL1 上它不起作用。

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  
  const vs = `#version 300 es
  void main() {
    // just draw an 8x8 pixel point in the center of the target
    // this shader needs/uses no attributes
    gl_Position = vec4(0, 0, 0, 1);
    gl_PointSize = 8.0;
  }
  `;
  const fsColor = `#version 300 es
  precision mediump float;
  uniform vec4 color;
  out vec4 outColor;
  void main() {
    outColor = color;
  }
  `;
  const fsTexture = `#version 300 es
  precision mediump float;
  uniform sampler2D tex;
  out vec4 outColor;
  void main() {
    // this shader needs no texcoords since we just
    // use gl_PoitnCoord provided by rendering a point with gl.POINTS
    // bias lets select the mip level so no need for 
    // some fancier shader just to show that it's working.        
    float bias = gl_PointCoord.x * gl_PointCoord.y * 4.0;
    outColor = texture(tex, gl_PointCoord.xy, bias);
  }
  `;
  
  // compile shaders, link into programs, look up attrib/uniform locations
  const colorProgramInfo = twgl.createProgramInfo(gl, [vs, fsColor]);
  const textureProgramInfo = twgl.createProgramInfo(gl, [vs, fsTexture]);
  
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  const levels = 4;
  const width = 8;
  const height = 8;
  gl.texStorage2D(gl.TEXTURE_2D, levels, gl.RGBA8, width, height);
  
  // make a framebuffer for each mip level
  const fbs = [];
  for (let level = 0; level < levels; ++level) {
    const fb = gl.createFramebuffer();
    fbs.push(fb);
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferTexture2D(
        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
        gl.TEXTURE_2D, tex, level);
  }
  
  // render a different color to each level
  const colors = [
    [1, 0, 0, 1],  // red
    [0, 1, 0, 1],  // green
    [0, 0, 1, 1],  // blue
    [1, 1, 0, 1],  // yellow
  ];
  gl.useProgram(colorProgramInfo.program);
  for (let level = 0; level < levels; ++level) {
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbs[level]);
    const size = width >> level;
    gl.viewport(0, 0, size, size);
    twgl.setUniforms(colorProgramInfo, { color: colors[level] });
    const offset = 0;
    const count = 1;
    gl.drawArrays(gl.POINTS, offset, count);  // draw 1 point
  }
  
  // draw the texture's mips to the canvas
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.useProgram(textureProgramInfo.program);
  // no need to bind the texture it's already bound
  // no need to set the uniform it defaults to 0
  gl.drawArrays(gl.POINT, 0, 1);  // draw 1 point
}
main();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas width="8" height="8" style="width: 128px; height: 128px;"></canvas>

您还可以渲染到 TEXTURE_2D_ARRAY 纹理层。

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need webgl2');
  }
  
  const vs = `#version 300 es
  void main() {
    // just draw an 8x8 pixel point in the center of the target
    // this shader needs/uses no attributes
    gl_Position = vec4(0, 0, 0, 1);
    gl_PointSize = 8.0;
  }
  `;
  const fsColor = `#version 300 es
  precision mediump float;
  uniform vec4 color;
  out vec4 outColor;
  void main() {
    outColor = color;
  }
  `;
  const fsTexture = `#version 300 es
  precision mediump float;
  uniform mediump sampler2DArray tex;
  out vec4 outColor;
  void main() {
    // this shader needs no texcoords since we just
    // use gl_PoitnCoord provided by rendering a point with gl.POINTS
    float layer = gl_PointCoord.x * gl_PointCoord.y * 4.0;
    outColor = texture(tex, vec3(gl_PointCoord.xy, layer));
  }
  `;
  
  // compile shaders, link into programs, look up attrib/uniform locations
  const colorProgramInfo = twgl.createProgramInfo(gl, [vs, fsColor]);
  const textureProgramInfo = twgl.createProgramInfo(gl, [vs, fsTexture]);
  
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex);
  const levels = 1;
  const width = 8;
  const height = 8;
  const layers = 4;
  gl.texStorage3D(gl.TEXTURE_2D_ARRAY, levels, gl.RGBA8, width, height, layers);
  // only use level 0 (of course we could render to levels in layers as well)
  gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  
  // make a framebuffer for each layer
  const fbs = [];
  for (let layer = 0; layer < layers; ++layer) {
    const fb = gl.createFramebuffer();
    fbs.push(fb);
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    const level = 0;  
    gl.framebufferTextureLayer(
        gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
        tex, level, layer);
  }
  
  // render a different color to each layer
  const colors = [
    [1, 0, 0, 1],  // red
    [0, 1, 0, 1],  // green
    [0, 0, 1, 1],  // blue
    [1, 1, 0, 1],  // yellow
  ];
  gl.useProgram(colorProgramInfo.program);
  for (let layer = 0; layer < layers; ++layer) {
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbs[layer]);
    gl.viewport(0, 0, width, height);
    twgl.setUniforms(colorProgramInfo, { color: colors[layer] });
    const offset = 0;
    const count = 1;
    gl.drawArrays(gl.POINTS, offset, count);  // draw 1 point
  }
  
  // draw the texture's mips to the canvas
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.useProgram(textureProgramInfo.program);
  // no need to bind the texture it's already bound
  // no need to set the uniform it defaults to 0
  gl.drawArrays(gl.POINT, 0, 1);  // draw 1 point
}
main();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas width="8" height="8" style="width: 128px; height: 128px; image-rendering: pixelated;"></canvas>

【讨论】:

  • 谢谢,我正在尝试从我的代码库中推断出一个最小示例来解决另一个问题,然后我有一个 GL_INVALID_FRAMEBUFFER_OPERATION 用于在 webgl2 中的立方体贴图上使用 glFramebufferTexture2D 设置 mipmap 级别,但我也是使用 emscripten 通过他们的 JS 从桌面/本机 c++ openGL 实现桥接到 webGL2,所以我真的不确定实际问题是什么/在哪里。如果我能得到那个最小的例子,我会提出另一个问题,但这个问题显然已经为我正确回答了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 2012-09-16
相关资源
最近更新 更多