我试图在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等)的相关代码,这让我相信我的请求是超级愚蠢的,但我&#39 ;我想明白为什么。 This page提示许可问题,这可能就是为什么WebGL没有正确压缩文件的方法,也不允许浏览器支持图像对象。
答案 0 :(得分:2)
我仍然可以使用原始PNG图像,加载它们,并将它们以压缩格式上传到GPU吗?换句话说,我可以动态地将纹理压缩为DXT1 / 5格式吗?
据我所知:否。
我只在桌面和嵌入式GL上工作,但即使没有专用代码或库也无法动态压缩纹理。
(而且,那些DXT格式也不是很好,如果你的纹理过于细致或者在小桶中有很多不同的颜色。很可能你最好只使用较小的纹理,因为DXT1压缩到原始大小的1/8和DXT5到1/4(这就像将纹理的分辨率减半)。)
答案 1 :(得分:0)
理论上我认为你可以用Javascript将PNG压缩到DXT。我想这只是疯了:)
预先使用本机代码进行更好的编码。支持PNG内容的一个选项是拥有一个资产代理,用于在服务器端即时进行转换(我们的托管http://www.meshmoon.com/的合作伙伴公司正是如此)。