Initial commit: add all skills files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 16:52:49 +08:00
commit 6487becf60
396 changed files with 108871 additions and 0 deletions

View File

@@ -0,0 +1,382 @@
**IMPORTANT - GLSL Type Strictness**:
- GLSL is a strongly-typed language and does not support the `string` type (you cannot define `string var`)
- `vec2`/`vec3`/`vec4` are vector types and cannot be directly assigned a float (e.g., `vec2 a = 1.0` must be `vec2 a = vec2(1.0)`)
- Array indices must be integer constants or uniform variables; runtime-computed floats cannot be used
- Avoid uninitialized variables — GLSL default values are undefined
# Texture Sampling
## Use Cases
- **Post-processing effects**: Blur, bloom, dispersion, chromatic aberration
- **Procedural noise**: FBM layering from noise textures to generate terrain, clouds, fire
- **PBR/IBL**: Cubemap environment lighting, BRDF LUT lookup
- **Simulation/feedback systems**: Reaction-diffusion, fluid simulation multi-buffer feedback
- **Data storage**: Textures used as structured data (game state, keyboard input)
- **Temporal accumulation**: TAA, motion blur, previous frame reading
## Core Principles
| Function | Coordinate Type | Filtering | Typical Use |
|----------|----------------|-----------|-------------|
| `texture(sampler, uv)` | Float UV `[0,1]` | Hardware bilinear | General texture reading |
| `textureLod(sampler, uv, lod)` | Float UV + LOD | Specified mip level | Control blur level / avoid auto mip |
| `texelFetch(sampler, ivec2, lod)` | Integer pixel coordinates | No filtering | Exact pixel data reading |
Key mathematics:
1. **Hardware bilinear interpolation**: `texture()` automatically linearly blends between 4 adjacent texels
2. **Quintic Hermite smoothing**: `u = f^3(6f^2 - 15f + 10)`, C2 continuous (eliminates hardware linear interpolation seams)
3. **LOD control**: `textureLod` third parameter selects mipmap level, `lod=0` is original resolution, each +1 halves resolution
4. **Coordinate wrapping**: `fract(uv)` implements torus boundary, equivalent to `GL_REPEAT`
## Implementation Steps
### Step 1: Basic Sampling and UV Normalization
```glsl
vec2 uv = fragCoord / iResolution.xy;
vec4 col = texture(iChannel0, uv);
```
### Step 2: textureLod for Mipmap Control
```glsl
// In ray marching: force LOD 0 to avoid artifacts
vec3 groundCol = textureLod(iChannel2, groundUv * 0.05, 0.0).rgb;
// Depth of field blur: LOD varies with distance
float focus = mix(maxBlur - coverage, minBlur, smoothstep(.1, .2, coverage));
vec3 col = textureLod(iChannel0, uv + normal, focus).rgb;
// Bloom: sample high mip levels
#define BLOOM_LOD_A 4.0 // adjustable: bloom first mip level
#define BLOOM_LOD_B 5.0
#define BLOOM_LOD_C 6.0
vec3 bloom = vec3(0.0);
bloom += textureLod(iChannel0, uv + off * exp2(BLOOM_LOD_A), BLOOM_LOD_A).rgb;
bloom += textureLod(iChannel0, uv + off * exp2(BLOOM_LOD_B), BLOOM_LOD_B).rgb;
bloom += textureLod(iChannel0, uv + off * exp2(BLOOM_LOD_C), BLOOM_LOD_C).rgb;
bloom /= 3.0;
```
### Step 3: texelFetch for Exact Pixel Reading
```glsl
// Data storage addresses
const ivec2 txBallPosVel = ivec2(0, 0);
const ivec2 txPaddlePos = ivec2(1, 0);
const ivec2 txPoints = ivec2(2, 0);
const ivec2 txState = ivec2(3, 0);
vec4 loadValue(in ivec2 addr) {
return texelFetch(iChannel0, addr, 0);
}
void storeValue(in ivec2 addr, in vec4 val, inout vec4 fragColor, in ivec2 fragPos) {
fragColor = (fragPos == addr) ? val : fragColor;
}
// Keyboard input
float key = texelFetch(iChannel1, ivec2(KEY_SPACE, 0), 0).x;
```
### Step 4: Manual Bilinear + Quintic Hermite Smoothing
```glsl
float noise(vec2 x) {
vec2 p = floor(x);
vec2 f = fract(x);
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0); // C2 continuous
#define TEX_RES 1024.0 // adjustable: noise texture resolution
float a = texture(iChannel0, (p + vec2(0.0, 0.0)) / TEX_RES).x;
float b = texture(iChannel0, (p + vec2(1.0, 0.0)) / TEX_RES).x;
float c = texture(iChannel0, (p + vec2(0.0, 1.0)) / TEX_RES).x;
float d = texture(iChannel0, (p + vec2(1.0, 1.0)) / TEX_RES).x;
return a + (b - a) * u.x + (c - a) * u.y + (a - b - c + d) * u.x * u.y;
}
```
### Step 5: FBM Texture Noise
```glsl
#define FBM_OCTAVES 5 // adjustable: number of layers
#define FBM_PERSISTENCE 0.5 // adjustable: amplitude decay rate
float fbm(vec2 x) {
float v = 0.0;
float a = 0.5;
float totalWeight = 0.0;
for (int i = 0; i < FBM_OCTAVES; i++) {
v += a * noise(x);
totalWeight += a;
x *= 2.0;
a *= FBM_PERSISTENCE;
}
return v / totalWeight;
}
```
### Step 6: Separable Gaussian Blur
```glsl
#define BLUR_RADIUS 4 // adjustable: blur radius
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec2 d = vec2(1.0 / iResolution.x, 0.0); // horizontal pass; for vertical pass change to vec2(0, 1/iResolution.y)
float w[9] = float[9](0.05, 0.09, 0.12, 0.15, 0.16, 0.15, 0.12, 0.09, 0.05);
vec4 col = vec4(0.0);
for (int i = -4; i <= 4; i++) {
col += w[i + 4] * texture(iChannel0, fract(uv + float(i) * d));
}
col /= 0.98;
fragColor = col;
}
```
### Step 7: Dispersion Sampling
```glsl
#define DISP_SAMPLES 64 // adjustable: sample count
vec3 sampleWeights(float i) {
return vec3(i * i, 46.6666 * pow((1.0 - i) * i, 3.0), (1.0 - i) * (1.0 - i));
}
vec3 sampleDisp(sampler2D tex, vec2 uv, vec2 disp) {
vec3 col = vec3(0.0);
vec3 totalWeight = vec3(0.0);
for (int i = 0; i < DISP_SAMPLES; i++) {
float t = float(i) / float(DISP_SAMPLES);
vec3 w = sampleWeights(t);
col += w * texture(tex, fract(uv + disp * t)).rgb;
totalWeight += w;
}
return col / totalWeight;
}
```
### Step 8: IBL Environment Sampling
```glsl
#define MAX_LOD 7.0 // adjustable: cubemap max mip level
#define DIFFUSE_LOD 6.5 // adjustable: diffuse sampling LOD
vec3 getSpecularLightColor(vec3 N, float roughness) {
vec3 raw = textureLod(iChannel0, N, roughness * MAX_LOD).rgb;
return pow(raw, vec3(4.5)) * 6.5; // HDR approximation
}
vec3 getDiffuseLightColor(vec3 N) {
return textureLod(iChannel0, N, DIFFUSE_LOD).rgb;
}
// BRDF LUT lookup
vec2 brdf = texture(iChannel3, vec2(NdotV, roughness)).rg;
vec3 specular = envColor * (F * brdf.x + brdf.y);
```
## Complete Code Template
iChannel0 bound to a noise texture (e.g., "Gray Noise Medium"), with mipmap enabled.
```glsl
// === Texture Sampling Comprehensive Demo ===
// iChannel0: noise texture (requires mipmap enabled)
#define TEX_RES 256.0
#define FBM_OCTAVES 6
#define FBM_PERSISTENCE 0.5
#define CLOUD_LAYERS 4
#define CLOUD_SPEED 0.02
#define DOF_MAX_BLUR 5.0
#define DOF_FOCUS_DIST 0.5
#define BLOOM_STRENGTH 0.3
#define BLOOM_LOD 4.0
float noise(vec2 x) {
vec2 p = floor(x);
vec2 f = fract(x);
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
float a = textureLod(iChannel0, (p + vec2(0.0, 0.0)) / TEX_RES, 0.0).x;
float b = textureLod(iChannel0, (p + vec2(1.0, 0.0)) / TEX_RES, 0.0).x;
float c = textureLod(iChannel0, (p + vec2(0.0, 1.0)) / TEX_RES, 0.0).x;
float d = textureLod(iChannel0, (p + vec2(1.0, 1.0)) / TEX_RES, 0.0).x;
return a + (b - a) * u.x + (c - a) * u.y + (a - b - c + d) * u.x * u.y;
}
float fbm(vec2 x) {
float v = 0.0;
float a = 0.5;
float w = 0.0;
for (int i = 0; i < FBM_OCTAVES; i++) {
v += a * noise(x);
w += a;
x *= 2.0;
a *= FBM_PERSISTENCE;
}
return v / w;
}
float cloudLayer(vec2 uv, float height, float time) {
vec2 offset = vec2(time * CLOUD_SPEED * (1.0 + height), 0.0);
float n = fbm((uv + offset) * (2.0 + height * 3.0));
return smoothstep(0.4, 0.7, n);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
float aspect = iResolution.x / iResolution.y;
// 1. Procedural sky
vec3 sky = mix(vec3(0.1, 0.15, 0.4), vec3(0.5, 0.7, 1.0), uv.y);
// 2. FBM cloud layers
vec3 col = sky;
for (int i = 0; i < CLOUD_LAYERS; i++) {
float h = float(i) / float(CLOUD_LAYERS);
float density = cloudLayer(vec2(uv.x * aspect, uv.y), h, iTime);
vec3 cloudCol = mix(vec3(0.8, 0.85, 0.9), vec3(1.0), h);
col = mix(col, cloudCol, density * (0.3 + 0.7 * h));
}
// 3. textureLod depth of field blur
float dist = abs(uv.y - DOF_FOCUS_DIST);
float lod = dist * DOF_MAX_BLUR;
vec3 blurred = textureLod(iChannel0, uv, lod).rgb;
col = mix(col, blurred * 0.5 + col * 0.5, 0.3);
// 4. Bloom
vec3 bloom = textureLod(iChannel0, uv, BLOOM_LOD).rgb;
bloom += textureLod(iChannel0, uv, BLOOM_LOD + 1.0).rgb;
bloom += textureLod(iChannel0, uv, BLOOM_LOD + 2.0).rgb;
bloom /= 3.0;
col += bloom * BLOOM_STRENGTH;
// 5. Post-processing
col = (col * (6.2 * col + 0.5)) / (col * (6.2 * col + 1.7) + 0.06);
col *= 0.5 + 0.5 * pow(16.0 * uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y), 0.2);
fragColor = vec4(col, 1.0);
}
```
## Common Variants
### Variant 1: Anisotropic Flow-Field Blur
```glsl
#define BLUR_ITERATIONS 32 // adjustable: number of samples along flow field
#define BLUR_STEP 0.008 // adjustable: UV offset per step
vec3 flowBlur(vec2 uv) {
vec3 col = vec3(0.0);
float acc = 0.0;
for (int i = 0; i < BLUR_ITERATIONS; i++) {
float h = float(i) / float(BLUR_ITERATIONS);
float w = 4.0 * h * (1.0 - h);
col += w * texture(iChannel0, uv).rgb;
acc += w;
vec2 dir = texture(iChannel1, uv).xy * 2.0 - 1.0;
uv += BLUR_STEP * dir;
}
return col / acc;
}
```
### Variant 2: Buffer-as-Data Storage
```glsl
const ivec2 txPosition = ivec2(0, 0);
const ivec2 txVelocity = ivec2(1, 0);
const ivec2 txState = ivec2(2, 0);
vec4 load(ivec2 addr) { return texelFetch(iChannel0, addr, 0); }
void store(ivec2 addr, vec4 val, inout vec4 fragColor, ivec2 fragPos) {
fragColor = (fragPos == addr) ? val : fragColor;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
ivec2 p = ivec2(fragCoord);
fragColor = texelFetch(iChannel0, p, 0);
vec4 pos = load(txPosition);
vec4 vel = load(txVelocity);
// ... update logic ...
store(txPosition, pos + vel * 0.016, fragColor, p);
store(txVelocity, vel, fragColor, p);
}
```
### Variant 3: Dispersion Effect
```glsl
#define DISP_SAMPLES 64 // adjustable: sample count
#define DISP_STRENGTH 0.05 // adjustable: dispersion strength
vec3 dispersion(vec2 uv, vec2 displacement) {
vec3 col = vec3(0.0);
vec3 w_total = vec3(0.0);
for (int i = 0; i < DISP_SAMPLES; i++) {
float t = float(i) / float(DISP_SAMPLES);
vec3 w = vec3(t * t, 46.666 * pow((1.0 - t) * t, 3.0), (1.0 - t) * (1.0 - t));
col += w * texture(iChannel0, fract(uv + displacement * t * DISP_STRENGTH)).rgb;
w_total += w;
}
return col / w_total;
}
```
### Variant 4: Triplanar Texture Mapping
```glsl
#define TRIPLANAR_SHARPNESS 2.0 // adjustable: blend sharpness
vec3 triplanarSample(sampler2D tex, vec3 pos, vec3 normal, float scale) {
vec3 w = pow(abs(normal), vec3(TRIPLANAR_SHARPNESS));
w /= (w.x + w.y + w.z);
vec3 xSample = texture(tex, pos.yz * scale).rgb;
vec3 ySample = texture(tex, pos.xz * scale).rgb;
vec3 zSample = texture(tex, pos.xy * scale).rgb;
return xSample * w.x + ySample * w.y + zSample * w.z;
}
```
### Variant 5: Temporal Reprojection (TAA)
```glsl
#define TAA_BLEND 0.9 // adjustable: history frame blend ratio
vec3 temporalBlend(vec2 currUv, vec2 prevUv, vec3 currColor) {
vec3 history = textureLod(iChannel0, prevUv, 0.0).rgb;
vec3 minCol = currColor - 0.1;
vec3 maxCol = currColor + 0.1;
history = clamp(history, minCol, maxCol);
return mix(currColor, history, TAA_BLEND);
}
```
## Performance & Composition
**Performance Tips**:
- Heavy sampling (e.g., 64 dispersion samples) is a bandwidth bottleneck — reduce sample count + use smart weight compensation; use `textureLod` with high LOD to reduce cache misses
- 2D Gaussian blur uses separable two-pass (O(N^2) -> O(2N)), leveraging hardware bilinear for (N+1)/2 samples to achieve N-tap
- Must use `textureLod(..., 0.0)` inside ray marching — the GPU cannot correctly estimate screen-space derivatives
- Manual Hermite interpolation is ~4x slower than hardware — only use for the first two FBM octaves, fall back to `texture()` for higher frequencies
- Each multi-buffer feedback adds one frame of latency — merge operations into the same pass; use `texelFetch` to avoid filtering overhead
**Composition Tips**:
- **+ SDF Ray Marching**: Noise textures for displacement maps/materials; use `textureLod(..., 0.0)` inside ray marching
- **+ Procedural Noise**: Hermite + FBM driving domain warping to generate terrain/clouds/fire; texture noise is faster than pure mathematical noise
- **+ Post-Processing Pipeline**: Multi-LOD bloom → separable DOF → dispersion → tone mapping, chaining a complete post-processing pipeline
- **+ PBR/IBL**: `textureLod` samples cubemap by roughness + BRDF LUT lookup = split-sum IBL
- **+ Simulation/Feedback**: Multi-buffer reaction-diffusion/fluid; Buffer A state, B/C separable blur diffusion, Image visualization; `fract()` torus boundary
## Further Reading
For complete step-by-step tutorials, mathematical derivations, and advanced usage, see [reference](../reference/texture-sampling.md)