【问题标题】:Unable to generate mipmap for half_float texture无法为 half_float 纹理生成 mipmap
【发布时间】:2019-07-01 02:37:08
【问题描述】:

我正在使用 webgl2 并将我的纹理数据加载为半浮点数。使用LINEARMIN_FILTER 时可以正确渲染图像。但是,我想使用 mipmap 过滤器。当我使用 mipmap 过滤器并尝试生成 mipmap 时,它会失败。 webgl 文档https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D 表示 R16F 纹理是可过滤的,并不表示它仅限于 LINEAR 过滤器。有没有我遗漏的步骤,或者这是 webgl2 的无证限制?

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
const tex = gl.createTexture();
const unit = 1;  // Pick some texture unit
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, tex);

const numPixels = this.width * this.height;

const level = 0;

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); //Works
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); //Does NOT work
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

// Upload the image into the texture
const pixel = new Uint16Array(this.binaryImage);

gl.texImage2D(gl.TEXTURE_2D, level, gl.R16F, this.width, this.height, 0, gl.RED, gl.HALF_FLOAT, pixel);

gl.generateMipmap(gl.TEXTURE_2D); //FAILS

const sampler2DLoc = gl.getUniformLocation(program, "u_image");
gl.uniform1i(sampler2DLoc, unit);

【问题讨论】:

    标签: webgl webgl2


    【解决方案1】:

    WebGL2 的规范说 WebGL2 是 OpenGL ES 3.0 与 WebGL2 规范中列出的差异。否则,WebGL2 规范要求阅读 OpenGL ES 3.0 规范以获取详细信息。

    来自 OpenGL ES 3.0 规范第 3.8.10.5 节

    3.8.10.5 手动生成 Mipmap

    可以使用命令手动生成 Mipmaps

    void GenerateMipmap(enumtarget);
    

    ...

    如果未使用表 3.3 中未调整大小的内部格式或根据表 3.13 既可颜色渲染又可纹理过滤的已调整大小的内部格式指定级别基础数组,则会生成 INVALID_OPERATION 错误

    R16F 可以进行纹理过滤,但不能进行颜色渲染

    您需要检查并启用 the EXT_color_buffer_float extension 才能为半浮点格式生成 mip。

    'use strict';
    
    function main() {
      const gl = document.querySelector('canvas').getContext('webgl2');
      if (!gl) {
        return alert('need webgl2');
      }
      const ext = gl.getExtension('EXT_color_buffer_float');
      if (!ext){
        return alert('need EXT_color_buffer_float');
      }
    
      const vs = `#version 300 es
      void main() {
        gl_Position = vec4(0, 0, 0, 1);
        gl_PointSize = 120.0;
      } 
      `;
    
      const fs = `#version 300 es
      precision mediump float;
    
      uniform sampler2D tex;
    
      out vec4 outColor;
    
      void main() {
        outColor = vec4(texture(tex, gl_PointCoord.xy).r, 0, 0, 1);
      }
      `;
    
      // setup GLSL program
      const program = twgl.createProgram(gl, [vs, fs]);
    
      // a 2x2 pixel data
      const h0 = 0x0000;
      const h1 = 0x3c00;
      const pixels = new Uint16Array([
        h0, h1,
        h1, h0,
      ]);
      const tex = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(
          gl.TEXTURE_2D,
          0,                 // level
          gl.R16F,           // internal format
          2,                 // width
          2,                 // height
          0,                 // border
          gl.RED,            // format
          gl.HALF_FLOAT,     // type
          pixels,            // data
      );
      gl.generateMipmap(gl.TEXTURE_2D);
    
      gl.useProgram(program);
    
      const offset = 0;
      const count = 1;
      gl.drawArrays(gl.POINTS, offset, count);
      console.log('gl.getError should be 0 was:', gl.getError());
    }
    
    main();
    <script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
    <canvas></canvas>

    【讨论】:

    • 如果我理解正确的话,“纹理可过滤”允许我使用 LINEAR min 过滤器而不是 NEAREST 并且“颜色可渲染”允许我生成 mipmap 纹理。通过启用扩展“EXT_color_buffer_float”,R16F 变得“可渲染”
    • 是的,没错,但EXT_color_buffer_float 并非在任何地方都可用,尤其是在移动设备上。同样重要的是要注意“texture-filterable”允许 LINEAR_MIPMAP_LINEAR 和其他需要 mip 的过滤模式,您只需自己生成和提供 mips。
    猜你喜欢
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多