如何在GLSL / WebGL的浮点数中存储状态标志

时间:2019-03-15 06:39:43

标签: javascript floating-point bit-manipulation glsl webgl

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

1 个答案:

答案 0 :(得分:1)

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

uint flags = ??;

...

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

在WebGL1中,您可以将值修改为最大限制

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在纹理或属性中,则将其作为每个通道的8位值(红色,绿色,蓝色,alpha)拉出。 8位小于23位限制,例如

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

现在flags.rflags[0]是前8位,flags.g是后8位,等等。

attribute vec4 flags;

在其中用UNSIGNED_BYTE值设置属性,然后将normalize = false设置为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));