// 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; }