【问题标题】:Uploading large images to the GPU in webgl在 webgl 中将大图像上传到 GPU
【发布时间】:2014-09-26 04:46:43
【问题描述】:

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

起初我想寻找是否有办法让texImage2D 异步执行其操作(将图像上传到 GPU 是 IO-ish,对吗?),但我找不到任何方法。 然后我尝试使用texSubImage2D 上传适合 16 毫秒时间窗口的小块(我的目标是 60 fps)。但是texSubImage2D 仅在您传入ArrayBufferView 时才采用偏移量和宽度/高度参数 - 传入图像对象时,您只能指定偏移量,它会(我猜)上传整个图像。我想首先将图像绘制到画布(将其作为缓冲区)与将整个图像上传到 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);
});

【问题讨论】:

    标签: javascript webgl


    【解决方案1】:

    引用的图像似乎是 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);
    

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

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

    【讨论】:

    • 很好的信息,但您似乎也同意将大图像异步传输到 GPU 是不可能的,对吧?
    猜你喜欢
    • 2017-11-18
    • 1970-01-01
    • 2013-11-25
    • 2019-10-10
    • 2013-07-24
    • 2012-10-11
    • 2020-04-16
    • 2014-12-07
    • 1970-01-01
    相关资源
    最近更新 更多