在WebGL中上传大型图像到GPU

8
如何使用WebGL上传大型图像到GPU而不会冻结浏览器(比如高分辨率的天空盒或贴图集)?
起初,我尝试寻找一种方法,让texImage2D异步执行其任务(将图像上传到GPU属于IO操作,对吧?),但是我没有找到任何方法。
然后,我尝试使用texSubImage2D上传适合在16毫秒时间窗口中完成的小块(我目标是60 fps)。但是,只有当你传递ArrayBufferView时,texSubImage2D才会接受偏移量和宽度/高度参数——当传递图像对象时,你只能指定偏移量,并且它会(我猜测)上传整张图片。我想在将其绘制到画布上之前先在画布上绘制这个图像(以此获取它作为缓冲区),但这也和将整张图片上传到GPU一样慢。
以下是我所说的最小示例:http://jsfiddle.net/2v63f/3/。上传此图像到GPU需要约130毫秒。
完全相同的代码如下:
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个回答

4
被引用的图片似乎是3840x1920大小的。对于高分辨率天空盒,通常可以放弃alpha通道的需求,并决定是否使用其他像素格式结构来在质量和数据大小之间提供合理的权衡。指定的RGBA编码意味着这将需要一个29,491,200字节的数据传输,而我尝试使用RGB进行测试,舍弃alpha但看到了相似的111毫秒传输时间。假设您能在使用前预处理图像,并且只关心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);

大多数块压缩技术可以在远处提供更丰富的图像,但近距离观看时会减少图像质量。如果需要高分辨率的近距离查看,可以最初加载低分辨率或压缩纹理作为远程视图,并在接近所需纹理时加载较高分辨率的一个较小子集。
在我的小型测试中,http://jsfiddle.net/zy8hkby3/2/ ,纹理负载大小的减少可能会导致数据传输时间指数级地减少,但这很可能取决于 GPU。

很棒的信息,但你似乎也同意异步地将大型图像传输到GPU是不可能的,对吧? - Ray Hulha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接