Implementation
The Dawn series of shaders are a tribute to some of the beautiful work of Rik Oostenbroek.
I've been a huge fan of his work for a long time, and was particularly inspired by some of his pieces that feature lovely, vertically-oriented gradients with a simple, repeating, linear pattern and a grainy texture.
A couple of examples that inspired this shader:
Breakdown
This shader builds on the geometric complexity of Dawn 4 but introduces new elements like contrast enhancement and different SDF masking techniques. It features layered noise, sphere-based masking, and a sophisticated color processing pipeline. There are 6 key components:
Gradient with Enhanced SDF Modulation
This gradient uses a sphere SDF with additional noise layering for more organic color variation:
// Get aspect-corrected UVs for the screen
const uv0 = screenAspectUV(screenSize).toVar()
// Palette arguments
const a = vec3(0.5, 0.5, 0.5)
const b = vec3(0.5, 0.5, 0.5)
const c = vec3(1.0, 1.0, 0.5)
const d = vec3(0.8, 0.9, 0.3)
// Offset UVs for noise
const offsetUv = vec2(_uv.x, _uv.y.add(repeatingPattern).add(sin(mul(s, 0.05))))
// Layered noise for organic variation
const n2 = simplexNoise3d(vec3(offsetUv.mul(3.0), time.mul(0.25))).mul(0.12)
// Gradient modulated by sphere SDF and noise
const col = cosinePalette(sdSphere(uv0).add(n2), a, b, c, d)Multi-Scale Noise System
This shader employs two different scales of simplex noise with varying time offsets for organic variation:
// Get aspect-corrected UVs for the screen
const _uv = screenAspectUV(screenSize).toVar()
// X-repeated pattern for banding
const repetitions = 12.0
const repeatingPattern = floor(_uv.x.mul(repetitions)).mul(repetitions).mul(0.005)
// Sine wave for vertical offset
const s = sin(uv0.x.mul(PI)).toVar()
// Offset UVs for noise
const offsetUv = vec2(_uv.x, _uv.y.add(repeatingPattern).add(sin(mul(s, 0.05))))
// Layered noise for organic variation
const n = simplexNoise3d(vec3(offsetUv, time.mul(0.1)))
const n2 = simplexNoise3d(vec3(offsetUv.mul(3.0), time.mul(0.25))).mul(0.12)Sphere-Based Masking
The masking system uses an absolute sphere SDF combined with noise for organic, flowing shapes:
// Get aspect-corrected UVs for the screen
const _uv = screenAspectUV(screenSize).toVar()
// X-repeated pattern for banding
const repetitions = 12.0
const repeatingPattern = floor(_uv.x.mul(repetitions)).mul(repetitions).mul(0.005)
// Sine wave for vertical offset
const s = sin(uv0.x.mul(PI)).toVar()
// Offset UVs for noise
const offsetUv = vec2(_uv.x, _uv.y.add(repeatingPattern).add(sin(mul(s, 0.05))))
// Layered noise for organic variation
const n = simplexNoise3d(vec3(offsetUv, time.mul(0.1)))
// Mask using noise and sphere SDF
const t = oneMinus(abs(sdSphere(offsetUv)).add(n))Horizontal Banding Pattern
This shader maintains the horizontal banding pattern using the floor function to create distinct bands:
// Get aspect-corrected UVs for the screen
const _uv = screenAspectUV(screenSize).toVar()
// X-repeated pattern for banding
const repetitions = 12.0
const repeatingPattern = floor(_uv.x.mul(repetitions)).mul(repetitions).mul(0.005)Sine Wave Modulation
A sine wave creates vertical offset variation that adds movement and organic flow:
// Get aspect-corrected UVs for the screen
const _uv = screenAspectUV(screenSize).toVar()
const uv0 = screenAspectUV(screenSize).toVar()
// X-repeated pattern for banding
const repetitions = 12.0
const repeatingPattern = floor(_uv.x.mul(repetitions)).mul(repetitions).mul(0.005)
// Sine wave for vertical offset
const s = sin(uv0.x.mul(PI)).toVar()
// Offset UVs for noise
const offsetUv = vec2(_uv.x, _uv.y.add(repeatingPattern).add(sin(mul(s, 0.05))))Contrast Enhancement
A hyperbolic tangent function enhances contrast and vibrancy in the final output:
// Soft contrast curve for vibrancy
finalColor.assign(tanh(finalColor.mul(2.5)))Texture
As with the other Dawn sketches, grain is added for texture:
// Get aspect-corrected UVs for the screen
const _uv = screenAspectUV(screenSize).toVar()
// Add grain for texture
const _grain = grainTexturePattern(_uv).mul(0.2)
finalColor.addAssign(_grain)


