Random 如何在金属着色器中获取随机数?

Random 如何在金属着色器中获取随机数?,random,metal,Random,Metal,如何在金属着色器中获取随机数 我在金属着色语言规范中搜索了“random”,但没有找到任何内容。看起来没有内置的。此示例代码定义了自己的简单rand函数 // Generate a random float in the range [0.0f, 1.0f] using x, y, and z (based on the xor128 algorithm) float rand(int x, int y, int z) { int seed = x + y * 57 + z * 241;

如何在金属着色器中获取随机数


我在金属着色语言规范中搜索了“random”,但没有找到任何内容。

看起来没有内置的。此示例代码定义了自己的简单
rand
函数

// Generate a random float in the range [0.0f, 1.0f] using x, y, and z (based on the xor128 algorithm)
float rand(int x, int y, int z)
{
    int seed = x + y * 57 + z * 241;
    seed= (seed<< 13) ^ seed;
    return (( 1.0 - ( (seed * (seed * seed * 15731 + 789221) + 1376312589) & 2147483647) / 1073741824.0f) + 1.0f) / 2.0f;
}
//使用x、y和z(基于xor128算法)在[0.0f、1.0f]范围内生成一个随机浮点
浮点随机数(整数x,整数y,整数z)
{
int seed=x+y*57+z*241;

seed=(seed除了在GPU上计算随机数,你还可以在CPU上计算一组随机数,并使用统一的/
MTLBuffer
将它们传递到着色器中,因此我正在为另一个项目开发一个随机数生成器,并想将其打包到一个整洁的框架中

你的问题促使我这么做。如果你不介意无耻的插件,这是一个非常简单的框架,它将在金属着色器中为你生成一个随机数,基于(最多)你给它三个种子。代码基于描述如何在并行处理器上为蒙特卡罗模拟创建随机数的。它还有一个(理论)周期
2^121
,因此它应该适合在GPU上进行最合理的计算

在着色器中只需调用初始化器,然后调用
rand()
,如下所示:

// Initialize a random number generator, seeds 2 and 3 are optional
Loki rng = Loki(seed1, seed2, seed3);

// get a random float [0,1)
float random_float = rng.rand();

我还在回购协议中加入了一个示例项目,这样你就可以看到它是如何使用的。

请看一下
[pcg random]
,它非常简单和快速,更重要的是它很快。而且修改金属的C代码非常容易


我不认为这个解决方案是一个非常有效的解决方案,但是对于需要大量随机数在运行中生成的应用程序来说……仅仅在金属着色器中创建一个随机数生成器不是更好吗?@QuantumHoneybees,随机性必须来自某个地方。即使在金属中实现了RNG,您也希望/需要种子从CPU获取初始随机性。如果使用顶点ID或碎片位置之类的内容作为种子,则每次运行都不会是随机的。@Kenthomass好吧,如果我们从CPU传递随机性的内容,看起来最轻的传递应该是“帧计数器”所以它实际上是随机运行的。多亏了几周前,我实际上能够创建一个在多个迭代中运行得非常好的程序。我很想听听你对所有人的反馈!(:@QuantumHoneybees-Huh?如果你传递一个帧计数器,它在一次运行中不会是随机的。是的,它在一次运行中会在一帧到另一帧之间是随机的,但下一次运行将再次启动帧计数器,你只需重复与所有其他运行相同的序列。@QuantumHoneybees,当然,只传递一个随机种子值是有意义的,这取决于你的操作你需要很多真正的随机性。但现在我们只是在争论你从CPU发送了多少随机数据。你需要发送一些数据的原则仍然成立。发送很多数据而不在GPU上生成任何数据可能是一个有效的选择。对x,y,z有什么要求吗?我会根据像素位置和系统生成噪声。噪声看起来它是周期性的,所以不好。
typedef struct { uint64_t state;  uint64_t inc; } pcg32_random_t;

void pcg32_srandom_r(thread pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
{
    rng->state = 0U;
    rng->inc = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initstate;
    pcg32_random_r(rng);
}

uint32_t pcg32_random_r(thread pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    rng->state = oldstate * 6364136223846793005ULL + rng->inc;
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

float randomF(thread pcg32_random_t* rng)
{
    //return pcg32_random_r(rng)/float(UINT_MAX);
    return ldexp(float(pcg32_random_r(rng)), -32);
}

pcg32_random_t rng;
pcg32_srandom_r(&rng, pos_grid.x*int_time, pos_grid.y*int_time);

auto randomFloat = randomF(&rng);