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

WebGL2光照与着色器实现

如何将光照模型接入已学过的模型—观察—投影流水线?

AttributeUniformNormal MatrixVertex/Fragment验证
#sec-2-1
Bridge-in · Programmable pipeline

同一个光照公式,放在哪里执行?

JS应用程序、顶点着色器、片元着色器都能参与光照;计算位置改变效率和视觉效果。

要在面内出现更精细的高光,通常优先考虑在哪个阶段计算光照?
A. 顶点阶段B. 片元阶段C. 仅在CPU执行
#sec-2-2
Connection · Chapter 5 → 6

从第五章的MVP,到第六章的光照数据

Position+Normal→Model/View→Projection→Rasterization→Fragment color
位置要进入裁剪坐标;法向量与光照方向在统一的世界或观察坐标系中计算,不能用投影后的坐标直接混算。
#sec-3-1
Data flow · GLSL ES 3.00

三类数据:Attribute、Uniform、插值输入

in · 顶点属性

aPosition、aNormal:随顶点变化。

uniform · 统一参数

变换矩阵、光源位置、材质参数。

out / in · 阶段传递

顶点着色器输出,光栅化插值后供片元使用。

#sec-3-2
Vertex shader · Essential

顶点着色器:既处理位置,也传递光照数据

#version 300 es
in vec4 aPosition;
in vec3 aNormal;
uniform mat4 uModelView, uProjection;
uniform mat3 uNormalMatrix;
out vec3 vNormal;
// main中:
vNormal = normalize(uNormalMatrix * aNormal);
gl_Position = uProjection * uModelView * aPosition;
这是关键语句摘录,省略完整main和其他变量,便于课堂聚焦。
#sec-3-3
Normal Matrix · Why

坐标空间必须一致:位置与法向量不是同一种量

\(\mathbf N'=\operatorname{normalize}((MV)^{-T}_{3\times3}\mathbf N)\)
  • 光源方向、观察方向、法向量在同一坐标空间中参与点积。
  • 存在非均匀缩放时,普通模型矩阵通常不能正确变换法向量。
  • 先计算法向量矩阵,再把结果传给着色器。
#sec-4-1
Vertex lighting

Gouraud实现:顶点阶段计算颜色

// 顶点着色器:计算Phong/Blinn-Phong分量
out vec3 vColor;
// ... N、L、V以及光照模型计算后
vColor = ambient + diffuse + specular;
光栅化阶段对vColor插值;片元着色器可直接输出插值后的颜色。
#sec-4-2
Fragment shader · Gouraud

Gouraud片元着色器:接收插值后的颜色

#version 300 es
precision highp float;
in vec3 vColor;
out vec4 fragColor;
void main() {
    fragColor = vec4(vColor, 1.0);
}
变量是in/out,不使用WebGL1风格的varying或gl_FragColor。
#sec-4-3
Fragment lighting · Phong

Phong实现:片元阶段使用插值法向量

#version 300 es
precision highp float;
in vec3 vNormal;
in vec3 vEyePosition;
uniform vec3 uLightPositionEye;
out vec4 fragColor;
// main中先把插值法向量重新单位化
vec3 N = normalize(vNormal);
vec3 L = normalize(uLightPositionEye-vEyePosition);
关键差异:每个片元重新求光照;这里的L与N均位于观察坐标空间。
#sec-4-4
Compare · GPU stages

一张流程图:两种计算位置

R06-19 · Gouraud与Phong的着色器计算位置对照
Gouraud:顶点算光照,插值颜色(vColor);Phong:插值法线(vNormal),片元算光照。
#sec-5-1
Experiment · Pipeline & Code

D06-04 · 着色方法代码实现与流水线机制

Interactive Demo · D06-04

Gouraud(顶点求值)与 Phong(片元求值)同屏渲染与 Shader 源码对照

预设观察条件:左右分屏同步渲染三维模型(球体/犹他茶壶/环面结),底部同屏对照 GLSL ES 3.00 顶点着色器与片元着色器真实源码;点击流程图节点可联动高亮关键计算行。

带着问题操作:对照源码,为什么同样的几何模型与光源,Gouraud 会在粗网格下丢失高光,而 Phong 能够平滑求出?光照计算究竟发生在哪个流水线阶段?
▶ 打开独立 Demo:D06-04 · 着色方法代码实现比较与流水线机制 ↗
#sec-5-2
Experiment · Predict

验证:什么情况下差异最明显?

  • 面数较少、三角形较大时,比较高光是否丢失。
  • 移动光源,让高光峰值落在某个三角形内部。
  • 增加面片数后,再检查Gouraud与Phong差异是否缩小。
任何效果比较都记录:网格数、光源、材质参数和着色模式。
#sec-5-3
AI Collaboration · Code audit

AI生成代码的三个核验点

核验①

插值后的法向量是否normalize?

核验②

N、L、V是否使用统一坐标空间?

核验③

非均匀缩放后是否正确变换法向量?

选一个错误做最小可复现验证;提交“问题—修改—运行证据—理由”。
#sec-6-1
Transfer · MED × CG

回到三维模型查看器

保持第五章的Model、View、Projection,实现一个可切换着色算法的三维对象。

  • 几何位置和相机投影由原有MVP完成。
  • 补充法向量与材质/光源参数。
  • 选择逐顶点或逐片元计算,记录对比。
#sec-6-2
Limits · Local vs Global

局部光照还解释不了哪些现象?

R06-20 · 局部光照与全局光照比较
遮挡形成的阴影、间接反射与颜色渗透,需要额外的绘制方法;局部模型本身不会自动生成。
#sec-6-3
Extension · NPR / PBR

非真实感与物理绘制:知道边界即可

NPR非真实感着色

根据视觉表达需要,刻意使用色阶、描边等效果。

PBR与全局光照

关注更合理的材质和能量传播;此处仅建立后续学习位置。

法线贴图、纹理采样、阴影映射和PBR细节留待后续专题,不在本课展开。
#sec-7-1
Summary · Chapter 6

本章知识闭环:从几何到颜色

模型与MVP→法向量/光源/材质→光照计算位置→片元颜色
能够解释现象、选择策略、定位GLSL实现环节,再用同一模型和参数验证。
#sec-7-2
Check for Understanding

Exit Ticket · 找出一处错误

in vec3 vNormal;  // 由光栅化插值得到
float intensity = max(dot(vNormal, L), 0.0);
最应补充哪一步,才能避免插值后法向量长度改变造成的误差?
A. normalize(vNormal)B. 直接乘以投影矩阵C. 删除L