Writing a decent rand function seems impossible [ Solved ]

Hi all, I recently moved from Godot to Unity. I’m recreating a procedural skybox shader that I wrote in godot, and I need a fast rand function to use in voronoi and simplex noise functions. I’ve been trying to port over a (output 0->1) rand function from godot (GLSL) into HLSL, but the output value is always zero.

Here’s my code

Shader "Unlit/Sky shader"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "Queue"="Background"}
        LOD 100

        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #pragma target 4.0

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 eyeDir : TEXCOORD0;
            };

            float4 _SkyColor;
            float4 _SunColor;
            float _SunAngle;
            
            const uint c = 1103515245u;
            const float d = 1103515245;
            float rand1 (float position){
                // uint bitpos = asuint(position) + 1u;
                // bitpos = ((bitpos>>8u) ^ bitpos)*c;
                // bitpos = ((bitpos>>8u) ^ bitpos)*c;
                // return frac(float(bitpos)/d);
                uint bitpos = asuint(position);
                bitpos = (bitpos >> 8u) ^ bitpos;
                bitpos = (bitpos >> 8u) ^ bitpos;
                return frac(asfloat(bitpos));
            }

            v2f vert (appdata v)
            {
                v2f o;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float rand = rand1(_Time.y);
                return float4(rand, 0, 0, 1);
            }
            ENDCG
        }
    }
}

…which should result in a random shade of red each frame (which works as expected in godot).
In unity however, the result is just black (zero, not negative)

Any ideas?

i know absolutely nothing about bitshifts in shaders so i can’t help you there. i would try out a simpler random function, maybe the typical white noise often used would work for you.

from unity’s own simple noise node in shader graph:

inline float unity_noise_randomValue (float2 uv)
{
    return frac(sin(dot(uv, float2(12.9898, 78.233)))*43758.5453);
}

other suggestions are just using a noise texture, or maybe interleaved gradient noise, though the latter may not provide interesting input for the voronoi since it follows a distinct pattern.

The problems with the frac(sin(dot() white noise functions is that once the input gets large enough they start to become visibly periodic or have significant artifacts, I’m no mathematician but from what I’ve read about rand() on shadertoy and the likes is that bit manipulation hashes like the one I implemented in godot are faster in general and more robust at large input values, which is important for my shader.

It seems strange to me that a theoretically identical function is behaving so vastly differently in unity compared to godot.

Thanks for the reply though, if anyone else has any ideas I’d be grateful to hear them!

1 Like

Can’t help either, but there’re some (integer) hash functions in the Core RP library.

For example:

float random = GenerateHashedRandomFloat(_Time.y);