#sec-4-1
Orthographic Projection
正交投影:投影线与投影平面垂直
在平行投影的一种常用情形中,所有投影线互相平行且垂直于投影平面。
#sec-4-2
View Volume
正交观察体是一个长方体
观察体与视口不是同一概念:前者决定场景中哪些区域进入成像,后者决定图像映射到屏幕的哪里。
#sec-4-3
Normalization
为什么要把任意观察体映射到规范立方体?
不同程序和模型可以使用不同世界单位;GPU裁剪和后续处理需要统一的规范范围。
视空间范围 [l,r]→平移 + 缩放→规范范围 [−1,1]
xndc = 2(x − l)/(r − l) − 1这里以正交投影的X分量为例说明;Y、Z按相应边界映射。
课堂快速代入:x=l时得到−1;x=r时得到1;中点对应0。
#sec-4-4
WebGL API · ortho
用六个参数构造正交投影矩阵
const projectionMatrix = mat4.create();
mat4.ortho(projectionMatrix,
left, right, bottom, top, near, far);
Portho 的作用
将选定的长方体观察范围映射为规范裁剪范围。
与View的区别
改变ortho的边界不会自动改变eye/at/up或相机方向。
这里使用gl-matrix函数签名;near/far与默认相机沿负Z方向的约定保持一致。
#sec-5-1
Perspective Projection
透视投影:投影线汇聚于一个中心
同一条深度方向上,物体越远,投影缩小越明显;正交投影没有这种透视性变化。
#sec-5-2
Similarity of Triangles
近大远小来自相似三角形
相机位于原点、沿负Z方向看,在z = −f平面投影。由相似三角形可得到:
x′ = f · x/(−z) y′ = f · y/(−z)
近处:z=−2
取f=1、x=1,则x′=0.5。
远处:z=−4
取f=1、x=1,则x′=0.25。
学生应能解释:分母随距离增加,投影后的坐标幅度变小。
#sec-5-3
Homogeneous Coordinates
非线性透视关系,为什么仍可用矩阵?
三维点的齐次表示→4×4 投影矩阵→裁剪坐标 (xc,yc,zc,wc)→除以 wc
xndc = xc/wc,yndc = yc/wc
透视投影矩阵利用齐次分量表示深度相关的变换;真正的除法由顶点着色器之后的流水线阶段完成。
#sec-5-4
Perspective Frustum
透视观察体是截头锥体(视锥体)
不把视锥体理解为真实光线追踪空间;这里是栅格化管线用来决定可见范围的几何体。
#sec-5-5
Perspective Parameters
四个参数,分别控制取景和裁剪
| 参数 |
含义 |
改变后的典型效果 |
| fovy |
垂直视角 |
变大 → 视野更广、物体通常更小 |
| aspect |
宽高比 |
决定水平与垂直显示范围比例 |
| near |
近裁剪距离 |
太近的几何可能被裁剪 |
| far |
远裁剪距离 |
太远的几何可能被裁剪 |
mat4.perspective(projectionMatrix,
Math.PI / 4, canvas.width / canvas.height,
0.1, 100.0);
gl-matrix中fovy单位是弧度;通常要求0 < near < far。
#sec-5-6
Prediction Before Demo
预测:FOV、near与相机后退是否相同?
固定相机、模型、视口大小,把fovy由45°增至90°,图中物体通常怎样变化?
A. 更大B. 更小,同时视野范围更宽C. 大小不变,只改变遮挡关系
答案:B FOV越大,相同角度范围内屏幕单位对应越少。
接下来用相同模型和相机,分开修改参数验证,避免一次调整多个变量。
#sec-6-1
Interactive Demo
D05-02 · 正交与透视投影显微镜
D05-02 · 教学实验台
WebGL2 + Canvas 2D + 原生三维数学
正交与透视投影交互显微镜
相机和模型不变,只改变投影矩阵。直观观察正交长方体与透视视锥体的形态变化,实时验证近大远小与裁剪机制。
🔹
三重视角联动:外部三维观察体、中间真实渲染高度实测与右侧完整投影参数控制
🔹 顶点不可变性:场景中两只立方体顶点 Buffer
永久保持不变,仅更新投影矩阵 P
🔹 坐标显微镜:实时跟踪计算点在裁剪空间 (Clip)
与透视除法后的 NDC 坐标
课堂观察任务
4 min
带着问题观察与验证
-
正交 vs 透视切换:观察两只严格同尺寸立方体在正交下的等高显示(1:1)与透视下的近大远小差异。
-
视场角 fovy 调节:在透视模式下逐步减小
fovy,观察视锥体变窄时屏幕物体如何被“拉近放大”。
-
Near/Far 边界裁剪:增大 near 使其切入近处物体,或缩小 far
使远处物体消失,确认被裁剪不是遮挡。
-
数学与 NDC 检验:展开“坐标显微镜”,观察透视除法中 \(w = -z\)
如何将远近坐标压缩映射至 NDC。
💡
核心法则:投影矩阵定义了“可视范围的几何体”和“如何将三维几何映射到二维规范视口”。
教学重点是观察中间状态,确认“投影选择”和“相机位置”是两类不同参数。
#sec-6-2
Demo Operations
三轮参数实验:一次只改一个因素
1固定相机与模型,切换正交/透视:比较不同深度同尺寸物体。
2固定其余参数,增大fovy:观察物体在画面中变小。
3逐步增大near或缩小far:观察部分几何消失的边界。
在第三轮特别询问:被裁剪掉,是否等于被前面的物体遮挡?答案:不是。
#sec-6-3
Complete Viewing Pipeline
从三维对象到屏幕:现在把整条链连接起来
pclip = P · V · M · pmodel
第三章窗口坐标/NDC的交互处理与第五章渲染方向相反,注意坐标流向。
#sec-6-4
Minimal Vertex Shader
WebGL2:在顶点着色器中形成裁剪坐标
#version 300 es
in vec4 aPosition;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjectionMatrix;
void main() {
gl_Position = uProjectionMatrix *
uViewMatrix * uModelMatrix * aPosition;
}
gl_Position输出齐次裁剪空间坐标;透视除法和视口变换由后续图形流水线完成。
#sec-6-5
Clipping ≠ Occlusion
“看不到”有两种不同原因
超出视见体 → 裁剪
几何不在投影定义的可见范围内,即使前方没有其他物体也可能被裁剪。
位于后方 → 遮挡
处于视见体内的表面可能被其他表面挡住,通常利用深度测试解决。
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
本节只建立区分;背面剔除、深度精度、阴影贴图等列为教材延伸。