summaryrefslogtreecommitdiffstats
path: root/math.cginc
diff options
context:
space:
mode:
Diffstat (limited to 'math.cginc')
-rwxr-xr-xmath.cginc92
1 files changed, 92 insertions, 0 deletions
diff --git a/math.cginc b/math.cginc
index 9d95588..6b24a55 100755
--- a/math.cginc
+++ b/math.cginc
@@ -109,5 +109,97 @@ float4 alpha_blend(float4 front, float4 back) {
return float4(front.rgb * front.a + back.rgb * (1 - front.a), front.a + back.a * (1 - front.a));
}
+// Cheap procedural 3D hash -> [0,1]^3. Based on the "hashwithoutsine" family.
+float3 hash33_fast(float3 p) {
+ p = frac(p * float3(0.1031, 0.1030, 0.0973));
+ p += dot(p, p.yxz + 33.33);
+ return frac((p.xxy + p.yxx) * p.zyx);
+}
+
+// Procedural value noise in [0,1]^3 — trilinear interpolation of hashed corners.
+float3 value_noise3(float3 p) {
+ float3 i = floor(p);
+ float3 f = frac(p);
+ float3 u = f * f * (3.0 - 2.0 * f);
+
+ return lerp(
+ lerp(lerp(hash33_fast(i + float3(0, 0, 0)), hash33_fast(i + float3(1, 0, 0)), u.x),
+ lerp(hash33_fast(i + float3(0, 1, 0)), hash33_fast(i + float3(1, 1, 0)), u.x), u.y),
+ lerp(lerp(hash33_fast(i + float3(0, 0, 1)), hash33_fast(i + float3(1, 0, 1)), u.x),
+ lerp(hash33_fast(i + float3(0, 1, 1)), hash33_fast(i + float3(1, 1, 1)), u.x), u.y),
+ u.z);
+}
+
+// Domain warping using procedural value noise.
+float3 domain_warp_procedural(float3 uvw, float strength,
+ uint octaves, float lacunarity, float gain) {
+ float3 noise = 0;
+ float g = 1;
+
+ for (uint ii = 0; ii < octaves; ++ii) {
+ noise += value_noise3(uvw + noise * strength) * g;
+ uvw *= lacunarity;
+ g *= gain;
+ }
+
+ noise *= (1 - gain) / (1 - pow(gain, octaves));
+
+ return noise;
+}
+
+// Domain warping using a 3D noise texture. Texture should have an EV of
+// 0.5.
+float3 domain_warp_3d_tex(texture3D noise_tex, float3 uvw, float strength,
+ uint octaves, float lacunarity, float gain) {
+ float3 noise = 0;
+ float g = 1;
+
+ float3 uvw_dx = ddx(uvw);
+ float3 uvw_dy = ddy(uvw);
+
+ for (uint ii = 0; ii < octaves; ++ii) {
+ noise += noise_tex.SampleGrad(aniso4_trilinear_repeat_s, uvw + noise * strength, uvw_dx, uvw_dy).rgb * g;
+ uvw *= lacunarity;
+ g *= gain;
+ uvw_dx *= lacunarity;
+ uvw_dy *= lacunarity;
+ }
+
+ // Normalize: geometric series 1 + r + ... + r^{n-1} = (1 - r^n) / (1 - r)
+ noise *= (1 - gain) / (1 - pow(gain, octaves));
+
+ return noise;
+}
+
+// Return distance to the nearest cell edge in a Voronoi pattern.
+float voronoi_edge_distance(float3 x) {
+ float3 p = floor(x);
+ float3 f = frac(x);
+ float d1 = 1e6;
+ float d2 = 1e6;
+ float3 p1 = 0;
+ float3 p2 = 0;
+
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 b = float3(i, j, k);
+ float3 r = b + hash33_fast(p + b) - f;
+ float d = dot(r, r);
+ if (d < d1) {
+ d2 = d1;
+ p2 = p1;
+ d1 = d;
+ p1 = r;
+ } else if (d < d2) {
+ d2 = d;
+ p2 = r;
+ }
+ }
+ }
+ }
+ return (d2 - d1) / (2.0 * max(1e-4, length(p2 - p1)));
+}
+
#endif // __MATH_INC