着色器管线
flowchart LR c1["CPU"] --> s1["顶点着色器"] subgraph x["细分着色器"] s2["细分控制着色器"] --> s3["细分验证着色器"] end s1 --> s2 s3 --> s4["几何着色器"] --> s5["片段着色器"] --> c2["帧缓冲区"]
顶点着色器 Vertex Shader
顶点着色器是 OpenGL 着色器管线的第一个阶段,负责处理每个输入顶点的数据。
#version 460 core
/* ① 输入数据 */
layout (location = 0) in vec3 aPos; // 顶点位置
layout (location = 1) in vec3 aNormal; // 顶点法线
layout (location = 2) in vec2 aTexCoord; // 纹理坐标
/* ② 输出数据 */
layout (location = 0) out vec2 TexCoord;
layout (location = 1) out vec3 FragPos;
layout (location = 2) out vec3 Normal;
/* ③ Uniform */
layout (location = 0) uniform mat4 Transform;
void main() {
/* ④ gl_Position */
gl_Position = Transform * vec4(Position, 1.0);
/* ② 输出数据 */
TexCoord = aTexCoord; // 传递纹理坐标
FragPos = vec3(model * vec4(aPos, 1.0)); // 计算顶点的世界坐标并传递
Normal = mat3(transpose(inverse(model))) * aNormal; // 计算法线变换并传递
}片段着色器 Fragment Shader
片段着色器是 OpenGL 着色器管线的最后一个阶段,负责计算每个片段(像素)的最终颜色。
#version 460 core
/* ① 输入数据 */
layout (location = 0) in vec2 TexCoord;
layout (location = 1) in vec3 FragPos;
layout (location = 2) in vec3 Normal;
/* ② 输出数据 */
layout (location = 0) out vec4 FragColor;
// layout (location = 1) out vec4 OtherColor;
/* ③ Uniform */
layout (location = 0) uniform vec4 SomeUniform;
void main() {
FragColor = vec4(1.0);
}① 输入数据
[layout (location = x)] in [插值类型] 变量类型 名称;顶点 着色器阶段
顶点着色器的in变量的数据由CPU程序直接传入,可以通过变量索引或变量名进行数据传递。
该阶段
插值类型无意义
其他 着色器阶段
其他着色器的in变量的数据由上阶段着色器的out变量传入,要求对应变量的变量索引、变量名、插值类型必须一致才能够匹配并传递。
② 输出数据
[layout (location = x)] out [插值类型] 变量类型 名称;其他 着色器阶段
out变量会向下一阶段的着色器传递。
提示
顶点着色器对每个顶点执行一次,一些与顶点直接相关的数据应当在顶点着色器中处理再向后传递,如法线。
片段 着色器阶段
片段着色器的out变量会直接写入 帧缓冲区(Frame Buffer)的指定颜色附件(Color Attachment),可以输出多个vec4变量到多个颜色附件。
③ Uniform
[layout (location = x)] uniform 变量类型 名称;Uniform变量的数据均由CPU程序直接传入,常用作动态调节的着色器参数。
⊙变量索引 和 插值符
- 变量索引:即
layout(location=x),若不设置则按照变量声明顺序自动设置。 - 插值符:控制变量数据在经过光栅化阶段时,是否进行插值。
smooth:线性插值(默认)flat:不插值,将会直接使用图元中某个点的数据noperspective:非透视插值
④ gl_Position
gl_Position 是顶点着色器的 唯一必须输出,用于存储当前顶点在 齐次裁剪空间 中的坐标。注意该变量类型为vec4。