Stateful Randomness in Shaders

I often find myself needing good random numbers in shaders, but this gets messy when you want to generate a bunch of different ones for each pixel. To get around this, I’m using a genuinely awful hack in DaeForth.

Implementation #

:m rand-given-seed (| seed |)
        [ seed seed 1141 * sin ]
        [ 12.9898 78.233 ]
    dot sin 43758.5453 * fract
;
@float global =pixel-seed
real-position /rand-given-seed \+ =pixel-seed
:m seed .7 rand-given-seed ;
:m gen-seed
    seed =>cur-seed
    cur-seed rand-given-seed =>next-seed
    [ next-seed ] &seed def-macro
    cur-seed
;
:m next-random gen-seed pixel-seed * store rand-given-seed ;

Each time you call next-random it generates a new, high-quality random number for the given pixel. Importantly, it does so with low overhead at runtime!

Example #

For instance, this generates two random colors and then mixes them randomly (for a total of 7 invocations):

[
        [ next-random next-random next-random ]
        [ next-random next-random next-random ]
        next-random
    mix
    1
] ->fragColor

randomness.png

The majority of the RNG process actually occurs at compile-time, leaving each invocation with something along the lines of:

fract((sin(dot(vec2(tmp_0, sin((tmp_0) * (1141.))), vec2(12.9898, 78.233)))) * (43758.547));

How does it work? #

The magic here lies in the fact that it’s redefining the seed macro for each iteration. This makes the compiler generate the next seed value. Because they don’t depend in any way on the pixel seed (which can only be known at runtime, obviously) it gets boiled down to a single float per invocation.

For instance, you can see the 7 ‘seeds’ used in the example here:

    tmp_0 = (0.86328125) * (pixel_seed);
    tmp_1 = (0.19335938) * (pixel_seed);
    tmp_2 = (0.7783203) * (pixel_seed);
    tmp_3 = (0.55859375) * (pixel_seed);
    tmp_4 = (0.26171875) * (pixel_seed);
    tmp_5 = (0.7519531) * (pixel_seed);
    tmp_6 = (0.42773438) * (pixel_seed);

Happy hacking,

- Sera Brocious (Daeken)

 
5
Kudos
 
5
Kudos

Now read this

Bounty Progress - September 2019

I have a few goals for my bug bounty work in 2019: $50k in total bounties/bonuses (ACHIEVED!) At least one $5k bounty (for reference, current best is $4802) At least half my reports rated high/critical (CVSS 7+) Blog about my progress... Continue →