如何为 GLSL / WebGL 以浮点数形式存储状态标志

How to store state flags in floating point numbers for GLSL / WebGL

我最近了解到 storing boolean flags in integers using bitmasks。我想知道如何执行此操作来存储和检索布尔标志 to/from JavaScript,以及如何存储和检索标志 to/from GLSL。我认为这需要 浮点位掩码 ,而不是整数位掩码。这样我就可以在纹理中编码 JavaScript 中的一些状态标志,然后在 GLSL 中解压缩它们。同样,如果我将数据写入 GLSL 中的像素作为状态标志,我可以在 JavaScript.

中读出它们

在 WebGL2 的 GLSL ES 3.0 中,和大多数语言一样有位操作

uint flags = ??;

...

bool flag1 = (flags & 0x1) > 0;
bool flag2 = (flags & 0x2) > 0;
bool flag3 = (flags & 0x4) > 0;

在 WebGL1 中,您可以 mod 输出达到某个限制的值

float flags = ??;

bool flag1 = mod(flags, 2.0) > 0.;
bool flag2 = mod(floor(flags / 2.0), 2.0) > 0.;
bool flag3 = mod(floor(flags / 4.0), 2.0) > 0.;

只要 flags 是一个 highp 值并且是正整数值,这应该适用于前 23 位。

当然要看flags来自哪里。例如,如果您将标志作为 UNSIGNED_BYTE 存储在纹理或属性中,那么您会将它们作为每个通道(红色、绿色、蓝色、alpha)的 8 位值提取出来。 8 位小于 23 位限制,例如

vec4 flags = texture2D(textureWithFlags, someUV) * 255.0;

现在flags.rflags[0]是前8位,flags.g是接下来的8位等

attribute vec4 flags;

你用 UNSIGNED_BYTE 值和 normalize = false 设置属性然后就像上面每个标志通道一样是原始数据的 8 位

不鼓励在 GLSL 中使用分支。一般来说,如果你想做 2 个或更多不同的事情,而不是添加标志,为每个变体编写或生成着色器。这是大多数 3D 引擎所做的,包括 Unity、Unreal、Three.js 等...

另一方面,有时在适当的时候,您可以使用 stepmix,而不是分支。例如

vec4 color1 = ??
vec4 color2 = ??
float useColor2 = mod(flags, 2.0);  // will be 0.0 or 1.0
vec4 color = mix(color1, color2, useColor2);

上面的代码没有分支。

同理这个

vec4 color;
if (x < 100.0)
  color = color1;
} else {
  color = color2;
}

可以翻译成

vec4 color = mix(color1, color2, step(100.0, x));