【研发类-游戏开发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.rgb→vec3(1.0, 0.5, 0.0)color.zyx→vec3(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 Directionfloat 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]范围内
限制说明
- 仅在任务明确匹配上述范围时使用此技能
- 不要将输出作为环境特定验证、测试或专家审查的替代品
- 如果缺少所需的输入、权限、安全边界或成功标准,请停止并请求澄清