// Shared procedural noise functions for cloud rendering
// Hash-based (no texture dependency) - suitable for GPU evaluation
// --- Hash functions ---
float hash21(vec2 p) {
// High-quality hash using 3-component mixing (same family as hash22)
vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
vec2 hash22(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.xx + p3.yz) * p3.zy);
}
// --- Value noise ---
float value_noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
// Quintic interpolation (C2 continuous — no visible grid artifacts)
f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
float a = hash21(i);
float b = hash21(i + vec2(1.0, 0.0));
float c = hash21(i + vec2(0.0, 1.0));
float d = hash21(i + vec2(1.0, 1.0));
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}
// --- Worley noise (cellular) ---
float worley_noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float min_dist = 1.0;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x), float(y));
vec2 point = hash22(i + neighbor);
vec2 diff = neighbor + point - f;
min_dist = min(min_dist, length(diff));
}
}
return min_dist;
}
// --- Voronoi noise ---
float voronoi_noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float min_dist = 1.0;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x), float(y));
vec2 point = hash22(i + neighbor);
float d = length(neighbor + point - f);
min_dist = min(min_dist, d);
}
}
return min_dist;
}