1

我正在尝试在 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()期望Uint8Array使用实际的 DDS/DXT 数据,而不是像我传递的那样的 JavaScript 图像。

显而易见的解决方案是以原始 DDS 格式上传文件 - 已在其他地方压缩的文件。但这就是我要避免的:在我当前的工作流程中,将图像保留为原始格式而不是预压缩它们(或重复)是有意义的。

我的问题是这样的:我是否仍然可以使用原始 PNG 图像,加载它们,并让它们以压缩格式上传到 GPU?换句话说,我可以即时将纹理压缩为它们的 DXT1/5 格式吗?

我正在做的事情有点受视频内存的限制,所以任何节省都会很棒。我设法通过使用UNSIGNED_SHORT_4_4_4_4和其他数据类型来最小化纹理使用的空间,这是一个好的开始,但我也想尝试使用本机压缩。

我没有找到关于该主题的太多文档,也没有在其他流行的库(Three.js、Pixi 等)上找到相关代码,这让我相信我的请求非常愚蠢,但我想了解原因。这个页面暗示了许可问题,这可能是 WebGL 没有正确压缩文件的方法,也不允许浏览器支持图像对象的原因。

4

2 回答 2

2

我还能使用原始 PNG 图像,加载它们,然后以压缩格式将它们上传到 GPU 吗?换句话说,我可以即时将纹理压缩为它们的 DXT1/5 格式吗?

据我所知:

我只在桌面和嵌入式 GL 上工作,但即使没有专门的代码或库,也没有机会即时压缩纹理。

(而且,那些 DXT 格式也不是很好,如果你的纹理太详细或者在小桶中有很多不同的颜色。很可能你最好只使用较小的纹理,因为 DXT1 压缩到 1/ 8th 和 DXT5 到原始大小的 1/4(这就像将纹理的分辨率减半)。

于 2014-11-13T23:30:57.163 回答
0

从理论上讲,我认为您可以使用 Javascript 将 PNG 压缩为 DXT。我想那会很生气:)

更好地预先使用本机代码进行编码。支持 PNG 内容的一个选项是使用资产代理在服务器端进行动态转换(我们的合作伙伴公司托管http://www.meshmoon.com/就是这样做的)。

于 2014-11-15T23:57:24.850 回答