gpt4 book ai didi

javascript - WebGL:有没有一种有效的方法可以只上传图像/ Canvas 的一部分作为纹理?

转载 作者:太空狗 更新时间:2023-10-29 15:05:14 25 4
gpt4 key购买 nike

我正在开发一个基于 2D 图层的应用程序,我想使用 WebGL 进行合成。这些层可能会相对于彼此移动,并且每个帧只有每个层的一小部分(矩形)可能会发生变化。但是,该矩形部分的宽度和高度可能会发生不可预测的变化。我想每层使用一个 Canvas (2D)和一个纹理,并且每个 Canvas 上的每一帧仅重绘已修改的图层部分,然后只需将该小区域上传到 GPU 以将相应部分更新为纹理,在 GPU 为我进行合成之前。但是我还没有找到一种有效的方法来将图像的一部分上传到纹理的一部分。似乎 texSubImage2D() 可以 更新纹理的一部分,但只需要完整的图像/ Canvas ,而且似乎无法指定矩形区域要使用的图像。

我已经想到了几种方法来做到这一点,但每种方法似乎都有明显的开销:

  • 使用 getImageData() + texSubImage2D() 仅将更改的部分上传到 GPU(将 Canvas 像素数据转换为 ImageData 的开销)
  • 使用 texImage2D()
  • 重新上传每一帧的整个图层 Canvas
  • 或创建/调整一个小的 canvas2D 到正确的尺寸以完美适应每个层的修改,然后使用 texSubImage2D() 发送它来更新相关的纹理(内存预留开销)

那么,有没有办法为纹理指定图像/ Canvas 的一部分?像 texImagePart2D()texSubImagePart2D 这样的东西,它们都接受另外四个参数,sourceX, sourceY, sourceWidthsourceHeight 指定要使用的图像/ Canvas 的矩形区域?

最佳答案

很遗憾,没有办法上传 Canvas /图像的一部分。

WebGL 所基于的 OpenGL ES 2.0 没有提供这样做的方法。 OpenGL ES 3.0 确实提供了一种将源的较小矩形上传到纹理或纹理的一部分的方法,因此下一个版本的 WebGL 可能会提供该功能。

现在您可以有一个单独的 Canvas 来帮助上传。首先调整 Canvas 大小以匹配您要上传的部分

canvasForCopying.width = widthToCopy;
canvasForCopying.height= heightToCopy;

然后将要复制的 Canvas 部分复制到复制的 Canvas 上

canvasForCopying2DContext.drawImage(
srcCanvas, srcX, srcY, widthToCopy, heightToCopy,
0, 0, widthToCopy, heightToCopy);

然后使用它上传到您想要的纹理。

gl.texSubImage2D(gl.TEXTURE_2D, 0, destX, destY, gl.RGBA, gl.UNSIGNED_BYTE, 
canvasForCopying);

getImageData 可能会更慢,因为浏览器必须调用 readPixels获取 图像数据,这会使图形管道停滞。浏览器不必为 drawImage 执行此操作。

至于为什么 texImage2D 有时比 texSubImage2D 快,这取决于驱动程序/GPU,但显然有时 texImage2D 可以使用 DMA 实现而 texSubImage2D 不能。 texImage2D 也可以通过创建新纹理并懒惰地丢弃旧纹理来进行流水线处理,而 texSubImage2D 则不能。

就我个人而言,我不会担心它,但如果你想检查一下,使用 texImage2DtexSubImage2D 上传数万个纹理的时间(不要只是时间一个是图形流水线)。如果您的纹理很大并且您要更新的部分小于纹理的 25%,您可能会发现 texSubImage2D 更快。至少那是我上次检查时发现的。大多数当前的驱动程序至少在以下方面进行了优化:如果您调用 texSubImage2D 并且碰巧要替换全部内容,它们将在内部调用 texImage2D 代码。

更新

你可以做几件事

  1. 对于图像,您可以使用 fetchImageBitmap 将图像的一部分加载到 ImageBitamp 中,然后您可以上传那。获取图像的一部分的示例

    在下面的示例中,我们调用了fetch,然后获取了一个Blob,并使用该blob 制作了一个只有一部分的ImageBitmap图片。结果可以传递给 texImage2D,但为了简洁起见,该示例仅在 2d Canvas 中使用它。

fetch('https://i.imgur.com/TSiyiJv.jpg', {mode: 'cors'})
.then((response) => {
if (!response.ok) {
throw response;
}
return response.blob();
})
.then((blob) => {
const x = 451;
const y = 453;
const width = 147;
const height = 156;
return createImageBitmap(blob, x, y, width, height);
}).then((bitmap) => {
useit(bitmap);
}).catch(function(e) {
console.error(e);
});

// -- just to show we got a portion of the image

function useit(bitmap) {
const ctx = document.createElement("canvas").getContext("2d");
document.body.appendChild(ctx.canvas);
ctx.drawImage(bitmap, 0, 0);
}

  1. 在 WebGL2 中有 gl.pixelStorei 设置

    UNPACK_ROW_LENGTH//源的一行有多少像素 UNPACK_SKIP_ROWS//从源头开始跳过多少行 UNPACK_SKIP_PIXELS//从源左边跳过多少个像素

    所以使用这 3 个设置,您可以告诉 webgl2 源更宽,但您想要的部分更小。您将较小的宽度传递给 texImage2D,上面的 3 个设置有助于告诉 WebGL 如何去掉较小的部分以及从哪里开始。

关于javascript - WebGL:有没有一种有效的方法可以只上传图像/ Canvas 的一部分作为纹理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20930466/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com