105 lines
3.2 KiB
HLSL
105 lines
3.2 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
// 3D random number generator inspired by PCGs (permuted congruential generator)
|
|
// Using a **simple** Feistel cipher in place of the usual xor shift permutation step
|
|
// @param v = 3D integer coordinate
|
|
// @return three elements w/ 16 random bits each (0-0xffff).
|
|
// ~8 ALU operations for result.x (7 mad, 1 >>)
|
|
// ~10 ALU operations for result.xy (8 mad, 2 >>)
|
|
// ~12 ALU operations for result.xyz (9 mad, 3 >>)
|
|
uint3 Rand3DPCG16(int3 p)
|
|
{
|
|
// taking a signed int then reinterpreting as unsigned gives good behavior for negatives
|
|
uint3 v = uint3(p);
|
|
|
|
// Linear congruential step. These LCG constants are from Numerical Recipies
|
|
// For additional #'s, PCG would do multiple LCG steps and scramble each on output
|
|
// So v here is the RNG state
|
|
v = v * 1664525u + 1013904223u;
|
|
|
|
// PCG uses xorshift for the final shuffle, but it is expensive (and cheap
|
|
// versions of xorshift have visible artifacts). Instead, use simple MAD Feistel steps
|
|
//
|
|
// Feistel ciphers divide the state into separate parts (usually by bits)
|
|
// then apply a series of permutation steps one part at a time. The permutations
|
|
// use a reversible operation (usually ^) to part being updated with the result of
|
|
// a permutation function on the other parts and the key.
|
|
//
|
|
// In this case, I'm using v.x, v.y and v.z as the parts, using + instead of ^ for
|
|
// the combination function, and just multiplying the other two parts (no key) for
|
|
// the permutation function.
|
|
//
|
|
// That gives a simple mad per round.
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
|
|
// only top 16 bits are well shuffled
|
|
return v >> 16u;
|
|
}
|
|
|
|
// 3D random number generator inspired by PCGs (permuted congruential generator)
|
|
// Using a **simple** Feistel cipher in place of the usual xor shift permutation step
|
|
// http://jcgt.org/published/0009/03/02/
|
|
// @param v = 3D integer coordinate
|
|
// @return three elements w/ 32 random bits each (0-0xffffffff).
|
|
uint3 Rand3DPCG32(int3 p)
|
|
{
|
|
// taking a signed int then reinterpreting as unsigned gives good behavior for negatives
|
|
uint3 v = uint3(p);
|
|
|
|
// Linear congruential step.
|
|
v = v * 1664525u + 1013904223u;
|
|
|
|
// shuffle
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
|
|
// xoring high bits into low bits makes all 32 bits pretty good
|
|
v ^= v >> 16u;
|
|
|
|
// final shuffle
|
|
v.x += v.y*v.z;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
|
|
return v;
|
|
}
|
|
|
|
// 4D random number generator inspired by PCGs (permuted congruential generator)
|
|
// Using a **simple** Feistel cipher in place of the usual xor shift permutation step
|
|
// http://jcgt.org/published/0009/03/02/
|
|
// @param v = 4D integer coordinate
|
|
// @return four elements w/ 32 random bits each (0-0xffffffff).
|
|
uint4 Rand4DPCG32(int4 p)
|
|
{
|
|
// taking a signed int then reinterpreting as unsigned gives good behavior for negatives
|
|
uint4 v = uint4(p);
|
|
|
|
// Linear congruential step.
|
|
v = v * 1664525u + 1013904223u;
|
|
|
|
// shuffle
|
|
v.x += v.y*v.w;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
v.w += v.y*v.z;
|
|
|
|
// xoring high bits into low makes all 32 bits pretty good
|
|
v ^= (v >> 16u);
|
|
|
|
// final shuffle
|
|
v.x += v.y*v.w;
|
|
v.y += v.z*v.x;
|
|
v.z += v.x*v.y;
|
|
v.w += v.y*v.z;
|
|
|
|
return v;
|
|
}
|