WebGL,将浮点数打包到 vec4 中

问题描述 投票:0回答:2

我有来自 Threejs 示例的代码示例,其中浮点值转换为

vec4
。我在其他几个论坛上看到过这种逻辑,但没有解释。

  1. 有人可以解释一下这个逻辑在做什么以及 256 的用途吗?我理解按位掩码和移位。

我也看过这个链接将 float 打包到 vec4 - 这段代码是如何工作的?

  1. 它表示

    vec4
    最终将存储在32位RGBA8缓冲区中。
    由于我们将深度值传递到颜色缓冲区中,OpenGL 如何知道如何处理它?

  2. 此外,由于

    vec4
    有 4 个分量,每个分量 4 个字节,使其成为 16 个字节,从而使其成为 16 * 8 位。这如何适合 32 位 RGBA8?

vec4 pack_depth( const in float depth ) {
    const vec4 bit_shift = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0);
    const vec4 bit_mask  = vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
    vec4 res = fract(depth * bit_shift);
    res -= res.xxyz * bit_mask;
    return res;
}

void main() {
    vec4 pixel = texture2D(texture, vUV);
    if (pixel.a < 0.5) discard;
    gl_FragData[0] = pack_depth(gl_FragCoord.z);
}
opengl-es three.js webgl
2个回答
2
投票

连同 @WaclawJasper 的答案,此代码将“深度”(浮点值(32 位))打包为 4 个 8 位值。

gl_FragData[ 0 ]
表示纹理中的单个像素,在本例中是每个通道 8 位的纹理(总共 32 位)。 如果我写

gl_FragData[0] = vec4(0.25, 0.5, 0.75, 1.0);

正在写入的纹理(假设它是 8 位纹理)实际上会获取值

r = Math.floor(0.25 * 255) = 63;
g = Math.floor(0.5  * 255) = 127;
b = Math.floor(0.75 * 255) = 191;
a = Math.floor(1.0  * 255) = 255;

规范中的实际公式是有效的

unsignedIntValue = floor(clamp(floatValue, 0., 1.) * (pow(2., numberOfBits) - 1.));

因此,即使

pack_depth
返回一个浮点型 vec4,并且
gl_FragData
被定义为
vec4
,当写入到当前正在写入的任何 WebGL(画布、渲染缓冲区、纹理)时,它最终也会被转换。

如果写入浮点纹理

pack_depth
将是不必要的。由于
pack_depth
正在执行的操作,我们可以推断它正在写入 8 位 RGBA 纹理。

为什么有这个需求?因为在 WebGL 中,对浮点纹理的支持是可选的。因此,如果用户的机器不支持浮点纹理,并且您需要类似浮点的数据(如阴影贴图的深度缓冲区),那么将数据打包到 8 位纹理中是一种解决方案。


1
投票
  1. 256是8位数据可以表示的不同值的数量。让我们暂时停止使用二进制,转而使用熟悉的十进制。如果我们有 2 个通道,每个通道只能存储 1 位数字 (0-9),那么我们如何打包 45 这样的数字?显然,我们将 5 打包为一位数字,将 40/10 或 4 打包为另一位数字。然后在我们的 unpack 函数中,我们只需执行相反的操作:4*10 + 5 = 45。256 类似于十进制示例中的 10。

  2. OpenGL 没有,但您自己的应用程序代码可以理解它。

  3. 我不确定我是否正确理解这部分,但您显示的代码是将一个浮点数打包成8*4位RGBA。

© www.soinside.com 2019 - 2024. All rights reserved.