如何在 HLSL/GLSL 中获取随机 uint 或浮点数的最后一位?

How can I get a random uint or the last digit of float in HLSL/GLSL?

我只需要一个随机的uint,最好在0-6之间,但是openGL中没有枚举类型。我了解到我可以从下面的代码中获得一个范围为 0-1 的随机浮点数:

frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453123)

我尝试执行 1/above 并获取 floor(),但它不起作用。那我怎样才能得到一个随机整数呢?或者有没有办法得到浮点数的最后一位(所以大概仍然是随机的)?

首先,让我们定义“随机”的含义。在此答案的上下文中,“随机”变量是其值 不可预测 的变量。也就是说,没有 function determines/computes 在评估随机变量时(使用任何可能的输入)的结果。或者至少,还没有找到这样的功能。

显然,当我们在这里谈论计算时,并不存在上述随机变量,因为我们在计算中所做的任何事情(以及在着色器中的扩展)必然绑定到可计算.

的函数集

你在问题中提出的功能:

f(uv) = frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453123)

只是一个可计算函数。它以一个向量 uv 作为输入,它本身是一个 deterministic/computable 值——例如派生自 built-in 或自定义可变变量,为您提供当前片段的“坐标”。

评估后,函数的结果本身是 computable/deterministic 并且恰好是一个值(输入向量 uv 映射到)。抛开不同的 IEEE 754 规则和精度(这可能因不同的 GPU 而异,例如桌面和移动),函数本身纯粹是 deterministic/computable,因此不会给你一个 random值。

我们人类可能认为输出是随机的,因为我们对用于计算结果的函数缺乏直觉,因此当我们“看到”一个数字 0.623513632 后跟另一个数字 0.9734126 对于输入向量的微小变化,我们可以得出“是的,这看起来很随机”的结论,但事实显然并非如此。给定两个输入值,这就是该函数的计算结果。

所以,当你已经有了一个像上面这样的确定性函数,并且想从它的封闭范围 [0, 6] 中获取值作为 GLSL uint,你可以简单地缩放所述的输出通过将函数的结果乘以 7.0 和 t运行 来计算结果:

g(uv) = uint(f(uv) * 7.0)

如果你想获得 true 从随机变量中抽取的随机数(其确定性函数尚未被发现),你可以从宇宙背景辐射中获得这些值(例如来自 random.org)并将其用作着色器的输入(例如通过纹理或缓冲区对象)。

但是,从计算的角度来看,着色器只是一个接受值(整数、浮点数...)并计算(通过可计算函数)确定性结果的函数。 我们所能做的就是以这种方式 shuffle/scramble/diffuse 输入位,结果对我们来说“看起来”像是随机的。然后我们称这些为“pseudo-random”值。

更进一步,我们现在可以询问获得的 pseudo-random 值的分布质量问题。这有两个特点:

  1. pseudo-random 值在 domain/interval 中的分布有多均匀? IE。所有可能的值都具有相同的出现概率吗?或者:你甚至 想要 有 uniformly-distributed 值,或者这些值应该遵循另一个分布(比如 Guassian?)

  2. 从两个连续输入值 间隔 中提取的两个值有多好? IE。 pseudo-random 值的 频率 是多少?

有不同的(确定性的)algorithms/functions,具体取决于您的值应具有的分布和频谱。但首先,您应该为 use-case 定义两个问题的答案。 顺便说一句,您问题中用于在着色器中获取 pseudo-random 数字的常用函数具有 糟糕的 分布质量。

最后但同样重要的是,还应该提到 true 随机性(即 non-determinism),就像你 do 使用熵源作为输入值,在计算中通常是不受欢迎的 属性,因为它:

  1. 使得在需要时难以重复相同的计算/输出,这在路径跟踪上下文中的各种算法中很有用

  2. 很难reproduce/debug/inspect你的函数针对特定的运行当每个后续execution/run都会产生不同的输出