Created
April 2, 2026 15:35
-
-
Save jazzathedev/2f842a78d0ec62b356312337f3a5cf80 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * fluid_noise.osl — Fluid-like noise shader for Blender Cycles | |
| * | |
| * Presets (dropdown in node UI): | |
| * jupiter — toxic lime/orange alien storm | |
| * deep_ocean — slow deep-sea thermals | |
| * magma — lava flow / pyroclastic | |
| * aurora — polar light curtains | |
| * inkdrop — ink diffusing in water, near-monochrome | |
| * custom — use all manual inputs as-is | |
| */ | |
| #include "stdosl.h" | |
| /* ═══════════════════════════════════════════════════════════════════════ | |
| Utilities | |
| ═══════════════════════════════════════════════════════════════════════ */ | |
| float fbm(point p, int octaves, float persistence, float lacunarity) | |
| { | |
| float val = 0.0, amp = 0.5, freq = 1.0, norm = 0.0; | |
| for (int i = 0; i < octaves; i++) { | |
| val += amp * (float)noise("perlin", p * freq); | |
| norm += amp; | |
| amp *= persistence; | |
| freq *= lacunarity; | |
| } | |
| return val / max(norm, 1e-5); | |
| } | |
| float pot(point p, float seed) | |
| { | |
| return (float)noise("perlin", | |
| p + vector(seed*1.71934, seed*0.31271, seed*2.18413)); | |
| } | |
| vector curlNoise(point p, float eps) | |
| { | |
| float ie = 0.5 / eps; | |
| vector ex = vector(eps,0,0), ey = vector(0,eps,0), ez = vector(0,0,eps); | |
| float cx = (pot(p+ey,2.0)-pot(p-ey,2.0)-pot(p+ez,1.0)+pot(p-ez,1.0))*ie; | |
| float cy = (pot(p+ez,0.0)-pot(p-ez,0.0)-pot(p+ex,2.0)+pot(p-ex,2.0))*ie; | |
| float cz = (pot(p+ex,1.0)-pot(p-ex,1.0)-pot(p+ey,0.0)+pot(p-ey,0.0))*ie; | |
| return vector(cx, cy, cz); | |
| } | |
| color ramp(float t, | |
| float s0, color c0, float s1, color c1, | |
| float s2, color c2, float s3, color c3, | |
| float s4, color c4) | |
| { | |
| float tt = clamp(t, 0.0, 1.0); | |
| if (tt <= s0) return c0; | |
| if (tt >= s4) return c4; | |
| if (tt < s1) return mix(c0, c1, (tt-s0)/max(s1-s0,1e-5)); | |
| if (tt < s2) return mix(c1, c2, (tt-s1)/max(s2-s1,1e-5)); | |
| if (tt < s3) return mix(c2, c3, (tt-s2)/max(s3-s2,1e-5)); | |
| return mix(c3, c4, (tt-s3)/max(s4-s3,1e-5)); | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════════ | |
| Main shader | |
| ═══════════════════════════════════════════════════════════════════════ */ | |
| shader fluid_noise( | |
| /* ── Spatial / time ─────────────────────────────────── */ | |
| point Pos = P, | |
| float Scale = 2.5, | |
| float Time = 0.0, | |
| /* ── Preset selector — renders as a dropdown in Blender ─ */ | |
| string Preset = "jupiter" | |
| [[ string widget = "popup", | |
| string options = "jupiter|deep_ocean|magma|aurora|inkdrop|custom" ]], | |
| /* ── Manual overrides (only matter when Preset = "custom") ─ */ | |
| int Octaves = 8, | |
| float Persistence = 0.52, | |
| float Lacunarity = 2.3, | |
| float WarpStrength = 1.4, | |
| int WarpIterations = 4, | |
| float CurlEps = 0.004, | |
| float VorticityBlend = 0.55, | |
| float Contrast = 1.6, | |
| float Brightness = 0.0, | |
| float TimeDrift = 0.07, | |
| /* ── Custom colour stops ────────────────────────────── */ | |
| color Col0 = color(0.00, 0.00, 0.00), | |
| color Col1 = color(0.05, 0.18, 0.02), | |
| color Col2 = color(0.30, 0.72, 0.00), | |
| color Col3 = color(0.82, 0.88, 0.00), | |
| color Col4 = color(0.92, 0.38, 0.00), | |
| output float Fac = 0.0, | |
| output color Color = 0.0 | |
| ) | |
| { | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 0 — load preset values | |
| Each preset writes into these working variables, which are then | |
| used for ALL subsequent computation, not just colour. | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| int p_octaves = Octaves; | |
| float p_persist = Persistence; | |
| float p_lacun = Lacunarity; | |
| float p_warpStr = WarpStrength; | |
| int p_warpIter = WarpIterations; | |
| float p_curlEps = CurlEps; | |
| float p_vortBlend = VorticityBlend; | |
| float p_contrast = Contrast; | |
| float p_bright = Brightness; | |
| float p_drift = TimeDrift; | |
| float p_scale = Scale; | |
| /* colour stops */ | |
| float ps0 = 0.00; color pc0 = Col0; | |
| float ps1 = 0.25; color pc1 = Col1; | |
| float ps2 = 0.50; color pc2 = Col2; | |
| float ps3 = 0.75; color pc3 = Col3; | |
| float ps4 = 1.00; color pc4 = Col4; | |
| /* ── Jupiter ───────────────────────────────────────────────────────── | |
| * Tight high-frequency swirls, strong vortex filaments, fast motion. | |
| * Bulk of the field sits in the lime band; orange only at peaks. */ | |
| if (Preset == "jupiter") { | |
| p_octaves = 8; | |
| p_persist = 0.52; | |
| p_lacun = 2.30; | |
| p_warpStr = 1.40; | |
| p_warpIter = 4; | |
| p_curlEps = 0.004; | |
| p_vortBlend = 0.55; | |
| p_contrast = 1.60; | |
| p_bright = 0.00; | |
| p_drift = 0.07; | |
| p_scale = 2.50; | |
| ps0 = 0.00; pc0 = color(0.01, 0.02, 0.00); | |
| ps1 = 0.22; pc1 = color(0.04, 0.18, 0.01); | |
| ps2 = 0.48; pc2 = color(0.45, 0.82, 0.00); | |
| ps3 = 0.70; pc3 = color(0.78, 0.76, 0.00); | |
| ps4 = 1.00; pc4 = color(0.90, 0.34, 0.00); | |
| } | |
| /* ── Deep ocean ────────────────────────────────────────────────────── | |
| * Very slow large-scale rolls, low lacunarity (broad swirls), gentle | |
| * vorticity. Feels like thermohaline convection. */ | |
| else if (Preset == "deep_ocean") { | |
| p_octaves = 6; | |
| p_persist = 0.58; /* smoother, rounder shapes */ | |
| p_lacun = 1.80; /* lower = larger, fewer curls */ | |
| p_warpStr = 0.90; | |
| p_warpIter = 3; | |
| p_curlEps = 0.006; | |
| p_vortBlend = 0.20; /* soft, not filament-y */ | |
| p_contrast = 1.20; | |
| p_bright = 0.05; | |
| p_drift = 0.025; /* very slow evolution */ | |
| p_scale = 1.80; | |
| ps0 = 0.00; pc0 = color(0.00, 0.00, 0.05); | |
| ps1 = 0.20; pc1 = color(0.00, 0.06, 0.24); | |
| ps2 = 0.45; pc2 = color(0.00, 0.28, 0.55); | |
| ps3 = 0.68; pc3 = color(0.00, 0.62, 0.72); | |
| ps4 = 1.00; pc4 = color(0.40, 0.95, 0.95); | |
| } | |
| /* ── Magma ─────────────────────────────────────────────────────────── | |
| * Sluggish top-level warp but lots of fine detail octaves. Strong | |
| * contrast to keep most of the field dark with bright crack-like | |
| * filaments. Slow drift speed. */ | |
| else if (Preset == "magma") { | |
| p_octaves = 9; /* lots of fine crust-crack detail */ | |
| p_persist = 0.48; | |
| p_lacun = 2.50; /* very fine veining */ | |
| p_warpStr = 1.80; /* heavy warp to break up any regularity */ | |
| p_warpIter = 4; | |
| p_curlEps = 0.003; | |
| p_vortBlend = 0.70; /* strong filaments = glowing crack edges*/ | |
| p_contrast = 2.20; /* most field is dark; peaks burn bright */ | |
| p_bright = -0.08; /* pull midtones down toward black */ | |
| p_drift = 0.018; /* lava is slow */ | |
| p_scale = 3.00; | |
| ps0 = 0.00; pc0 = color(0.00, 0.00, 0.00); | |
| ps1 = 0.28; pc1 = color(0.22, 0.00, 0.00); | |
| ps2 = 0.55; pc2 = color(0.72, 0.06, 0.00); | |
| ps3 = 0.78; pc3 = color(0.98, 0.50, 0.00); | |
| ps4 = 1.00; pc4 = color(1.00, 0.96, 0.82); | |
| } | |
| /* ── Aurora ────────────────────────────────────────────────────────── | |
| * Tall vertical curtains — low warp iterations, higher persistence | |
| * for dreamy soft bands. Very low drift (aurora moves slowly). */ | |
| else if (Preset == "aurora") { | |
| p_octaves = 5; | |
| p_persist = 0.65; /* soft, washy forms */ | |
| p_lacun = 1.90; | |
| p_warpStr = 0.70; /* gentle — keeps the curtain structure */ | |
| p_warpIter = 2; /* fewer warp passes = less tangled */ | |
| p_curlEps = 0.007; | |
| p_vortBlend = 0.30; | |
| p_contrast = 1.10; | |
| p_bright = 0.08; | |
| p_drift = 0.012; | |
| p_scale = 1.50; | |
| ps0 = 0.00; pc0 = color(0.01, 0.00, 0.08); | |
| ps1 = 0.22; pc1 = color(0.08, 0.00, 0.32); | |
| ps2 = 0.48; pc2 = color(0.00, 0.52, 0.62); | |
| ps3 = 0.72; pc3 = color(0.22, 0.90, 0.72); | |
| ps4 = 1.00; pc4 = color(0.88, 0.96, 1.00); | |
| } | |
| /* ── Inkdrop ───────────────────────────────────────────────────────── | |
| * Ink diffusing in water. Maximum domain warp iterations and high | |
| * vorticity for micro-tendrils. Near-monochrome: deep indigo → cream. | |
| * Medium speed. */ | |
| else if (Preset == "inkdrop") { | |
| p_octaves = 8; | |
| p_persist = 0.55; | |
| p_lacun = 2.20; | |
| p_warpStr = 2.20; /* very tangled — ink doesn't flow clean */ | |
| p_warpIter = 5; /* maximum nesting */ | |
| p_curlEps = 0.003; | |
| p_vortBlend = 0.80; /* the tendrils ARE the point */ | |
| p_contrast = 1.80; | |
| p_bright = -0.05; | |
| p_drift = 0.055; | |
| p_scale = 2.80; | |
| ps0 = 0.00; pc0 = color(0.02, 0.01, 0.06); | |
| ps1 = 0.25; pc1 = color(0.10, 0.06, 0.28); | |
| ps2 = 0.50; pc2 = color(0.28, 0.22, 0.50); | |
| ps3 = 0.74; pc3 = color(0.70, 0.68, 0.78); | |
| ps4 = 1.00; pc4 = color(0.96, 0.94, 0.92); | |
| } | |
| /* "custom" — all p_ variables already hold the manual input values */ | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 1 — base position | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| point base = Pos * p_scale + vector(0.0, 0.0, Time * p_drift); | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 2 — iterative curl domain warp | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| point warped = base; | |
| float wAmp = p_warpStr; | |
| for (int i = 0; i < p_warpIter; i++) { | |
| float s = pow(1.75, (float)i); | |
| vector c = curlNoise(warped * s, p_curlEps) / s; | |
| warped = warped + c * wAmp; | |
| wAmp *= 0.52; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 3 — FBM at warped position | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| float f = fbm(warped, p_octaves, p_persist, p_lacun); | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 4 — vorticity confinement overlay | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| vector cv = curlNoise(warped * p_lacun, p_curlEps * 0.45); | |
| float vrt = smoothstep(0.0, 1.6, length(cv)); | |
| f = mix(f, f + vrt * 0.30, p_vortBlend); | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 5 — large-eddy drift | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| float driftX = (float)noise("perlin", base*0.22 + vector(Time*0.035, 0.0, 0.0)); | |
| float driftY = (float)noise("perlin", base*0.22 + vector(0.0, Time*0.028, 0.0)); | |
| point drifted = warped + vector(driftX, driftY, 0.0) * 0.16; | |
| f += (float)noise("perlin", drifted * 0.45) * 0.10; | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| Stage 6 — remap, contrast, output | |
| ═══════════════════════════════════════════════════════════════════ */ | |
| float raw = clamp(f * 0.5 + 0.5, 0.0, 1.0); | |
| Fac = clamp((raw - 0.5) * p_contrast + 0.5 + p_bright, 0.0, 1.0); | |
| Color = ramp(Fac, ps0,pc0, ps1,pc1, ps2,pc2, ps3,pc3, ps4,pc4); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment