3. 3D图形学核心概念

在嵌入式3D可视化界面开发中,无论你使用 OpenGL ES、Vulkan、DirectFB 还是轻量级软件渲染器,屏幕上的每一个像素最终都由同一套数学管线推导而来。这套管线的骨架就是:坐标系定义“在哪里”,向量描述“方向和位移”,矩阵把变换打包成可复用的算子,模型变换、视图变换、投影则把物体从自己的局部空间一步步送到裁剪空间。理解这条链路,是排查“模型不见了”“画面倒置”“深度错乱”等问题的前提。

一、坐标系:从局部空间到屏幕空间

3D 渲染中常见的坐标系有五个层次,每个层次都有明确的语义和取值范围:

  • 局部空间(Local/Object Space):建模工具导出的顶点原始坐标,原点通常在模型中心或脚底,单位可以是米、毫米或任意单位。
  • 世界空间(World Space):把模型摆放到场景中的统一坐标系,所有物体共享同一原点和轴向。
  • 视图空间(View/Eye Space):以摄像机为原点,摄像机看向 -Z(OpenGL 约定)或 +Z(部分引擎约定)。
  • 裁剪空间(Clip Space):经过投影矩阵后得到的齐次坐标,满足 -w ≤ x,y,z ≤ w 的顶点才会被保留。
  • 屏幕空间(Screen Space):透视除法与视口变换后得到的像素坐标,y 轴方向由视口配置决定。

嵌入式平台常见的一个坑是坐标系手性不一致:OpenGL 使用右手系,而某些传感器、CAD 数据或 Vulkan 的 NDC 深度范围是 [0,1] 而非 [-1,1]。如果直接混用,会出现模型镜像、深度测试失效等问题。

二、向量:位置、方向与法线的载体

向量在图形学中承担三类角色:位置(点)、方向(单位向量)、法线(用于光照)。核心运算包括:

  • 点积:判断夹角、计算漫反射光照强度、做背面剔除。
  • 叉积:由两条边求三角形法线,或构建正交基。
  • 归一化:光照计算前必须把法线和方向向量单位化,否则亮度会随长度缩放。
在嵌入式 GPU 上,向量运算通常由顶点着色器并行完成。若在 CPU 端做大量向量计算(如碰撞检测),应优先使用 SIMD 或定点数,避免浮点性能瓶颈。

三、矩阵:把变换打包成 4×4 算子

3D 图形学使用 4×4 齐次矩阵统一表示平移、旋转、缩放。齐次坐标的第四个分量 w 让平移也能写成矩阵乘法,从而把多个变换合并为一个矩阵。常见的组合顺序是:

MVP = Projection × View × Model
// 顶点最终位置
gl_Position = MVP * vec4(position, 1.0);

矩阵乘法不满足交换律,因此顺序至关重要。先缩放、再旋转、最后平移,与先平移再旋转的结果完全不同。嵌入式开发中,建议在 CPU 端预计算 MVP 并作为 uniform 传入,避免在着色器里重复相乘。

四、模型变换、视图变换与投影

这三者构成了从物体到屏幕的完整链路,下图展示了顶点在各级坐标系之间的流转关系与关键矩阵:

顶点变换管线:从局部空间到屏幕空间 局部空间 Local / Object 世界空间 World 视图空间 View / Eye 裁剪空间 Clip Model View Projection 屏幕空间 Screen 透视除法 + 视口 关键矩阵与作用 Model:平移/旋转/缩放,把模型摆到世界空间 View:由摄像机位置与朝向构建,把世界变换到摄像机前方 Projection:透视/正交,把视锥体映射到裁剪空间 Viewport:把 NDC 映射到实际像素区域,处理 y 轴方向 MVP 组合 P × V × M × v 顺序不可交换

模型变换负责把物体从局部空间搬到世界空间;视图变换把世界空间搬到以摄像机为原点的视图空间;投影变换则把视锥体压缩到裁剪空间。三者相乘得到 MVP 矩阵,是顶点着色器中最常见的 uniform。

五、典型场景与参数对照

以嵌入式车载仪表盘为例:一个转速表指针模型需要绕自身 Z 轴旋转,同时整体仪表盘要摆放在屏幕中央偏下位置。此时模型变换包含“指针自转 + 仪表盘平移”,视图变换由固定的正交摄像机决定,投影使用正交投影以保证 UI 元素不产生透视变形。下表列出常见参数配置:

变换阶段 输入空间 输出空间 典型参数 嵌入式注意点
模型变换 局部空间 世界空间 平移、旋转角、缩放因子 避免每帧重建矩阵,可缓存
视图变换 世界空间 视图空间 摄像机位置、朝向、上向量 用 lookAt 构建,注意手性
投影变换 视图空间 裁剪空间 FOV、宽高比、近远裁剪面 近裁剪面不宜过小,防止深度精度不足
视口变换 NDC 屏幕空间 视口 x/y/w/h 处理 y 轴翻转与 DPI 缩放

六、常见误区与排查思路

误区一:矩阵乘法顺序写反。把 P × V × M 写成 M × V × P,模型会飞到屏幕外或完全不可见。排查时先单独输出 M、V、P 矩阵,确认每个矩阵的平移分量是否落在预期位置。

误区二:法线矩阵直接用模型矩阵。当模型存在非均匀缩放时,法线会被拉斜,光照出现错误。正确做法是使用模型矩阵左上角 3×3 的逆转置矩阵。

误区三:忽略 w 分量。在裁剪空间判断可见性时,必须用 -w ≤ x,y,z ≤ w,而不是直接比较 x、y、z 与 ±1。透视除法之前,w 可能为负,表示顶点在摄像机后方。

误区四:深度范围不匹配。OpenGL 的 NDC 深度是 [-1,1],Vulkan 是 [0,1]。移植渲染代码时若忘记调整投影矩阵,会出现深度测试全部失败或全部通过。

建议在嵌入式调试阶段加入一个“坐标轴可视化”开关:在世界空间绘制红绿蓝三色线段表示 X/Y/Z 轴,并叠加一个单位立方体。当模型位置异常时,先确认坐标轴方向是否正确,再逐级检查 M、V、P 矩阵,通常能快速定位问题所在。

核心记忆点:模型变换摆物体,视图变换摆摄像机,投影变换定视锥,视口变换落像素。四步顺序固定,矩阵从右向左作用于顶点。掌握这条链路,就掌握了 3D 渲染管线的数学主干。