文章目录
- 概述
- 现代GPU的图形渲染管线完整流程
- 阶段详解(2D视角)
-
- [输入装配(Input Assembler)](#输入装配(Input Assembler))
- [顶点着色器(Vertex Shader)](#顶点着色器(Vertex Shader))
- [图元装配(Primitive Assembly)](#图元装配(Primitive Assembly))
- 光栅化(Rasterization)
- [片段着色器(Fragment Shader)](#片段着色器(Fragment Shader))
- [测试与混合(Tests & Blending)](#测试与混合(Tests & Blending))
- 对于2D游戏,可以重点关注
- 实际渲染2D精灵流程示例
概述
- 图形渲染管线(Graphics Pipeline)
现代GPU的图形渲染管线完整流程
- CPU提交数据
- 输入装配 -> 【顶点着色器】-> 曲面细分 -> 几何着色器
- 图元装配 -> 光栅化 -> 【片段着色器】 -> 测试与混合
- 帧缓冲区 -> 【屏幕显示】
阶段详解(2D视角)
输入装配(Input Assembler)
- 作用:收集原始的顶点数据
- 2D示例:
javascript
// 一个2D矩形的4个顶点数据
const vertices = [
// x, y, u, v (位置坐标 + UV纹理坐标)
-1, -1, 0, 0, // 左下角
1, -1, 1, 0, // 右下角
-1, 1, 0, 1, // 左上角
1, 1, 1, 1 // 右上角
];
顶点着色器(Vertex Shader)
- 作用:处理每个顶点的位置和属性
- 2D特点:通常简单,只是传递数据
- 示例关键理解:每个顶点都会执行一次这个程序:
typescript
// Laya 2D顶点着色器
void main() {
gl_Position = mvp * vec4(a_Position, 0.0, 1.0); // 位置变换
v_TexCoord0 = a_TexCoord0; // 传递UV坐标
}
图元装配(Primitive Assembly)
- 作用:将顶点组装成三角形、线条等基本图形
- 2D示例:把4个顶点组装成2个三角形,组成一个矩形精灵
光栅化(Rasterization)
- 作用:将几何图形转换为屏幕上的像素(片段)
- 过程:三角形几何体 → 计算覆盖的像素 → 生成片段(Fragment)
- 重要概念:片段(Fragment) ≠ 像素(Pixel)
- 片段是"候选像素",还需要经过测试才能成为最终像素
片段着色器(Fragment Shader)
- 作用:决定每个片段的最终颜色
- 示例关键理解:每个像素都会执行一次这个程序!
typescript
void main() {
vec4 color = texture2D(u_AlbedoTexture, v_TexCoord0); // 采样纹理
color.rgb *= u_Brightness; // 调整亮度
gl_FragColor = color; // 输出颜色
}
测试与混合(Tests & Blending)
- 深度测试:决定哪个物体在前(3D重要,2D通常按绘制顺序)
- 模板测试:用于遮罩效果
- Alpha混合:处理半透明效果
typescript
// 经典的Alpha混合公式
final_color = source_color * source_alpha +
destination_color * (1.0 - source_alpha)
对于2D游戏,可以重点关注
-
精灵顶点数据\] → \[顶点着色器(传递数据)\] → \[光栅化\] → \[片段着色器(上色)\] → \[混合
- 关键简化:
- 顶点着色器通常只是传递位置和UV
- 深度测试通常用绘制顺序代替
- 主要工作都在片段着色器中完成
实际渲染2D精灵流程示例
准备阶段(CPU)
typescript
// Laya中创建精灵
let sprite = new Laya.Sprite();
sprite.loadImage("hero.png");
顶点着色器处理
typescript
// 每个顶点执行:位置 → 裁剪空间,UV → 传递
// 输入:4个顶点 → 输出:4个变换后的顶点
光栅化
- 矩形几何体 → GPU计算覆盖的像素 → 生成1000个片段(假设精灵大小)
片段着色器处理
typescript
// 每个片段执行:
void main() {
// 根据UV坐标从纹理获取颜色
vec4 color = texture2D(u_Texture, v_TexCoord0);
// 应用特效(如变红表示受伤)
if (u_IsHurt > 0.5) {
color.rgb = mix(color.rgb, vec3(1.0, 0.0, 0.0), 0.5);
}
gl_FragColor = color;
}
最终输出
- 经过Alpha混合后,精灵显示在屏幕上