|
1 | 1 | import tgpu, { d, type TgpuFnShell, type TgpuSlot } from 'typegpu'; |
2 | | -import { bitcastU32toF32, cos, dot, fract } from 'typegpu/std'; |
| 2 | +import { cos, dot, fract } from 'typegpu/std'; |
| 3 | +import { hash, u32To01Float } from './utils.ts'; |
3 | 4 |
|
4 | 5 | export interface StatefulGenerator { |
5 | 6 | seed?: (seed: number) => void; |
@@ -49,36 +50,70 @@ export const BPETER: StatefulGenerator = (() => { |
49 | 50 | })(); |
50 | 51 |
|
51 | 52 | /** |
52 | | - * Naive Linear Congruential Generator (LCG) |
| 53 | + * Incorporated from https://github.com/chaos-matters/chaos-master |
| 54 | + * by deluksic and Komediruzecki |
53 | 55 | */ |
54 | | -export const LCG: StatefulGenerator = (() => { |
55 | | - const seed = tgpu.privateVar(d.u32); |
| 56 | +export const XOROSHIRO64STARSTAR: StatefulGenerator = (() => { |
| 57 | + const seed = tgpu.privateVar(d.vec2u); |
| 58 | + |
| 59 | + const rotl = tgpu.fn( |
| 60 | + [d.u32, d.u32], |
| 61 | + d.u32, |
| 62 | + )((x, k) => { |
| 63 | + return (x << k) | (x >> (32 - k)); |
| 64 | + }); |
| 65 | + |
| 66 | + const next = tgpu.fn([])(() => { |
| 67 | + const s0 = seed.$[0]; |
| 68 | + let s1 = seed.$[1]; |
56 | 69 |
|
57 | | - const u32To01Float = tgpu.fn( |
58 | | - [d.u32], |
59 | | - d.f32, |
60 | | - )((value) => { |
61 | | - const mantissa = value >> 9; |
62 | | - const bits = 0x3f800000 | mantissa; |
63 | | - const f = bitcastU32toF32(bits); |
64 | | - return f - 1; |
| 70 | + s1 ^= s0; |
| 71 | + seed.$[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); |
| 72 | + seed.$[1] = rotl(s1, 13); |
65 | 73 | }); |
66 | 74 |
|
67 | 75 | return { |
68 | | - seed: tgpu.fn([d.f32])((value) => { |
69 | | - seed.$ = d.u32(value * 32768); |
70 | | - }), |
71 | | - |
72 | 76 | seed2: tgpu.fn([d.vec2f])((value) => { |
73 | | - seed.$ = d.u32(value.x * 32768 + value.y * 1024); |
| 77 | + seed.$ = d.vec2u(value); |
74 | 78 | }), |
75 | 79 |
|
76 | | - seed3: tgpu.fn([d.vec3f])((value) => { |
77 | | - seed.$ = d.u32(value.x * 32768 + value.y * 1024 + value.z * 32); |
| 80 | + sample: randomGeneratorShell(() => { |
| 81 | + 'use gpu'; |
| 82 | + next(); |
| 83 | + const r = seed.$.x; |
| 84 | + return u32To01Float(r); |
| 85 | + }).$name('sample'), |
| 86 | + }; |
| 87 | +})(); |
| 88 | + |
| 89 | +/** |
| 90 | + * Naive Linear Congruential Generator (LCG) with 32 bits state |
| 91 | + */ |
| 92 | +export const LCG32: StatefulGenerator = (() => { |
| 93 | + const seed = tgpu.privateVar(d.u32); |
| 94 | + |
| 95 | + return { |
| 96 | + seed: tgpu.fn([d.f32])((value) => { |
| 97 | + seed.$ = hash(d.u32(value)); |
78 | 98 | }), |
79 | 99 |
|
80 | | - seed4: tgpu.fn([d.vec4f])((value) => { |
81 | | - seed.$ = d.u32(value.x * 32768 + value.y * 1024 + value.z * 32 + value.w); |
| 100 | + sample: randomGeneratorShell(() => { |
| 101 | + 'use gpu'; |
| 102 | + seed.$ = seed.$ * 1664525 + 1013904223; // % 2 ^ 32 |
| 103 | + return u32To01Float(seed.$); |
| 104 | + }).$name('sample'), |
| 105 | + }; |
| 106 | +})(); |
| 107 | + |
| 108 | +/** |
| 109 | + * Naive Linear Congruential Generator (LCG) with 64 bits state |
| 110 | + */ |
| 111 | +export const LCG64: StatefulGenerator = (() => { |
| 112 | + const seed = tgpu.privateVar(d.u32); |
| 113 | + |
| 114 | + return { |
| 115 | + seed: tgpu.fn([d.f32])((value) => { |
| 116 | + seed.$ = d.u32(value) * 1048577; |
82 | 117 | }), |
83 | 118 |
|
84 | 119 | sample: randomGeneratorShell(() => { |
|
0 commit comments