WebGl 将浮点数打包到 v4 中
WebGl packing a float into v4
我有这个代码示例来自 threejs 示例 [http://threejs.org/examples/#webgl_animation_cloth],其中浮点值被转换为 vec4。我在其他几个论坛上看到过这种逻辑,但没有解释。
- 有人可以解释一下这个逻辑在做什么以及 256 的用途吗?我理解按位掩码和移位。
这个我也看过linkPacking float into vec4 - how does this code work?
表示vec4最终会存储在一个32位的RGBA8缓冲区中
由于我们将深度值传递到颜色缓冲区,opengl 如何知道如何处理它?
此外,由于 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 );
}
256是一个8位数据可以表示的不同值的个数。让我们暂时停止使用二进制,转而使用熟悉的十进制。如果我们有 2 个通道,每个通道只能存储 1 个数字 (0-9),我们如何打包 45 之类的东西?显然,我们将 5 打包成一个数字,将 40/10 或 4 打包成另一个数字。然后在我们的解包函数中,我们只是做相反的事情:4*10 + 5 = 45。256 类似于我们十进制示例中的 10。
Opengl 没有,但您自己的应用程序代码可以理解它。
我不确定我是否理解正确。但是您显示的代码将一个浮点数打包成 8*4 位 RGBA。
与@WaclawJasper 的回答一起,此代码将 'depth',一个浮点值(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
returns 一个 floats 和 gl_FragData
的 vec4 被定义为 vec4
它最终会在写入到当前正在写入的任何 WebGL 时被转换进入(canvas,渲染缓冲区,纹理)。
如果写入浮点纹理 pack_depth
则没有必要。由于 pack_depth
正在做的事情,我们可以推断它正在写入 8 位 RGBA 纹理。
为什么有这个需求?因为在 WebGL 中对浮点纹理的支持是可选的。因此,如果用户的机器不支持浮点纹理,而您需要类似浮点的数据(例如阴影贴图的深度缓冲区),那么将数据打包到 8 位纹理中是一种解决方案。
我有这个代码示例来自 threejs 示例 [http://threejs.org/examples/#webgl_animation_cloth],其中浮点值被转换为 vec4。我在其他几个论坛上看到过这种逻辑,但没有解释。
- 有人可以解释一下这个逻辑在做什么以及 256 的用途吗?我理解按位掩码和移位。
这个我也看过linkPacking float into vec4 - how does this code work?
表示vec4最终会存储在一个32位的RGBA8缓冲区中
由于我们将深度值传递到颜色缓冲区,opengl 如何知道如何处理它?此外,由于 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 ); }
256是一个8位数据可以表示的不同值的个数。让我们暂时停止使用二进制,转而使用熟悉的十进制。如果我们有 2 个通道,每个通道只能存储 1 个数字 (0-9),我们如何打包 45 之类的东西?显然,我们将 5 打包成一个数字,将 40/10 或 4 打包成另一个数字。然后在我们的解包函数中,我们只是做相反的事情:4*10 + 5 = 45。256 类似于我们十进制示例中的 10。
Opengl 没有,但您自己的应用程序代码可以理解它。
我不确定我是否理解正确。但是您显示的代码将一个浮点数打包成 8*4 位 RGBA。
与@WaclawJasper 的回答一起,此代码将 'depth',一个浮点值(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
returns 一个 floats 和 gl_FragData
的 vec4 被定义为 vec4
它最终会在写入到当前正在写入的任何 WebGL 时被转换进入(canvas,渲染缓冲区,纹理)。
如果写入浮点纹理 pack_depth
则没有必要。由于 pack_depth
正在做的事情,我们可以推断它正在写入 8 位 RGBA 纹理。
为什么有这个需求?因为在 WebGL 中对浮点纹理的支持是可选的。因此,如果用户的机器不支持浮点纹理,而您需要类似浮点的数据(例如阴影贴图的深度缓冲区),那么将数据打包到 8 位纹理中是一种解决方案。