如何将纹理作为一个 16 位(灰度)组件发送到 GPU?

How do I send a texture to the GPU as one component 16 bit (greyscale)?

我有一个 16 位灰度 PNG,其值在 [0,65535] 中,我在 WebGL 中用作纹理:

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

在着色器中,我只读取 R 分量并使用此值从颜色 table 中查找 RGBA。

这很好用。但是我真的不明白这里发生了什么。图像每个像素有 2 个字节。相反,我告诉 WebGL 它有 4 个组件,每个组件有 1 个字节。我认为这会导致读取两个像素而不是一个像素。

图像精度为 2 字节。由于每个组件都被指定为只有 1 个字节,我想知道;我这样做会失去精度吗?

理想情况下,我只想将一个 16 位通道 R 发送到 GPU。 我该怎么做?

无法将 16 位纹理上传到 WebGL。您可以改为上传 2 个 8 位通道(如 R 和 G)并将它们添加到您的着色器中。

vec4 color = texture2D(someSampler, someTexCoord);
float value = color.r + color.g * 256.0f

至于 gl.texImage2D 如何处理图像,gl.texImage2D 采用以下参数。

gl.texImage2D(target, level, internalFormat, 
              format, type, image/video/canvas);

WebGL 将首先获取图像、视频或 canvas 并将其转换为 formattype,同时考虑 UNPACK_PREMULTIPLY_ALPHA_WEBGLUNPACK_FLIP_Y_WEBGLUNPACK_COLORSPACE_CONVERSION_WEBGL 设置。然后它将调用 glTexImage2D

因为 WebGL 不支持 16 位整数格式,但无法上传 16 位整数通道。如果用户的机器支持这些格式并且您启用了扩展 OES_texture_float and or OES_texture_half_float,则可以上传到浮点或半浮点纹理,但是当从图像转换时,无法保证转换会有多大损失。另外,AFAIK Safari 是唯一可以加载 16 位和/或浮点图像的浏览器(它接受图像标签中的 16 位和 32 位 .TIF 文件,或者我上次检查大约 4 年前)。它是否在 WebGL 中无损上传它们我不相信在 WebGL 规范中指定也没有测试。无损上传只需要 8 位图像,并且前提是您正确设置了 UNPACK_ 设置。

当然,您始终可以使用 ArrayBuffer 自己上传数据以获得无损半浮点数或浮点数数据。但否则你需要将数据分成 8 位通道。