mcpField
S
shader-programming-glsl

shader-programming-glsl

github.com/sickn33开发48.7k192 次安装今天更新
代码仓库

关于 shader-programming-glsl

面向使用 GLSL 编写 GPU 着色器的开发者,介绍着色器结构、变量、向量运算和渲染实践。内容还包括 WebGL 场景、效果示例、性能建议及编译问题排查。

主要功能

  1. 01讲解顶点与片段着色器
  2. 02说明 uniform 与 varying
  3. 03介绍向量运算与分量重排
  4. 04提供光线步进示例
  5. 05涵盖编译排查与性能建议

适用场景

  1. 01为 WebGL 或游戏引擎制作视觉效果
  2. 02实现模糊、泛光或色彩校正
  3. 03在 GPU 上生成纹理或几何体
  4. 04排查着色器编译或黑屏问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill shader-programming-glsl

安装后在 Claude Code 中输入/shader-programming-glsl确认已加载。

详细介绍

Shader 编程 GLSL

概述

这是一份使用 GLSL(OpenGL 着色语言)编写 GPU 着色器的综合指南。了解语法、uniform、varying 变量,以及混合向量分量和向量运算等关键数学概念,从而实现视觉效果。

何时使用此技能

  • 用于在 WebGL、Three.js 或游戏引擎中创建自定义视觉效果。
  • 用于优化图形渲染性能。
  • 用于实现后期处理效果(模糊、泛光、颜色校正)。
  • 用于在 GPU 上以程序化方式生成纹理或几何体。

分步指南

1. 结构:顶点着色器与片元着色器

以下基本语法面向 GLSL ES 1.00/WebGL 1。宿主引擎可能会注入矩阵/属性;原生 WebGL 必须显式绑定它们。GLSL ES 3.00 使用 in/out 和声明的片元输出,而不是 attribute/varying/gl_FragColor。分别编译顶点着色器和片元着色器,将它们链接为一个程序,并检查编译/链接日志。

了解渲染管线:

  • 顶点着色器:将 3D 坐标转换为 2D 屏幕空间坐标(gl_Position)。
  • 片元着色器:为单个像素着色(gl_FragColor)。
// Vertex Shader (basic)
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

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

void main() {
    gl_FragColor = vec4(color, 1.0);
}
2. Uniform 和 Varying
  • uniform:所有顶点/片元共享的常量数据(由 CPU 传入)。
  • varying:从顶点着色器插值传递到片元着色器的数据。
// Separate vertex and fragment shader snippets; both declare varying vec2 vUv.
// Vertex shader also needs attribute vec2 uv and the matrices/position above.
// Raw WebGL fragment shader needs a float precision declaration.
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. 分量混合与向量运算

可自由访问向量分量: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)(重新排序)

示例

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

这是 Shadertoy 风格的片元入口点,使用宿主提供的 iResolution;在原生 WebGL 中需要宿主包装器。

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;
    bool hit = false;
    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) { hit = true; break; }
        t += d;
        if(t > 10.0) break;
    }
    
    vec3 col = vec3(0.0);
    if(hit) {
        vec3 p = ro + rd * t;
        vec3 normal = normalize(p);
        col = normal * 0.5 + 0.5; // Color by normal
    }
    
    fragColor = vec4(col, 1.0);
}

最佳实践

  • ✅ 应做: 使用 mix() 进行线性插值,而不是手动计算。
  • ✅ 应做: 使用 step() 和 smoothstep() 进行阈值判断和柔和边缘处理(避免 if 分支)。
  • ✅ 应做: 将数据打包到向量(vec4)中,以尽量减少内存访问。
  • ❌ 不应做: 尽可能避免在循环中使用繁重的分支(if-else);这会损害 GPU 并行性。
  • ❌ 不应做: 在着色器中计算常量;应在 CPU 上预先计算(作为 uniform)。

故障排除

问题: 着色器编译成功,但屏幕是黑色的。
解决方案: 检查完整的裁剪空间变换和齐次坐标 gl_Position.w;透视投影通常不会产生 w = 1。检查宿主应用是否确实设置了 uniform。确认 UV 坐标位于 [0, 1] 范围内。

关于 GLSL ES 片元精度的可移植性,请参阅 Khronos 指南。请在目标 GPU 上分析分支/向量优化的性能;这些风格建议并不保证能提升速度。

局限性

  • 仅当任务明确符合上述范围时才使用此技能。
  • 不要将输出视为对特定环境验证、测试或专家审查的替代。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请暂停并请求澄清。

评论

支持 Markdown