在webgl中将大图像上传到GPU

时间:2014-08-03 15:48:45

标签: javascript webgl

如何在不冻结浏览器的情况下使用webgl将大图像上传到GPU(想想高分辨率的天空盒或纹理地图集)?

我一开始认为是否有办法让texImage2D异步地完成它的工作(将图像上传到GPU是IO-ish,对吧?),但我找不到任何办法。 然后我尝试使用texSubImage2D上传适合16毫秒时间窗口的小块(我的目标是60 fps)。但texSubImage2D只有在传入ArrayBufferView时才会获取偏移AND宽度/高度参数 - 当传入Image对象时,您只能指定偏移量并且它将(我猜测)上传整个形象。我想首先将图像绘制到画布上(将其作为缓冲区)与将整个内容上传到GPU一样慢。

这是我的意思的最小例子:http://jsfiddle.net/2v63f/3/。 我需要大约130毫秒才能将此图像上传到GPU。

与jsfiddle完全相同的代码:

var canvas = document.getElementById('can');
var gl = canvas.getContext('webgl');

var image = new Image();
image.crossOrigin = "anonymous";
//image.src = 'http://i.imgur.com/9Tq28Qj.jpg?1';
image.src = 'http://i.imgur.com/G0qL97y.jpg'
image.addEventListener('load', function () {
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);

    var now = performance.now();
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    console.log(performance.now() - now);
});

1 个答案:

答案 0 :(得分:4)

参考图像似乎是3840x1920

对于高分辨率天空盒,您通常可以放弃对Alpha通道的需求,然后决定其他像素格式结构是否可以在质量和数据大小之间提供合理的权衡。

指定的RGBA编码意味着在图像解码后需要29,491,200字节的数据传输。我试图用RGB测试,丢弃alpha但看到类似的111 ms传输时间。 假设您可以在使用之前预处理图像,并且只关心测量GPU数据传输时间的时间,您可以对数据执行某种形式的有损编码或压缩,以减少所需的带宽量传输。

其中一个更简单的编码方法是将数据大小减半,然后使用RGB 565将数据发送到芯片。这会将数据大小减少到14,745,600字节,但代价是颜色范围。

var buff = new Uint16Array(image.width*image.height);
//encode image to buffer
//on texture load-time, perform the following call
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, image.width, image.height, 0, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, buff);

假设您可以确认支持S3TC扩展(https://developer.mozilla.org/en-US/docs/Web/WebGL/Using_Extensions#WEBGL_compressed_texture_s3tc),您还可以以DXT1格式存储和下载纹理,并将内存传输要求降低到3,686,400字节。 看来任何形式的S3TC都会导致相同的RGB565颜色范围缩小。

var ext = (
  gl.getExtension("WEBGL_compressed_texture_s3tc") ||
  gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") ||
  gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc")
);

gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGB_S3TC_DXT1_EXT, image.width, image.height, 0, buff);

大多数块压缩可以近距离提供降低的图像质量,但可以在远处获得更丰富的图像。 如果您需要近距离高分辨率,最初可以加载较低分辨率或压缩纹理以用作较差的LOD远景,并且可以在接近相关纹理时加载较高分辨率的较小子集。

http://jsfiddle.net/zy8hkby3/2/的微不足道的测试中,纹理有效负载大小的减少会导致数据传输的时间要求呈指数下降,但这很可能取决于GPU。