【问题标题】:How to store state flags in floating point numbers for GLSL / WebGL如何将状态标志存储为 GLSL / WebGL 的浮点数
【发布时间】:2019-08-06 04:47:18
【问题描述】:

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

【问题讨论】:

  • 我必须承认我从未见过有人使用浮点位掩码。我怀疑这是有道理的。特别是因为通常,按位运算或移位仅对整数进行。
  • 为什么要存储状态标志?通常不鼓励在着色器中进行分支。如果你想让一个着色器有条件地做一件事或另一个做 2 个着色器,一个做事情 1,一个做事情 2。
  • 这将是非常低效的。在大多数处理器中,fp 和整数存储在不同的寄存器中,您无法对 fp 寄存器执行逻辑操作。每当您想要执行按位运算时,寄存器之间都会有几个无用的副本。又有什么优势呢?
  • @gman 所以听起来使用switch statement 不是一个好主意。

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


【解决方案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.;

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

当然,这取决于flags 的来源。例如,如果您将标志作为UNSIGNED_BYTE 存储在纹理或属性中,那么您会将它们作为每个通道(红色、绿色、蓝色、alpha)的 8 位值拉出。 8bits 小于 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));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多