20

Whenever I asked for a fragment shader with fractal brownian motion I got a hash based on sin(dot(p, vec2(12.9898,78.233))) * 43758.5453. It looks fine at small scale then produces visible diagonal banding once you zoom, because that classic hash has directional artifacts.

What fixed it was banning that specific one-liner in the prompt and asking for an integer-based hash plus a named interpolation. I also made it expose octaves/lacunarity/gain as uniforms so I could tune the look live instead of editing constants.

Curious whether people prefer value noise or gradient noise as the fbm base for cloud-like fields.

THE PROMPT
Write a GLSL 3.0 fragment shader (for a three.js ShaderMaterial on a fullscreen quad) that renders animated fbm noise. Requirements:
- BANNED: the `sin(dot(p, vec2(12.9898,78.233)))*43758.5453` hash. Use an integer bit-mix hash (e.g. based on `uint` xor/shift) to avoid directional banding.
- fbm with uniforms: `uOctaves` (int, default 5), `uLacunarity` (float, 2.0), `uGain` (float, 0.5), `uScale` (float), and `uTime`.
- Use smootherstep (6t^5-15t^4+10t^3), not linear or basic smoothstep, for the interpolation.
- Domain-warp the field once: sample fbm of the fbm coordinate for a marbled look, gated by a `uWarp` uniform so I can turn it off.
- Output grayscale in linear space, then apply a simple ACES-ish tonemap before gl_FragColor.
- Comment each uniform with its perceptual effect in one line.
Explain in two sentences why the integer hash removes the banding I get from the trig hash.
4banning the exact trig hash string in the prompt is such an underrated move. the model reaches for it on reflex otherwise.onepromptwonder 2 months ago
add a comment

1 Answer

15

This is the correct instinct. One thing: uOctaves as a uniform int will make some drivers refuse to unroll the loop. If you see it tank on mobile, template the octave count as a #define constant and recompile the material when it changes. Keeps the loop unrolled and fast.

THE PROMPT
Swap the uniform loop for `#define OCTAVES 5` and recompile via `material.needsUpdate = true` when the user changes it, instead of a dynamic-length for loop.

Your Answer