Skip to content

Commit d97946e

Browse files
committed
Improve the PRNG for the particles sample
The trig / fract approach for PRNG is not portable and can produce remarkably non-random results on IMG GPUs. Replace this with a bit-xor & shift function, adapted from the cornell sample. Fixes the particles sample on Pixel 10.
1 parent 426b33e commit d97946e

File tree

3 files changed

+31
-25
lines changed

3 files changed

+31
-25
lines changed

sample/cornell/common.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ fn raytrace(ray : Ray) -> HitInfo {
9090
return hit;
9191
}
9292

93-
// A psuedo random number. Initialized with init_rand(), updated with rand().
93+
// A pseudo random number. Initialized with init_rand(), updated with rand().
9494
var<private> rnd : vec3u;
9595

9696
// Initializes the random number generator.

sample/particles/main.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,20 +397,17 @@ const view = mat4.create();
397397
const mvp = mat4.create();
398398

399399
function frame() {
400-
device.queue.writeBuffer(
401-
simulationUBOBuffer,
402-
0,
403-
new Float32Array([
404-
simulationParams.simulate ? simulationParams.deltaTime : 0.0,
405-
simulationParams.brightnessFactor,
406-
0.0,
407-
0.0, // padding
408-
Math.random() * 100,
409-
Math.random() * 100, // seed.xy
410-
1 + Math.random(),
411-
1 + Math.random(), // seed.zw
412-
])
413-
);
400+
const uboDataF32 = new Float32Array(simulationUBOBuffer.size / 4);
401+
const uboDataU32 = new Uint32Array(uboDataF32);
402+
uboDataF32[0] = simulationParams.simulate ? simulationParams.deltaTime : 0.0;
403+
uboDataF32[1] = simulationParams.brightnessFactor;
404+
// [2] [3] are alignment padding
405+
uboDataU32[4] = 0xffffffff * Math.random(); // seed.x
406+
uboDataU32[5] = 0xffffffff * Math.random(); // seed.y
407+
uboDataU32[6] = 0xffffffff * Math.random(); // seed.z
408+
uboDataU32[7] = 0xffffffff * Math.random(); // seed.w
409+
410+
device.queue.writeBuffer(simulationUBOBuffer, 0, uboDataF32);
414411

415412
mat4.identity(view);
416413
mat4.translate(view, vec3.fromValues(0, 0, -3), view);

sample/particles/particle.wgsl

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
////////////////////////////////////////////////////////////////////////////////
22
// Utilities
33
////////////////////////////////////////////////////////////////////////////////
4-
var<private> rand_seed : vec2f;
5-
6-
fn init_rand(invocation_id : u32, seed : vec4f) {
7-
rand_seed = seed.xz;
8-
rand_seed = fract(rand_seed * cos(35.456+f32(invocation_id) * seed.yw));
9-
rand_seed = fract(rand_seed * cos(41.235+f32(invocation_id) * seed.xw));
4+
// A pseudo random number. Initialized with init_rand(), updated with rand().
5+
var<private> rnd : vec4u;
6+
7+
// Initializes the random number generator.
8+
fn init_rand(invocation_id : u32, seed : vec4u) {
9+
const A = vec4(1741651 * 1009,
10+
140893 * 1609 * 13,
11+
6521 * 983 * 7 * 2,
12+
1109 * 509 * 83 * 11 * 3);
13+
rnd = (A * vec4u(invocation_id)) ^ seed;
1014
}
1115

16+
// Returns a random number between 0 and 1.
1217
fn rand() -> f32 {
13-
rand_seed.x = fract(cos(dot(rand_seed, vec2f(23.14077926, 232.61690225))) * 136.8168);
14-
rand_seed.y = fract(cos(dot(rand_seed, vec2f(54.47856553, 345.84153136))) * 534.7645);
15-
return rand_seed.y;
18+
const C = vec4(60493 * 9377,
19+
11279 * 2539 * 23,
20+
7919 * 631 * 5 * 3,
21+
1277 * 211 * 19 * 7 * 2);
22+
23+
rnd = (rnd * C) ^ (rnd.yzwx >> vec4(4u));
24+
return f32(rnd.x ^ rnd.y) / f32(0xffffffff);
1625
}
1726

1827
////////////////////////////////////////////////////////////////////////////////
@@ -65,7 +74,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4f {
6574
struct SimulationParams {
6675
deltaTime : f32,
6776
brightnessFactor : f32,
68-
seed : vec4f,
77+
seed : vec4u,
6978
}
7079

7180
struct Particle {

0 commit comments

Comments
 (0)