【发布时间】:2014-11-16 07:57:24
【问题描述】:
我正在尝试在 WebGL 中加载图像,然后将它们上传到 GPU。我想使用压缩纹理格式,即使原始图像是未压缩/无损的。
要上传,这就是我正在做的:
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureSource);
在上面的代码中,textureSource 是一个加载的(比如“texture.png”)。
一切正常,但我想加载WEBGL_compressed_texture_s3tc 格式(COMPRESSED_RGB_S3TC_DXT1_EXT)以压缩方式存储图像。
我确保扩展程序可用并已启用...
var ext = gl.getExtension("WEBGL_compressed_texture_s3tc");
var fmt = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
console.log(fmt); // 33779
但是我不能将它用作一种格式。使用texImage2D() 不起作用:
gl.texImage2D(gl.TEXTURE_2D, 0, fmt, fmt, gl.UNSIGNED_BYTE, textureSource);
// WebGL: INVALID_ENUM: texImage2D: invalid texture format
// [.WebGLRenderingContext]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'
预期的方法是compressedTexImage2D(),但这也不是很有帮助:
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, fmt, 256, 256, 0, texture.source);
// Uncaught TypeError: Failed to execute 'compressedTexImage2D' on 'WebGLRenderingContext': parameter 7 is not of type 'ArrayBufferView'.
这显然是因为 compressedTexImage2D() 需要一个带有实际 DDS/DXT 数据的 Uint8Array,而不是像我传递的那样的 JavaScript 图像。
显而易见的解决方案是以原始 DDS 格式上传文件 - 已在其他地方压缩的文件。但这就是我要避免的:在我当前的工作流程中,将图像保留为原始格式而不是预压缩它们(或重复)是有意义的。
我的问题是这样的:我仍然可以使用原始 PNG 图像,加载它们,并让它们以压缩格式上传到 GPU 吗?换句话说,我可以即时将纹理压缩为 DXT1/5 格式吗?
我正在做的事情有点受视频内存的限制,所以任何节省都会很棒。我设法通过使用UNSIGNED_SHORT_4_4_4_4 和其他数据类型来最小化纹理使用的空间,这是一个好的开始,但我也想尝试使用本机压缩。
我没有找到关于该主题的太多文档,也没有在其他流行库(Three.js、Pixi 等)上找到相关代码,这让我相信我的请求非常愚蠢,但我想明白为什么。 This page 暗示了许可问题,这可能是 WebGL 没有正确压缩文件的方法,也不允许浏览器支持图像对象的原因。
【问题讨论】:
-
该扩展只允许您上传预压缩的图像数据。将原始 RGB[A] 数据编码为 DXT 不是 OpenGL ES / WebGL 的一部分。如果您想使用 PNG 进行存储,您必须自己对图像进行块编码,然后再将其传递给 WebGL。
标签: opengl-es webgl webgl-extensions