一、GLSL 内置变量(Built-in Variables)
GLSL 提供以 gl_ 前缀的预定义内置变量,作为 Shader 中数据交互的额外方式。
1.1 顶点着色器内置变量
| 变量 | 类型 | 作用 |
|---|---|---|
gl_Position |
vec4 |
输出裁剪空间顶点位置(必设) |
gl_PointSize |
float |
设置点的大小(像素),用于 GL_POINTS 图元 |
gl_VertexID |
int |
当前顶点 ID(只读) |
关键代码示例:
glsl
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
gl_PointSize = gl_Position.z; // 距离越远,点越大
}
使用前需启用:glEnable(GL_PROGRAM_POINT_SIZE);
1.2 片元着色器内置变量
| 变量 | 类型 | 作用 |
|---|---|---|
gl_FragCoord |
vec3 |
片元窗口坐标 (x, y) + 深度值 (z) |
gl_FrontFacing |
bool |
判断片元是否面向观察者 |
gl_FragDepth |
float |
输出变量,可手动修改深度值 |
gl_PointCoord |
vec2 |
点图元的局部坐标 |
gl_FragCoord 示例:
glsl
void main()
{
if(gl_FragCoord.x < 400)
FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色 - 左侧
else
FragColor = vec4(0.0, 1.0, 0.0, 1.0); // 绿色 - 右侧
}
gl_FrontFacing 应用:内外纹理切换
glsl
void main()
{
if(gl_FrontFacing)
FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 正面用红色
else
FragColor = vec4(0.0, 1.0, 0.0, 1.0); // 背面用绿色
}
二、接口块(Interface Blocks)
用于组织着色器间的输入输出数据,使代码更清晰。
2.1 基本语法
glsl
#version 330 core
// 输出到下一个着色器
out VS_OUT
{
vec3 textCoord;
} vs_out;
// 输入来自上一个着色器
in VS_OUT
{
vec3 textCoord;
} fs_in;
void main()
{
vs_out.textCoord = aTexCoord;
// ...
}
2.2 与 Uniform 对比
- 普通 Uniform :
in float someValue; - 接口块 :
in BlockName { type varName; } instanceName;
接口块更易管理大量相关数据,适合传递变换矩阵、材质属性等结构化数据。
三、统一缓冲区对象(UBO - Uniform Buffer Objects)
3.1 为什么需要 UBO?
传统方式每个 shader 都要单独绑定 Uniform,UBO 允许:
- 一次绑定,多个 Shader 共享
- 高效更新:减少 CPU-GPU 数据传输
- 符合标准布局:便于多项目复用
3.2 定义与使用
1. C++ 端定义 Uniform 块:
cpp
// 定义 Uniform 块结构
#version 330 core
layout(std140) uniform MatrixBlock
{
mat4 projection;
mat4 view;
mat4 model;
};
2. GLSL 访问:
glsl
uniform MatrixBlock matrices;
void main()
{
gl_Position = matrices.projection * matrices.view * matrices.model * vec4(aPos, 1.0);
}
3. C++ 端创建与绑定:
cpp
unsigned int uboExample;
glGenBuffers(1, &uboExample);
glBindBuffer(GL_UNIFORM_BUFFER, uboExample);
glBufferData(GL_UNIFORM_BUFFER, sizeof(matrices), &matrices, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboExample); // 绑定到索引 0
3.3 布局限定符
| 限定符 | 说明 |
|---|---|
shared |
不同程序共享,需手动设置 offset |
packed |
运行时优化,需查询 offset |
std140 |
最常用,显式定义内存布局 |
std430 |
更紧凑的布局(不常用) |
四、实用技巧
4.1 gl_PointCoord 制作点精灵
glsl
void main()
{
vec2 uv = gl_PointCoord; // 0.0 ~ 1.0
if(length(uv - vec2(0.5)) > 0.5)
discard; // 裁剪圆形外的像素
FragColor = texture(spriteTexture, uv);
}
4.2 gl_FragDepth 性能注意
使用 gl_FragDepth 会禁用 Early-Z 测试,可能影响渲染性能,仅在必要时使用。
五、要点总结
| 类别 | 要点 |
|---|---|
| 内置变量 | 顶点用 gl_Position/PoinSize/VertexID,片元用 gl_FragCoord/FrontFacing/FragDepth |
| 接口块 | 用 in/out BlockName {} instance 组织输入输出 |
| UBO | glBindBufferBase + layout(std140) 实现高效 Uniform 管理 |