@@ -16,7 +16,7 @@ const vec2 left = vec2(-1, 0);
1616
1717uniform float k; // spring constant
1818uniform float damping; // velocity damping
19- const float scale = 1.0 ; // scale for reading/formatting velocity/offsets
19+ const float scale = 1 .0f ; // scale for reading/formatting velocity/offsets
2020uniform float clamp_value; // clamp max velocity/offsets
2121uniform float turbulence_factor; // turbulence strength multiplier [0 - 10]
2222
@@ -39,23 +39,57 @@ vec4 getPixel(vec2 coord) {
3939}
4040
4141vec2 getOffset(vec4 pixel) {
42- return vec2 (pixel.z * 2.0 - 1.0 , pixel.a * 2.0 - 1.0 ) * scale;
42+ return vec2 (pixel.z * 2 .0f - 1 .0f , pixel.a * 2 .0f - 1 .0f ) * scale;
4343}
4444
4545vec2 getVelocity(vec4 pixel) {
46- return vec2 (pixel.x * 2.0 - 1.0 , pixel.y * 2.0 - 1.0 ) * scale;
46+ return vec2 (pixel.x * 2 .0f - 1 .0f , pixel.y * 2 .0f - 1 .0f ) * scale;
4747}
4848
4949bool isEdgePixel(vec2 coord) {
50- if (coord.x <= 1.0 || coord.x >= resolution.x - 1.0 || coord.y <= 1.0 || coord.y >= resolution.y - 1.0 ) return true;
51- if (texture(obstacles, coord / resolution.xy).r > 0.5 ) return true;
50+ if (coord.x <= 1 .0f || coord.x >= resolution.x - 1 .0f || coord.y <= 1 .0f || coord.y >= resolution.y - 1 .0f)
51+ return true;
52+ if (texture(obstacles, coord / resolution.xy).r > 0 .5f)
53+ return true;
5254 return false;
5355}
5456
5557// random number [0,1] inclusive
5658float rand(vec2 identity) {
57- vec2 seeded = identity + vec2 (seed * 0.1 , seed * 0.2 );
58- return fract (sin (dot (seeded, vec2 (12.9898 , 78.233 ))) * 43758.5453 );
59+ vec2 seeded = identity + vec2 (seed * 0 .1f, seed * 0 .2f);
60+ return fract (sin (dot (seeded, vec2 (12 .9898f, 78 .233f))) * 43758 .5453f);
61+ }
62+
63+ // A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm for u32.
64+ uint hash_u32(uint x_in) {
65+ uint x = x_in;
66+ x += (x << 10u);
67+ x ^= (x >> 6u);
68+ x += (x << 3u);
69+ x ^= (x >> 11u);
70+ x += (x << 15u);
71+ return x;
72+ }
73+
74+ // Construct a float with half-open range [0:1] using low 23 bits.
75+ // All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0.
76+ float float_construct_from_u32(uint m_in) {
77+ uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask
78+ uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32
79+
80+ uint m = m_in;
81+ m &= ieeeMantissa; // Keep only mantissa bits (fractional part)
82+ m |= ieeeOne; // Add fractional part to 1.0
83+
84+ float f = uintBitsToFloat(m); // Range [1:2]
85+ return f - 1 .0f; // Range [0:1]
86+ }
87+
88+ // Pseudo-random value in half-open range [0:1] from a f32 seed.
89+ // from https://marktension.nl/blog/my_favorite_wgsl_random_func_so_far/
90+ float random_uniform(vec2 identity) {
91+ float seeded = identity.x * seed * 0 .1f + identity.y * seed * 0 .2f;
92+ return float_construct_from_u32(hash_u32(floatBitsToUint(seeded)));
5993}
6094
6195vec2 updateForces(vec2 forces, vec2 position, vec2 direction) {
@@ -67,7 +101,7 @@ vec2 updateForces(vec2 forces, vec2 position, vec2 direction) {
67101
68102 vec2 spring_vec = n_position - position;
69103 float current_length = length (spring_vec);
70- if (current_length > 0.001 ) { // avoid division by zero
104+ if (current_length > 0 .001f ) { // avoid division by zero
71105 vec2 spring_dir = spring_vec / current_length;
72106 float displacement = current_length - rest_length;
73107
@@ -81,17 +115,16 @@ vec2 updateForces(vec2 forces, vec2 position, vec2 direction) {
81115}
82116
83117vec2 format(vec2 v) {
84- return clamp (v / scale * 0.5 + vec2 (0.5 ), 0.0 , 1.0 );
118+ return clamp (v / scale * 0 .5f + vec2 (0 .5f ), 0 .0f , 1 .0f );
85119}
86120
87-
88121void main() {
89122 vec4 rgba = getPixel();
90123
91124 bool isEdge = isEdgePixel(gl_FragCoord .xy);
92125
93- if (isEdge) {
94- fragColor = vec4 (0.5 , 0.5 , 0.5 , 0.5 );
126+ if (isEdge) {
127+ fragColor = vec4 (0 .5f , 0 .5f , 0 .5f , 0 .5f );
95128 return ;
96129 }
97130
@@ -100,7 +133,7 @@ void main() {
100133 vec2 position = vec2 (gl_FragCoord .xy + offsets);
101134
102135 // spring force from neighbors
103- vec2 forces = vec2 (0.0 , 0.0 );
136+ vec2 forces = vec2 (0 .0f , 0 .0f );
104137 forces = updateForces(forces, position, left);
105138 forces = updateForces(forces, position, right);
106139 forces = updateForces(forces, position, top);
@@ -111,33 +144,30 @@ void main() {
111144 forces = updateForces(forces, position, bottom + right);
112145
113146 // turbulence / noise
114- if (turbulence_factor > 0.0 ) {
147+ if (turbulence_factor > 0 .0f ) {
115148 float turbulence_strength = turbulence_factor * length (velocity);
116149 float noise = rand(gl_FragCoord .xy);
117- vec2 turbulence = vec2 (cos (noise * 6.28318 ), sin (noise * 6.28318 ));
150+ vec2 turbulence = vec2 (cos (noise * 6 .28318f ), sin (noise * 6 .28318f ));
118151 forces += turbulence * turbulence_strength;
119152 }
120153
121154 // velocity
122155 velocity += forces * dt;
123156 velocity *= damping;
124- if (length (velocity) < clamp_value * scale) {
125- velocity = vec2 (0.0 , 0.0 );
157+ if (length (velocity) < clamp_value * scale) {
158+ velocity = vec2 (0 .0f , 0 .0f );
126159 }
127160
128161 // position
129162 offsets += velocity * dt;
130- if (velocity.x == 0.0 && velocity.y == 0.0 && length (offsets) < clamp_value * scale) {
131- offsets = vec2 (0.0 , 0.0 );
163+ if (velocity.x == 0 .0f && velocity.y == 0 .0f && length (offsets) < clamp_value * scale) {
164+ offsets = vec2 (0 .0f , 0 .0f );
132165 }
133166
134167 // clamp
135168 offsets = format(offsets);
136169 velocity = format(velocity);
137170
138171 // output
139- fragColor = vec4 (
140- velocity,
141- offsets
142- );
172+ fragColor = vec4 (velocity, offsets);
143173}
0 commit comments