shader-programming-glsl

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Shader Programming GLSL

GLSL着色器编程

Overview

概述

A comprehensive guide to writing GPU shaders using GLSL (OpenGL Shading Language). Learn syntax, uniforms, varying variables, and key mathematical concepts like swizzling and vector operations for visual effects.
这是一份使用GLSL(OpenGL着色语言)编写GPU着色器的全面指南。您将学习语法、uniforms、varying变量,以及用于视觉效果的关键数学概念,如分量重组(swizzling)和向量运算。

When to Use This Skill

适用场景

  • Use when creating custom visual effects in WebGL, Three.js, or game engines.
  • Use when optimizing graphics rendering performance.
  • Use when implementing post-processing effects (blur, bloom, color correction).
  • Use when procedurally generating textures or geometry on the GPU.
  • 在WebGL、Three.js或游戏引擎中创建自定义视觉效果时使用。
  • 优化图形渲染性能时使用。
  • 实现后期处理效果(模糊、bloom、色彩校正)时使用。
  • 在GPU上程序化生成纹理或几何体时使用。

Step-by-Step Guide

分步指南

1. Structure: Vertex vs. Fragment

1. 结构:Vertex Shader vs Fragment Shader

Understand the pipeline:
  • Vertex Shader: Transforms 3D coordinates to 2D screen space (
    gl_Position
    ).
  • Fragment Shader: Colors individual pixels (
    gl_FragColor
    ).
glsl
// Vertex Shader (basic)
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
glsl
// Fragment Shader (basic)
uniform vec3 color;

void main() {
    gl_FragColor = vec4(color, 1.0);
}
理解渲染管线:
  • Vertex Shader(顶点着色器):将3D坐标转换为2D屏幕空间(
    gl_Position
    )。
  • Fragment Shader(片段着色器):为单个像素上色(
    gl_FragColor
    )。
glsl
// Vertex Shader (basic)
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
glsl
// Fragment Shader (basic)
uniform vec3 color;

void main() {
    gl_FragColor = vec4(color, 1.0);
}

2. Uniforms and Varyings

2. Uniforms与Varying变量

  • uniform
    : Data constant for all vertices/fragments (passed from CPU).
  • varying
    : Data interpolated from vertex to fragment shader.
glsl
// Passing UV coordinates
varying vec2 vUv;

// In Vertex Shader
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

// In Fragment Shader
void main() {
    // Gradient based on UV
    gl_FragColor = vec4(vUv.x, vUv.y, 1.0, 1.0);
}
  • uniform
    :所有顶点/片段共享的常量数据(从CPU传入)。
  • varying
    :从顶点着色器插值传递到片段着色器的数据。
glsl
// Passing UV coordinates
varying vec2 vUv;

// In Vertex Shader
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

// In Fragment Shader
void main() {
    // Gradient based on UV
    gl_FragColor = vec4(vUv.x, vUv.y, 1.0, 1.0);
}

3. Swizzling & Vector Math

3. 分量重组(Swizzling)与向量运算

Access vector components freely:
vec4 color = vec4(1.0, 0.5, 0.0, 1.0);
  • color.rgb
    ->
    vec3(1.0, 0.5, 0.0)
  • color.zyx
    ->
    vec3(0.0, 0.5, 1.0)
    (reordering)
可自由访问向量分量:
vec4 color = vec4(1.0, 0.5, 0.0, 1.0);
  • color.rgb
    ->
    vec3(1.0, 0.5, 0.0)
  • color.zyx
    ->
    vec3(0.0, 0.5, 1.0)
    (重新排序)

Examples

示例

Example 1: Simple Raymarching (SDF Sphere)

示例1:简单光线步进(SDF球体)

glsl
float sdSphere(vec3 p, float s) {
    return length(p) - s;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    vec3 ro = vec3(0.0, 0.0, -3.0); // Ray Origin
    vec3 rd = normalize(vec3(uv, 1.0)); // Ray Direction
    
    float t = 0.0;
    for(int i = 0; i < 64; i++) {
        vec3 p = ro + rd * t;
        float d = sdSphere(p, 1.0); // Sphere radius 1.0
        if(d < 0.001) break;
        t += d;
    }
    
    vec3 col = vec3(0.0);
    if(t < 10.0) {
        vec3 p = ro + rd * t;
        vec3 normal = normalize(p);
        col = normal * 0.5 + 0.5; // Color by normal
    }
    
    fragColor = vec4(col, 1.0);
}
glsl
float sdSphere(vec3 p, float s) {
    return length(p) - s;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    vec3 ro = vec3(0.0, 0.0, -3.0); // Ray Origin
    vec3 rd = normalize(vec3(uv, 1.0)); // Ray Direction
    
    float t = 0.0;
    for(int i = 0; i < 64; i++) {
        vec3 p = ro + rd * t;
        float d = sdSphere(p, 1.0); // Sphere radius 1.0
        if(d < 0.001) break;
        t += d;
    }
    
    vec3 col = vec3(0.0);
    if(t < 10.0) {
        vec3 p = ro + rd * t;
        vec3 normal = normalize(p);
        col = normal * 0.5 + 0.5; // Color by normal
    }
    
    fragColor = vec4(col, 1.0);
}

Best Practices

最佳实践

  • Do: Use
    mix()
    for linear interpolation instead of manual math.
  • Do: Use
    step()
    and
    smoothstep()
    for thresholding and soft edges (avoid
    if
    branches).
  • Do: Pack data into vectors (
    vec4
    ) to minimize memory access.
  • Don't: Use heavy branching (
    if-else
    ) inside loops if possible; it hurts GPU parallelism.
  • Don't: Calculate constant values inside the shader; pre-calculate them on the CPU (uniforms).
  • 建议:使用
    mix()
    进行线性插值,而非手动计算。
  • 建议:使用
    step()
    smoothstep()
    实现阈值处理和柔化边缘(避免
    if
    分支)。
  • 建议:将数据打包到向量(
    vec4
    )中,以减少内存访问。
  • 避免:尽可能不要在循环内使用大量分支(
    if-else
    ),这会影响GPU并行性。
  • 避免:不要在着色器内计算常量值;在CPU上预先计算(作为uniforms传入)。

Troubleshooting

故障排除

Problem: Shader compiles but screen is black. Solution: Check if
gl_Position.w
is correct (usually 1.0). Check if uniforms are actually being set from the host application. Verify UV coordinates are within [0, 1].
问题:着色器编译成功但屏幕显示黑色。 解决方案:检查
gl_Position.w
是否正确(通常为1.0)。检查宿主应用是否正确设置了uniforms。验证UV坐标是否在[0, 1]范围内。

Limitations

局限性

  • Use this skill only when the task clearly matches the scope described above.
  • Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
  • Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
  • 仅当任务与上述描述的范围完全匹配时使用本技能。
  • 不要将输出结果视为特定环境下验证、测试或专家评审的替代品。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请暂停并要求澄清。