:投影矩阵深度解析——正交 vs 透视,彻底搞懂3D视觉魔法)
还在为 WebGL 中物体“近大远小”的效果感到神奇或者苦恼于正交投影和透视投影到底该怎么选为什么 3D 物体总被裁剪看不见今天这篇教程带你彻底搞懂 WebGL 中的投影矩阵。我们从数学原理到实战代码手把手教你区分正交与透视投影并理解 MVP 矩阵中投影矩阵的核心作用。左图为正交六个面为平行四边形右图为透视六个面近大远小左图为正交六个面为平行四边形右图为透视六个面近大远小1.先搞懂为什么需要投影矩阵在 WebGL 中顶点着色器输出的gl_Position坐标范围是裁剪空间四个分量 x,y,z,w 都在 -w 到 w 之间。但我们的世界是三维的屏幕是二维的投影矩阵的作用就是将 3D 空间中的物体变换到 2D 屏幕上并决定“近大远小”的视觉感。没有投影矩阵你只能看到物体在[-1,1]范围内的正交投影毫无立体感。投影矩阵是连接 3D 世界与 2D 屏幕的魔法桥梁。核心优势投影矩阵版透视投影产生景深感符合人眼视觉是 3D 游戏/场景的首选。正交投影保持物体实际大小无透视变形适合 2D 游戏、UI 界面、工程制图。GPU 统一处理无论哪种投影都通过 4x4 矩阵乘法完成性能高效。2.WebGL 投影矩阵工作原理投影矩阵是 MVP 矩阵模型-视图-投影中的最后一环模型矩阵将物体从局部坐标变换到世界坐标平移/旋转/缩放。视图矩阵将世界坐标变换到观察者相机坐标定义相机位置和朝向。投影矩阵将观察坐标变换到裁剪坐标并定义可视范围视景体。关键公式glslgl_Position 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标;3.投影矩阵核心原理3.1 透视投影Perspective Projection透视投影模拟人眼成像遵循“近大远小”规则。它定义了一个平截头体视景体近平面大、远平面小物体越靠近近平面在屏幕上投影越大。透视矩阵原理重点标准透视矩阵由视野、宽高比、近平面、远平面构建text[ 1/(aspect*tan(fov/2)) 0 0 0 ] [ 0 1/tan(fov/2) 0 0 ] [ 0 0 -(farnear)/(far-near) -2*far*near/(far-near) ] [ 0 0 -1 0 ]fov视野角度Field of View角度越大可见范围越广。aspectcanvas 宽高比防止画面拉伸。near/far近平面和远平面距离在此范围内的物体才会被渲染。矩阵乘法效果顶点的z坐标被用于控制缩放比例实现“近大远小”。3.2 正交投影Orthographic Projection正交投影无视物体远近在屏幕上保持相同大小。它定义了一个长方体视景体适合精确的 2D 布局、UI 或技术绘图。正交矩阵原理text[ 2/(right-left) 0 0 -(rightleft)/(right-left) ] [ 0 2/(top-bottom) 0 -(topbottom)/(top-bottom) ] [ 0 0 -2/(far-near) -(farnear)/(far-near) ] [ 0 0 0 1 ]参数直接定义左右上下远近的范围物体在此范围内则显示且大小不随距离变化。4.实战透视投影 vs 正交投影同屏对比以下代码在一个页面中左右分屏展示两种投影效果并支持鼠标拖拽同步旋转视角让你直观感受差异。html// 渲染正交投影左侧 const canvas orthoGL.gl.canvas; canvas.width width; canvas.height height; orthoGL.gl.viewport(0, 0, width, height); const view mat4.create(); const camDist 5.0; const cx camDist * Math.sin(rotY) * Math.cos(rotX); const cy camDist * Math.sin(rotX); const cz camDist * Math.cos(rotY) * Math.cos(rotX); mat4.lookAt(view, [cx, cy, cz], [0,0,0], [0,1,0]); const proj mat4.create(); const aspect width / height; let left, right, bottom, top; if (aspect 1) { left -orthoRange * aspect; right orthoRange * aspect; bottom -orthoRange; top orthoRange; } else { left -orthoRange; right orthoRange; bottom -orthoRange / aspect; top orthoRange / aspect; } mat4.ortho(proj, left, right, bottom, top, 0.5, 20); const mvp mat4.create(); mat4.multiply(mvp, proj, view); orthoGL.gl.uniformMatrix4fv(orthoGL.mvpLoc, false, mvp); orthoGL.gl.clearColor(0.08, 0.08, 0.12, 1); orthoGL.gl.clear(orthoGL.gl.COLOR_BUFFER_BIT | orthoGL.gl.DEPTH_BUFFER_BIT); orthoGL.gl.drawArrays(orthoGL.gl.TRIANGLES, 0, 36); // 渲染透视投影右侧 const canvas perspGL.gl.canvas; canvas.width width; canvas.height height; perspGL.gl.viewport(0, 0, width, height); const view mat4.create(); const cx perspDist * Math.sin(rotY) * Math.cos(rotX); const cy perspDist * Math.sin(rotX); const cz perspDist * Math.cos(rotY) * Math.cos(rotX); mat4.lookAt(view, [cx, cy, cz], [0,0,0], [0,1,0]); const proj mat4.create(); const aspect width / height; mat4.perspective(proj, Math.PI / 4, aspect, 0.3, 30); const mvp mat4.create(); mat4.multiply(mvp, proj, view); perspGL.gl.uniformMatrix4fv(perspGL.mvpLoc, false, mvp); perspGL.gl.clearColor(0.08, 0.08, 0.12, 1); perspGL.gl.clear(perspGL.gl.COLOR_BUFFER_BIT | perspGL.gl.DEPTH_BUFFER_BIT); perspGL.gl.drawArrays(perspGL.gl.TRIANGLES, 0, 36);5.正交 vs 透视核心区别一览表对比维度正交投影透视投影视觉效果物体大小不随距离变化无“近大远小”近大远小符合人眼视觉视景体长方体平行投影平截头体锥体被切去顶部平行线始终保持平行在远处交汇于灭点典型用途2D游戏、UI界面、工程制图、CAD3D游戏、虚拟场景、模型展示矩阵函数mat4.ortho(left, right, bottom, top, near, far)mat4.perspective(fov, aspect, near, far)参数含义直接定义可视范围的左右上下边界定义视野角度、宽高比、近远平面6.投影矩阵核心知识点必记MVP 矩阵顺序固定gl_Position 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标顺序不可颠倒。透视投影调节fov越大看到的范围越广物体越小类似广角镜头。aspect必须与 canvas 的宽高比一致否则图形会拉伸。near/far物体必须在两者之间才能显示过近或过远会被裁剪。正交投影调节left/right/bottom/top决定了可视范围的大小范围越大物体在屏幕上显得越小。深度测试必须开启gl.enable(gl.DEPTH_TEST)否则远近遮挡关系会错误。 新手投影避坑指南物体看不见检查物体是否在 near/far 范围内。可以临时将 near 设小、far 设大来测试。画面拉伸透视投影中aspect 必须与 canvas 的宽高比一致并在窗口改变时更新。深度冲突Z-fightingnear/far 范围太大或物体靠太近时表面会闪烁。尽量缩小范围或提高深度缓冲区精度。纹理扭曲WebGL 会自动进行透视校正插值但必须通过varying传递纹理坐标不要手动计算。7.总结投影矩阵是 WebGL 3D 渲染的最后一步决定了视觉效果是“近大远小”还是“保持真实大小”。透视投影通过平截头体实现景深正交投影通过长方体实现精确尺寸。MVP 矩阵的构建顺序至关重要工业级开发推荐使用gl-matrix库。 下期预告投影矩阵学完MVP 矩阵就完整了下期我们将深入光照模型教你如何让物体拥有明暗变化、阴影和高光彻底告别扁平感打造真正逼真的 3D 场景。关注我下期手把手教你用矩阵光照新手也能轻松拿捏