【研发类-游戏开发Skills】shader-programming-glsl 技能

📅 2026/7/19 17:34:28 👁️ 阅读次数 📝 编程学习
【研发类-游戏开发Skills】shader-programming-glsl 技能

编写高效GLSL着色器(顶点/片段)的专家指南,适用于Web和游戏引擎,涵盖语法、uniforms和常见效果。

技能概述

下载地址:antigravity-awesome-skills/skills/shader-programming-glsl at main · sickn33/antigravity-awesome-skills · GitHub

shader-programming-glsl 技能是一个全面的GPU着色器编写指南,使用GLSL(OpenGL着色语言)。学习语法、uniforms、varying变量以及Swizzling和向量运算等关键数学概念,用于创建视觉效果。

主要功能

  • 顶点着色器开发:教授如何将3D坐标转换为2D屏幕空间(gl_Position)
  • 片段着色器开发:指导如何为单个像素着色(gl_FragColor)
  • Uniforms和Varyings:深入讲解uniform和varying变量的使用
  • Swizzling和向量运算:教授向量组件的自由访问和重排序
  • 视觉效果实现:提供常见视觉效果的实现方法
  • 性能优化:分享着色器性能优化的最佳实践

触发条件

在以下情况下应该调用此技能:

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

核心概念

1. 结构:顶点 vs 片段

理解渲染管线:

  • 顶点着色器:将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)
uniform vec3 color;

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

2. Uniforms和Varyings

  • uniform:对所有顶点/片段不变的数据(从CPU传递)
  • varying:从顶点着色器插值到片段着色器的数据

传递UV坐标

// 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和向量运算

自由访问向量组件:vec4 color = vec4(1.0, 0.5, 0.0, 1.0);

  • color.rgbvec3(1.0, 0.5, 0.0)
  • color.zyxvec3(0.0, 0.5, 1.0)(重排序)

使用示例

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

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);
}

最佳实践

  • 推荐:使用mix()进行线性插值,而不是手动计算
  • 推荐:使用step()smoothstep()进行阈值处理和软边缘(避免if分支)
  • 推荐:将数据打包到向量(vec4)中以最小化内存访问
  • 不推荐:在循环内使用重分支(if-else),这会损害GPU并行性
  • 不推荐:在着色器内计算常量值;在CPU上预先计算它们(uniforms)

故障排除

问题:着色器编译但屏幕是黑色的

解决方案:

  • 检查gl_Position.w是否正确(通常为1.0)
  • 检查uniforms是否实际从宿主应用程序设置
  • 验证UV坐标在[0, 1]范围内

限制说明

  • 仅在任务明确匹配上述范围时使用此技能
  • 不要将输出作为环境特定验证、测试或专家审查的替代品
  • 如果缺少所需的输入、权限、安全边界或成功标准,请停止并请求澄清