Skip to main content

forge-shader-noise

Add GPU noise functions (hash, value, Perlin, fBm, domain warping) to an SDL GPU project

Aller à l'installation

Informations de source

Dépôt
Nebulavenus/forge-gpu
Dernière activité de la source
1 mars 2026 à 21:31
Langue détectée de SKILL.md
anglais
Étoiles
38
Forks
7

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
forge-shader-noise
description
Add GPU noise functions (hash, value, Perlin, fBm, domain warping) to an SDL GPU project
user_invokable
true
# Shader Noise Add procedural noise functions to an SDL GPU fragment shader. Implements GPU-friendly hash functions, value noise, Perlin gradient noise, fBm (fractal Brownian motion), and domain warping — all running per-pixel on the GPU with no texture assets. ## When to use - Procedural textures (marble, wood, clouds, terrain) - Terrain height and coloring without texture assets - Dissolve and erosion effects - Adding organic variation to materials or lighting - Any situation requiring randomness in a fragment shader ## HLSL noise library Add these functions to your fragment shader. They are self-contained and require no external textures or buffers. ### Hash functions GPU shaders lack `rand()`. Use deterministic integer hashes instead — same input always produces the same output. ```hlsl /* Thomas Wang 32-bit integer hash — good avalanche properties */ uint wang_hash(uint seed) { seed = (seed ^ 61u) ^ (seed >> 16u); seed *= 9u; seed = seed ^ (seed >> 4u); seed *= 0x27d4eb2du; seed = seed ^ (seed >> 15u); return seed; } /* Map hash to float in [0, 1) */ float hash_to_float(uint h) { return float(h) / 4294967296.0; } /* Combine two hash values (Boost hash_combine pattern) */ uint hash_combine(uint seed, uint value) { return seed ^ (value + 0x9e3779b9u + (seed << 6u) + (seed >> 2u)); } /* Hash 2D integer coordinates to uint */ uint hash2d_uint(int2 p) { uint h = wang_hash(uint(p.x)); h = hash_combine(h, uint(p.y)); return wang_hash(h); } /* Hash 2D integer coordinates to float in [0, 1) */ float hash2d(int2 p) { return hash_to_float(hash2d_uint(p)); } ``` ### White noise Random value per integer cell. Useful for TV static, sparkle effects. ```hlsl float white_noise(float2 p, float time_seed) { int2 ip = int2(floor(p)); uint seed = hash_combine(hash2d_uint(ip), uint(time_seed * 60.0)); return hash_to_float(seed); } ``` ### Value noise Smoothly interpolated random values at lattice points. ```hlsl float value_noise(float2 p) { int2 i = int2(floor(p)); float2 f = frac(p); float2 u = f * f * (3.0 - 2.0 * f); /* Hermite smoothstep */ float a = hash2d(i); float b = hash2d(i + int2(1, 0)); float c = hash2d(i + int2(0, 1)); float d = hash2d(i + int2(1, 1)); return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y); } ``` ### Gradient noise (Perlin 2D) Smoother than value noise with C2 continuity. ```hlsl float grad2d(uint hash, float2 d) { uint h = hash & 3u; float u = ((h & 1u) != 0u) ? -d.x : d.x; float v = ((h & 2u) != 0u) ? -d.y : d.y; return u + v; } float2 quintic(float2 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); } float perlin2d(float2 p) { int2 i = int2(floor(p)); float2 f = frac(p); float2 u = quintic(f); float a = grad2d(hash2d_uint(i), f); float b = grad2d(hash2d_uint(i + int2(1, 0)), f - float2(1.0, 0.0)); float c = grad2d(hash2d_uint(i + int2(0, 1)), f - float2(0.0, 1.0)); float d = grad2d(hash2d_uint(i + int2(1, 1)), f - float2(1.0, 1.0)); return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y); } ``` ### fBm (fractal Brownian motion) Stack multiple octaves of Perlin noise for natural fractal detail. ```hlsl float fbm(float2 p) { float value = 0.0; float amplitude = 0.5; float frequency = 1.0; for (int oct = 0; oct < 6; oct++) { value += amplitude * perlin2d(p * frequency); frequency *= 2.0; /* lacunarity */ amplitude *= 0.5; /* persistence */ } return value; } ``` ### Domain warping Compose fBm with itself for organic, marble-like patterns. ```hlsl float domain_warp(float2 p) { float2 q = float2( fbm(p + float2(0.0, 0.0)), fbm(p + float2(5.2, 1.3)) ); float2 r = float2( fbm(p + 4.0 * q + float2(1.7, 9.2)), fbm(p + 4.0 * q + float2(8.3, 2.8)) ); return fbm(p + 4.0 * r); } ``` ### Dithering (Interleaved Gradient Noise) Break up 8-bit color banding with blue-noise-like dithering. ```hlsl float ign(float2 screen_pos) { float3 ign_coeffs = float3(0.06711056, 0.00583715, 52.9829189); return frac(ign_coeffs.z * frac(dot(screen_pos, ign_coeffs.xy))); } /* Apply after computing final color: */ color += (ign(screen_pos) - 0.5) / 255.0; ``` ## Integration pattern ### Using noise in an existing scene shader Add the noise functions to your fragment shader and use them to modify materials, lighting, or geometry: ```hlsl /* Procedural terrain coloring */ float height = fbm(world_pos.xz * 0.1); float3 base_color = terrain_color(height); /* Add organic variation to a material */ float variation = perlin2d(world_pos.xz * 2.0 + time * 0.1); diffuse_color *= 0.9 + 0.1 * variation; /* Dissolve effect */ float noise = fbm(world_pos * 3.0); clip(noise - dissolve_threshold); /* discard if below threshold */ ``` ### Fullscreen noise visualization For standalone noise visualization, use the SV_VertexID fullscreen quad pattern from [Lesson 21 — HDR & Tone Mapping](../../../lessons/gpu/21-hdr-tone-mapping/) (no vertex buffer, pipeline with no vertex input state). Fragment uniforms (register b0, space3 for SDL GPU): ```hlsl cbuffer NoiseParams : register(b0, space3) { float time; int mode; int dither_enabled; float scale; float2 resolution; float2 _pad; }; ``` ## C-side uniform struct ```c typedef struct NoiseUniforms { float time; int mode; int dither_enabled; float scale; vec2 resolution; float _pad[2]; } NoiseUniforms; ``` ## Common patterns ### Aspect-correct noise coordinates ```hlsl float aspect = resolution.x / resolution.y; float2 p = uv * scale; p.x *= aspect; /* prevent stretching */ ``` ### Remapping noise range Perlin/fBm output is approximately [-1, 1]. Remap to [0, 1] for display or color mapping: ```hlsl float n = fbm(p); n = n * 0.5 + 0.5; /* remap to [0, 1] */ ``` ### Terrain color mapping Map noise height to biome colors with smooth transitions: ```hlsl float3 color = deep_water; color = lerp(color, grass, smoothstep(0.38, 0.50, height)); color = lerp(color, rock, smoothstep(0.62, 0.75, height)); color = lerp(color, snow, smoothstep(0.75, 0.85, height)); ``` ## Common mistakes - **Forgetting aspect ratio correction** — multiply `uv.x *= aspect` before sampling noise, otherwise noise cells appear stretched on non-square windows - **Not remapping Perlin/fBm output** — `perlin2d()` returns approximately [-1, 1]; use `n * 0.5 + 0.5` to remap to [0, 1] for display or color mapping - **cbuffer alignment** — the uniform struct must be padded to a multiple of 16 bytes; misaligned fields silently read wrong values on some backends - **Using `int` casts on negative coordinates** — `int2(floor(p))` is correct; `int2(p)` truncates toward zero, causing a seam at the origin where two adjacent cells map to the same integer - **Animating white noise with `frac(time)`** — produces periodic patterns; use `hash_combine` with an integer time seed instead for true per-frame randomness ## Reference - [Lesson 25 — Shader Noise](../../../lessons/gpu/25-shader-noise/) - [Math Lesson 12 — Hash Functions](../../../lessons/math/12-hash-functions/) - [Math Lesson 13 — Gradient Noise](../../../lessons/math/13-gradient-noise/) - [Math Lesson 14 — Blue Noise](../../../lessons/math/14-blue-noise-sequences/)
Voir sur GitHub