由于这本书是英文原版,且年代稍早,我会为您提供一个结合了该书核心思想与现代实践的、系统化的 CG 教程和学习路径,这不仅仅是一本“书”的解读,更是一份从零到一的实战指南。

CG 教程:可编程实时渲染权威指南(实战版)
这份指南将分为以下几个部分:
- 核心思想:从固定功能到可编程管线
- 图形渲染管线:你的“Hello World”在哪里?
- 着色器语言:GLSL vs. HLSL
- 第一块积木:顶点着色器
- 魔法发生的地方:片元着色器
- 现代渲染进阶:从 Shader Model 5 到现代 API
- 学习资源与实战项目推荐
核心思想:从固定功能到可编程管线
在学习代码之前,必须理解这个根本性的转变。
-
固定功能管线:在早期(如 DirectX 7/8),GPU 内部有固定的处理流程,你告诉 GPU “用这个光源”、“用这个纹理”、“开启这个混合模式”,GPU 就会按照预设的公式去执行,这就像一个只能做特定菜品的厨师,你点菜,他照着菜谱做。
-
可编程管线:从 DirectX 9 / OpenGL 2.0 开始,程序员可以直接编写小程序(即 着色器 - Shader)上传到 GPU,让 GPU 在特定阶段执行这些自定义程序,这就像给了厨师一个完整的厨房和菜谱,你可以让他用任意食材、任意方法创造全新的菜品。
(图片来源网络,侵删)
着色器就是运行在 GPU 上的小程序,它们是可编程管线的灵魂。
图形渲染管线:你的“Hello World”在哪里?
想象一下,你如何告诉 GPU 画一个彩色的三角形?这个过程就是渲染管线,虽然现代管线非常复杂,但其核心阶段与《可编程实时权威指南》中描述的概念一脉相承。
一个简化的可编程管线流程如下:
- 应用阶段:你的游戏主程序在 CPU 上运行,它负责准备数据:顶点坐标、颜色、纹理坐标、模型变换矩阵等,然后将这些数据发送给 GPU。
- 几何阶段:
- 输入装配:GPU 收集 CPU 发来的顶点数据。
- 顶点着色器:(可编程) 对每个顶点执行一次,它的主要工作是:
- 坐标变换:将顶点从模型空间 -> 世界空间 -> 观察空间 -> 裁剪空间,这是“画在哪里”的关键。
- 计算其他属性:如法线、光照等。
- 曲面细分 & 几何着色器:(可选,更高级)用于增加模型细节或动态生成几何体。
- 裁剪 & 光栅化:将屏幕外的顶点裁剪掉,然后将三角形“像素化”,确定哪些像素被这个三角形覆盖,并为每个像素生成一个片元。
- 光栅化阶段:
- 片元着色器:(可编程) 对每个片元执行一次,它的主要工作是:
- 纹理采样:根据片元的纹理坐标,从纹理图像中获取颜色。
- 光照计算:根据光源和法线计算最终颜色。
- 颜色输出:输出该片元的最终颜色值。
- 片元着色器:(可编程) 对每个片元执行一次,它的主要工作是:
- 输出合并阶段:将片元着色器输出的颜色与屏幕上已有的颜色进行混合、深度测试等,最终写入帧缓冲区,显示在屏幕上。
你的第一个“Hello World”程序,就是编写一个最简单的顶点着色器,把一个三角形的三个顶点画在屏幕上。

着色器语言:GLSL vs. HLSL
《可编程实时权威指南》主要基于 HLSL (High-Level Shading Language),它是 DirectX 的一部分,而在跨平台领域,GLSL (OpenGL Shading Language) 是标准。
- HLSL:主要用于 Windows 平台的 DirectX 应用,语法上与 C/C++/C# 更相似。
- GLSL:主要用于跨平台的 OpenGL/Vulkan/Metal 应用,语法上更像 C,但有一些独特的特性。
核心概念几乎完全相同:变量、数据类型(vec3, mat4)、函数、in/out、uniform、attribute/varying(旧版GLSL)等。
现代选择:
- Vulkan / Metal:使用一种名为 SPIR-V 的中间语言,可以由 HLSL 或 GLSL 编译而来,这提供了更好的跨平台兼容性。
- OpenGL:继续使用 GLSL。
- DirectX 12:继续使用 HLSL。
建议:初学者可以先选择一种深入学习,GLSL(配合 OpenGL),因为它在学术和跨平台领域应用更广,理解一种后,另一种的语法转换非常容易。
第一块积木:顶点着色器
顶点着色器是处理单个顶点的“工人”,它的基本任务是位置变换。
一个最简单的 GLSL 顶点着色器示例:
// 声明从应用阶段传入的变量
// 'layout' 指定了顶点属性的位置索引
layout (location = 0) in vec3 aPos; // aPos = 顶点位置
// 声明传递给片元着色器的变量(可选)
// out vec3 ourColor;
// 声明全局的、所有顶点共享的变量(如变换矩阵)
uniform mat4 model; // 模型矩阵
uniform mat4 view; // 观察矩阵
uniform mat4 projection; // 投影矩阵
void main()
{
// 核心计算:将顶点位置从模型空间转换到裁剪空间
gl_Position = projection * view * model * vec4(aPos, 1.0);
// 如果需要,可以传递其他数据给片元着色器
// ourColor = aColor;
}
关键点:
in/in vec3 aPos:输入变量,代表顶点的某个属性(位置、颜色等)。uniform:全局常量,对于所有顶点都是相同的,如矩阵、时间、光源位置。gl_Position:一个内置的输出变量,必须被赋值,它代表顶点在裁剪空间中的最终位置。- 矩阵乘法顺序:
projection * view * model * vertex,记住矩阵乘法不满足交换律,顺序至关重要。
魔法发生的地方:片元着色器
片元着色器决定屏幕上每个像素最终呈现什么颜色,它是实现光照、纹理、后期效果的核心。
一个简单的 GLSL 片元着色器示例(带颜色):
// 从顶点着色器接收的数据(需要和 VS 中的 'out' 变量名和类型匹配)
// in vec3 ourColor;
// 声明一个纹理采样器
uniform sampler2D ourTexture;
// 输出变量,最终的颜色值
out vec4 FragColor;
void main()
{
// 方式1:使用从顶点着色器插值得到的颜色
// FragColor = vec4(ourColor, 1.0);
// 方式2:从纹理中采样颜色(更常见)
FragColor = texture(ourTexture, vec2(0.5, 0.5)); // 采样纹理的中心点
}
进阶:Phong 光照模型(经典示例)
这是《可编程实时权威指南》中的核心内容之一,片元着色器需要计算环境光、漫反射和镜面反射。
in vec3 FragPos; // 从顶点着色器传递过来的片元位置(世界坐标)
in vec3 Normal; // 从顶点着色器传递过来的片元法线
uniform vec3 lightPos; // 光源位置
uniform vec3 viewPos; // 观察者位置(摄像机)
uniform vec3 lightColor; // 光源颜色
out vec4 FragColor;
void main()
{
// 1. 环境光
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// 2. 漫反射
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// 3. 镜面反射
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); // 32是高光系数
vec3 specular = specularStrength * spec * lightColor;
// 组合所有光照
vec3 result = (ambient + diffuse + specular) * vec4(1.0, 1.0, 1.0, 1.0).xyz; // 假设物体是白色的
FragColor = vec4(result, 1.0);
}
现代渲染进阶:从 Shader Model 5 到现代 API
《可编程实时权威指南》的时代是 DirectX 9/10/11,现在我们已经进入了 DirectX 12, Vulkan, Metal 的时代。
- 可编程管线对象:现代 API(如 DX12, Vulkan)要求你显式地创建和绑定整个管线的状态,包括所有着色器、混合状态、光栅化状态等,这比旧的“设置一个着色器”更底层、更强大,也更复杂。
- GPU Driven Rendering:一种新的渲染范式,利用计算着色器来高效地驱动渲染流程,例如进行大规模的可见性剔除、动态批处理等。
- 物理渲染:基于物理的材质和工作流,着色器需要更精确地模拟光线与材质的交互(微表面模型)。
- Ray Tracing(光线追踪):通过硬件加速光线追踪,着色器可以编写“光线着色器”,实现全局光照、反射、折射等过去难以实现的效果。
不变的核心:无论 API 如何变化,顶点着色器负责位置变换,片元着色器负责颜色计算这一核心逻辑从未改变,理解了基础,才能驾驭现代的复杂技术。
学习资源与实战项目推荐
-
书籍(理论基石):
- 《Programming Vertex, Geometry, and Pixel Shaders》:必读,深入理解管线和着色器编程。
- 《Real-Time Rendering, 4th Edition》:实时渲染的“百科全书”,涵盖了从管线到光照、到现代技术的方方面面。
- 《OpenGL SuperBible》:学习 OpenGL 和 GLSL 的绝佳入门书籍。
-
在线教程(动手实践):
- LearnOpenGL (CN):强烈推荐! 从零开始,使用现代 OpenGL(3.3+)和 GLSL,讲解清晰,代码完整,覆盖了所有基础和进阶主题,它的结构几乎就是一份完美的实战教程。
- Bilibili / YouTube:搜索“OpenGL教程”、“Shader Toy教程”、“HLSL教程”,有大量优秀的视频课程。The Cherno、Sebastian Lague、Johnnysson 等博主的视频质量非常高。
-
工具与社区:
- Shader Toy:一个在线的 GLSL 片元着色器“游乐场”,你可以看到别人的炫酷效果,并学习他们的代码,是学习视觉特效的绝佳平台。
- RenderHub:提供大量高质量的 3D 模型和材质,方便你专注于编写着色器。
- GitHub:寻找开源的图形学项目,阅读源码是提升最快的方式之一。
-
实战项目路径:
- 项目 1:渲染一个彩色三角形:学习设置 OpenGL 上下文,编译和链接着色器,传递顶点数据。
- 项目 2:加载并显示一个纹理:学习纹理坐标和纹理采样。
- 项目 3:实现 Phong 光照模型:将上面提到的 Phong 着色器代码应用到你的模型上。
- 项目 4:实现一个简单的后处理效果:如灰度、反色、模糊等,这需要你将渲染结果作为纹理再次输入。
- 项目 5:学习并使用 PBR:尝试实现一个基于物理的渲染材质。
- 项目 6(终极挑战):实现一个简单的延迟渲染器:这是现代游戏引擎普遍使用的技术,能让你深入理解 G-Buffer 和光照计算。
学习 CG 和可编程实时渲染是一个理论与实践紧密结合的过程,以《可编程实时权威指南》的思想为骨架,以现代教程(如 LearnOpenGL)为血肉,通过不断动手实践,才能真正掌握这门强大的技术,祝你学习顺利!
