【问题标题】:Converting DDS (DXT3) texture to ImageData using WebGL使用 WebGL 将 DDS (DXT3) 纹理转换为 ImageData
【发布时间】:2018-02-25 16:45:17
【问题描述】:

我正在尝试使用 WebGL 将 DDS texture(主要是 DXT1 和 DXT3)转换为 ImageData。这是我的尝试...

let ext = <WEBGL_compressed_texture_s3tc>gl.getExtension('WEBGL_compressed_texture_s3tc');

let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

let fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGBA_S3TC_DXT3_EXT, width, height, 0, sourceImage);

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

let data = new Uint8Array(width * height * 4);

gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.deleteFramebuffer(fb);

let image = new ImageData(new Uint8ClampedArray(data), width, height);

其中 gl 是 WebGLRenderingContext 而 sourceImage (Uint8Array) 是 DXT3 格式的纹理。没有任何 mipmap 或其他东西。我很确定,因为我尝试使用this sn-p 渲染这个纹理并且它工作正常。

代码在 readPixels 函数中失败并出现以下错误(谷歌浏览器):

[.Offscreen-For-WebGL-000001F2F3C04690]GL 错误 :GL_INVALID_FRAMEBUFFER_OPERATION:glReadPixels:帧缓冲区 不完整

当然,我正在寻找答案,但没有任何成功。也许this 可能会有所帮助。如果需要,我可以提供一些示例纹理。

【问题讨论】:

    标签: typescript webgl framebuffer dds-format


    【解决方案1】:

    您无法渲染为压缩纹理格式,因此将它们附加到帧缓冲区会引发无效操作错误。您需要将未压缩的纹理附加到帧缓冲区,然后从 DXT 纹理中绘制屏幕空间四边形采样。像这样:

    let ext = <WEBGL_compressed_texture_s3tc>gl.getExtension('WEBGL_compressed_texture_s3tc');
    
    // create framebuffer attachment texture
    let colorTarget = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, colorTarget);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    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.texImage2D(
        gl.TEXTURE_2D,
        0,
        gl.RGBA,
        width,
        height,
        0,
        gl.RGBA,
        gl.UNSIGNED_BYTE,
        null
    );
    // setup framebuffer
    let fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTarget, 0);
    
    // create and upload compressed texture
    let compressedTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, compressedTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGBA_S3TC_DXT3_EXT, width, height, 0, sourceImage);
    
    gl.viewport(0,0,width,height);
    //draw screenspace quad here
    
    // read back uncompressed color data
    let data = new Uint8Array(width * height * 4);
    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
    
    gl.deleteFramebuffer(fb);
    
    let imageData = new ImageData(new Uint8ClampedArray(data), width, height);
    

    【讨论】:

    • 所以...如果我理解正确,我应该以某种方式将 DXT WebGL 纹理转换为未压缩的 RGBA WebGL 纹理,然后使用帧缓冲区和 readPixels 执行这些操作?我是 WebGL 的新手,所以也许我理解错了......?
    • 我已将您的代码 sn-p 的修改版本添加到我的答案中以举例说明流程
    • 它不起作用:/。我做了个小demo,什么时候可以试试。只需将this texture 拖放到this jsfiddle sn-p 的结果窗口即可。它会告诉你纹理。但是thissn-p 将纹理转换为 imageData 在某处坏了。 imageData 中的所有字节都为零...
    • 是的,因为你应该用绘制屏幕空间四边形的实际代码替换 //draw screenspace quad here...
    • 是的!它正在工作!谢谢! ;-) 那么,如果不将所有内容都渲染到 Canvas,就不可能将 DXT 纹理转换为 ImageData?
    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2019-07-31
    • 2018-03-05
    • 2016-02-01
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多