我有来自 Threejs 示例的代码示例 [http://thirdjs.org/examples/#webgl_animation_cloth],其中浮点值转换为 vec4。我在其他几个论坛上看到过这种逻辑,但没有解释。
我也看过这个链接将 float 打包到 vec4 - 这段代码是如何工作的?
它表示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 );
}
连同 @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 位纹理中是一种解决方案。
256是8位数据可以表示的不同值的数量。让我们暂时停止使用二进制,转而使用熟悉的十进制。如果我们有 2 个通道,每个通道只能存储 1 位数字 (0-9),那么我们如何打包 45 这样的数字?显然,我们将 5 打包为一位数字,将 40/10 或 4 打包为另一位数字。然后在我们的 unpack 函数中,我们只需执行相反的操作:4*10 + 5 = 45。256 类似于十进制示例中的 10。
OpenGL 没有,但您自己的应用程序代码可以理解它。
我不确定我是否正确理解这部分,但您显示的代码是将一个浮点数打包成8*4位RGBA。