学院 LOGO · 占位
#sec-1
Computer Graphics · Chapter 6 · 04

从多边形到平滑着色

同样的三角形网格,为什么会呈现完全不同的表面效果?

三角网格面/顶点法向量FlatGouraudPhong
#sec-2-1
Bridge-in · Mesh vs Shading

这是同一个三维对象,为什么一个有棱角?

所有效果都来自同一几何模型与光照:差别在于计算位置(面心/顶点/片元)与插值对象,几何轮廓保持不变。
#sec-2-2
Predict · Where to compute

预测:着色发生在顶点,还是面内每一处?

如果只在三角形三个顶点计算光照,面内出现的高光一定准确吗?
A. 一定B. 不一定;面内强高光可能未出现在顶点上
#sec-3-1
Normals · Face

三角面片:整个面有一个几何法向量

R06-15a · 面法向量与顶点法向量(旧素材)
平面三角形的几何朝向固定,面法向量可由两条边的叉积求得。
#sec-3-2
Normals · Vertex Normal Averaging

顶点法向量:相邻面法向量的平均与归一化

R06-15b · 相邻面法向量平均构造顶点法向量示意图
图解对应:黑色顶点被 4 个相邻面共享,各面法向分别为 \(\mathbf{n}_1, \mathbf{n}_2, \mathbf{n}_3, \mathbf{n}_4\),中心复合向量为平滑顶点法向 \(\mathbf{n}\)。
📐 图示 4 个相邻面的具体计算公式:
\[\mathbf{n} = \frac{\mathbf{n}_1 + \mathbf{n}_2 + \mathbf{n}_3 + \mathbf{n}_4}{\|\mathbf{n}_1 + \mathbf{n}_2 + \mathbf{n}_3 + \mathbf{n}_4\|}\]
🌐 通用网格计算公式(设有 \(k\) 个共顶点相邻面):
\[\mathbf{n} = \frac{\sum_{i=1}^{k} \mathbf{n}_i}{\left\|\sum_{i=1}^{k} \mathbf{n}_i\right\|} \quad \left(\text{加权形式:} \mathbf{n} = \frac{\sum w_i \mathbf{n}_i}{\|\sum w_i \mathbf{n}_i\|}\right)\]
计算要点与工程考量:
① 累加平均:遍历共享该顶点的所有相邻面,累加各面的几何法向量 \(\mathbf{n}_i\);
② 强制归一化:多个向量直接相加后的长度通常不为 1,必须除以模长以保证为单位向量;
③ 折痕控制(Crease Angle):对机械硬边(夹角过大),不能无条件平均,需拆分顶点保留硬棱外观。
核心价值:顶点法向量平滑处理是曲面网格着色(Gouraud/Phong)消除楞线棱角、获得连续视觉过渡的数学基础。
#sec-3-3
WebGL2 · Attribute

法向量属于顶点属性,位置坐标不是法向量

#version 300 es
in vec4 aPosition;  // 顶点位置
in vec3 aNormal;    // 顶点法向量
球心在原点的单位球面,可以用归一化顶点位置构造法向量;一般网格不能照搬。
#sec-4-1
Shading Methods · Overview

三大多边形着色方法:核心定义与关键对比

平面着色 Flat

逐面计算

每个面计算一次光照,面内片元恒定赋同色。

特征:面法向 \(\mathbf{n}_f\) | 无插值 | 面片棱角

高洛德 Gouraud

逐顶点

顶点计算光照颜色,面内片元插值颜色。

特征:顶点法向 \(\mathbf{n}_v\) | 插值颜色 | 高光易失

冯氏着色 Phong

逐片元

面内插值法向量,逐片元独立计算光照。

特征:插值法向 \(\mathbf{n}\) | 重新归一化 | 高光精准
⚖️ 相同点(共享基础):
• 同一几何网格:顶点与拓扑完全一致,几何轮廓不变
• 同一光照模型:均采用环境光 + 漫反射 + 镜面高光公式
🔍 核心差异(本质不同):
• 计算阶段:逐面(单次) \(\rightarrow\) 顶点着色器 (VS) \(\rightarrow\) 片元着色器 (FS)
• 插值对象:无插值 \(\rightarrow\) 插值颜色 \(\rightarrow\) 插值法向量
• 光影品质:面片棱角(马赫带) \(\rightarrow\) 平滑但高光失真 \(\rightarrow\) 精准高光与平滑曲面
核心规律:光照计算越靠后(面 \(\rightarrow\) 顶点 \(\rightarrow\) 片元),曲面高光与明暗越平滑真实,计算开销越大。
#sec-4-2
Shading · Flat Shading

平面着色:逐面单次计算与面片效应

Flat着色球面渲染效果
视觉特征:整面明暗均一,面边界亮度跳变,多面体棱角分明。
📌 计算原理与流程
整面共用同一面法向 \(\mathbf{n}_f\),在中心点计算一次光照,全片元赋予相同颜色。
面顶点 → 面法向 \(\mathbf{n}_f\) → 单次光照计算 → 整面赋同色
✅ 核心优点
• 计算极快:逐面单次计算,无插值开销
• 真实硬表面:天然契合立方体与多面体
• 风格鲜明:Low-Poly 极简复古艺术风格
❌ 主要缺点
• 面片效应:曲面被割裂为平面碎块
• 马赫带伪影:视网膜侧抑制诱发虚假亮边
• 缺失高光:面内无法表达细腻局部高光
马赫带效应(Mach Banding):人眼视觉对亮度的一阶导数极度敏感,两面明暗突变边界处会产生虚假的过度对比亮暗边缘。
#sec-4-3
Shading · Gouraud Shading

Gouraud着色:先算顶点颜色,再在面内插值

Gouraud着色球面渲染效果
视觉特征:曲面明暗连续平滑,消除了面片棱角;但高光变平钝,易出现畸变。
📌 计算原理与流程
顶点着色器计算各顶点的完整光照颜色,光栅化在三角面内双线性插值颜色。
顶点法向 \(\mathbf{n}_v\) → VS算顶点颜色 \(C_v\) → 光栅化插值颜色 → 片元直接输出
✅ 核心优点
• 平滑连续:消除面片明暗跳变与马赫带
• 性能优异:计算量取决于顶点数,远少于像素数
• 硬件经典:早期固定管线(OpenGL 1.x)标准
❌ 主要缺点
• 高光丢失:高光落在面内未覆盖顶点时完全消失
• 非线性畸变:线性颜色插值无法拟合高次方高光
• 光影生硬:高光形状易被三角形网格拉伸扭曲
高光丢失根源:高光指数运算是非线性的陡峭峰值;若三顶点均未对准高光区,线性颜色插值只能得到全暗结果。
#sec-4-4
Shading · Phong Shading

Phong着色:插值法向量,逐片元计算光照

Phong着色球面渲染效果
视觉特征:高光亮斑圆润精确,表面逼真;注意外边缘剪影仍为折线。
📌 计算原理与流程
面内插值法向量,片元着色器重新归一化后,逐像素独立计算光照。
顶点法向 \(\mathbf{n}_v\) → 插值法向 \(\mathbf{n}_{\text{interp}}\) → FS重新归一化 → 逐片元独立算光照
✅ 核心优点
• 高光精准:小高光亮斑精确定位,杜绝丢失
• 画质真实:表面极其光滑细腻,无面片伪影
• 工业标准:现代可编程 GPU 与 PBR 渲染基石
❌ 主要局限
• 算力开销大:逐片元归一化与幂次计算,正比于像素数
• 不改几何轮廓:多边形边缘剪影仍为折线锯齿
为什么必须重新归一化?单位向量线性插值后长度必然小于 1,片元着色器必须执行 normalize(),否则漫反射与高光会虚假变暗。
#sec-4-5
Pipeline Comparison · Gouraud vs Phong

实践路径对比:Gouraud 与 Phong 在渲染管线上的分流

Gouraud 与 Phong 两种着色方法在实践路径上的差异流程图
Gouraud着色(顶点算颜色 → 面内插值颜色)
• 计算前置:光照计算在顶点着色器完成,片元阶段只做颜色传递,片元开销极低。
• 实践局限:高光峰值落在三角形内部未覆盖顶点时,面内线性插值导致高光遗漏或钝化。
Phong着色(面内插值法线 → 片元逐像素算光照)
• 计算后置:面内插值法向量,在片元着色器重新归一化并逐像素计算完整光照方程。
• 画质优势:高光圆润集中、定位精确,高光更准确;算力开销正比于屏幕像素数。
管线分水岭:Gouraud 与 Phong 的本质分歧在于光照计算发生在光栅化之前还是之后;Phong 必须在片元着色器中执行 normalize(vNormal)。
#sec-4-6
Critical distinction · Model vs Algorithm

两个“Phong”回答图形学中完全不同的问题

① Phong 光照模型 (Model)

物理公式维度

核心问题:“空间中某一点的颜色依据什么公式计算?”

\[I = I_a k_a + I_d k_d (\mathbf{l}\cdot\mathbf{n}) + I_s k_s (\mathbf{r}\cdot\mathbf{v})^s\]
本质:经验着色方程(环境光 + 漫反射 + 镜面高光)。与执行阶段解耦,CPU、VS、FS 均可计算。

② Phong 着色算法 (Algorithm)

管线策略维度

核心问题:“多边形面内片元何时获得法向并执行光照计算?”

顶点法向 \(\mathbf{n}_v \xrightarrow[\text{插值}]{\text{光栅化}} \mathbf{n}_{\text{interp}} \xrightarrow[\text{归一化}]{\text{FS}} \mathbf{n}_{\text{frag}} \rightarrow \text{逐像素光照}\)
本质:管线插值与执行策略。其内部不仅能用 Phong 公式,也能用 Blinn-Phong 或 PBR 公式。
正交解耦关系:光照模型是“计算公式”,着色策略是“执行位置与插值策略”;两者相互独立、正交组合。
#sec-5-1
Experiment · Controlled comparison

D06-C · 三种着色算法对比显微镜

Interactive Demo · D06-C

同一模型、同一光源、同一材质下切换三种着色策略

预设观察条件:固定低面数球体与高光指数,轮流选择Flat、Gouraud、Phong。

带着问题操作:哪些地方出现面片边界?高光是否出现在三个顶点之间?
▶ 打开独立 Demo:D06-03 · 三维模型着色方式对比实验台 ↗
#sec-5-2
Experiment · One-factor

控制变量:比较才有解释力

  • ① 固定网格层级,只改变着色策略。
  • ② 固定着色策略,只增加三角形数量。
  • ③ 固定网格与策略,只移动光源或改变高光指数。
不要同时改变网格精度、光源和着色方式后再归因。
#sec-5-3
Experiment · Geometry vs Shading

更密的三角形是否等于更好的着色?

R06-17 · 同一球面不同细分层级
几何细分改善轮廓与曲率近似;法向量和插值策略改善光照的平滑表现,二者作用不同。
#sec-5-4
Reason · Highlight missed

Gouraud为什么可能错过面内高光?

R06-18 · 三角形内部高光峰值示意
这是着色计算位置与非线性高光函数共同造成的结果,不是“GPU忘了插值”。
#sec-6-1
Comparison

三种方法:输入、插值与成本

Flat

面常量近似;保留明显棱角。

Gouraud

顶点计算颜色;片元插值。

Phong

插值法向量;逐片元求光照。

视觉质量与计算量有权衡;不同网格密度与场景会改变实际差异。
#sec-6-2
Interactive Quiz · Curvature & Visual Quality

课堂测验 ① · 高曲率表面的视觉平滑度与剪影特征

Q1. 在处理高曲率物体表面(如强弯曲管道、茶壶流线部位)时,比较 Gouraud 着色与 Phong 着色的视觉表现,下列哪项判断最准确?
A Gouraud 着色因计算量小,能自动消除高曲率表面的剪影边(Silhouette)锯齿,使整个模型几何轮廓平滑
B Phong 着色因逐片元插值法向量使曲面看起来更平滑;而 Gouraud 易产生明暗突变与折棱,且两者均不能把几何网格折线剪影变成平滑曲线
C 高曲率表面上 Phong 着色的光照计算会发散,产生强烈的马赫带明暗阶跃,平滑度反而劣于 Gouraud
D 两者在高曲率表面的高光分布完全相同,差异仅体现在漫反射背景颜色微弱差异上
✓ 正确答案:B
• 法向量插值优势:高曲率表面法向剧烈偏转,Phong 着色对法向量逐片元插值并归一化,能精准跟踪表面弯曲,保持高光和明暗圆润平滑;Gouraud 仅线性插值顶点颜色,易出现明暗突变与折棱。
• 着色与几何的本质界限:逐片元着色改善的是表面内部明暗,多边形外边缘剪影(Silhouette)始终由几何三角形网格决定,要消除外轮廓折线必须增加网格细分。
#sec-6-3
Interactive Quiz · Computation & Real-time Feasibility

课堂测验 ② · 管线计算量分布与现代实时性

Q2. 从 GPU 渲染管线的计算阶段与计算开销来看,关于 Gouraud 着色与 Phong 着色的计算量及实时渲染性能,下列说法正确的是?
A Gouraud 着色计算量大于 Phong 着色,因为光栅化插值 RGB 颜色的浮点开销高于法向量归一化
B Phong 着色主要在顶点着色器(Vertex Shader)中完成,计算开销与屏幕分辨率无关
C Phong 着色主要在片元着色器(Fragment Shader)逐像素求解完整光照,计算量显著大于 Gouraud,但在现代可编程 GPU 算力下完全可进行实时计算
D Phong 着色因包含高阶幂指数运算开销过大,目前只能用于离线渲染农场,完全无法在浏览器或游戏中实时交互
✓ 正确答案:C
• 计算量阶段分布:Gouraud 的光照计算发生在顶点着色器(正比于顶点数 \(V\));Phong 的光照计算发生在片元着色器(正比于屏幕片元数 \(F\))。因典型场景中覆盖像素数远超顶点数(\(F \gg V\)),且片元着色器需逐点归一化和计算高光幂次,Phong 计算量显著大于 Gouraud。
• 现代 GPU 实时性:现代 GPU 拥有上千个 SIMD 并行片元处理单元,即使在高分辨率下执行逐片元光照计算也能轻松达到 60~120+ FPS,Phong 着色早已是实时三维交互的通用工业基石。
#sec-6-4
Transfer · MED × CG

医学器械的平面与球面,是否应相同处理?

在带尖锐边缘的器械和平滑骨骼表面中,法向量设计与着色策略未必相同。

硬质器械的明显折线边缘,是否应该把两侧面的法向量无条件平均?
A. 应该,越平滑越好B. 不应该,否则可能掩盖真实尖锐边缘
#sec-6-5
Connection · Next lesson

WebGL2流水线:颜色在哪一段被计算?

顶点输入→顶点着色器→光栅化插值→片元着色器
下课时把三种方法落到真正的GLSL ES 3.00代码和参数传递上。
#sec-7-1
Summary

本课小结:什么决定网格的明暗过渡?

网格与法向量→光照计算位置→插值对象→片元颜色
#sec-7-2
Check for Understanding

Exit Ticket · 判别着色策略

哪种方法是“插值法向量,再逐片元计算光照”?
A. FlatB. GouraudC. Phong shading