跳转至

09-模型与网格:OBJ/GLTF(简化版)加载、法线、切线

目录页:见 OpenGL 教程目录

目标

  • 从“手写顶点数组”升级到“加载模型文件并渲染”
  • 建立 Mesh 的最小工程抽象:顶点格式、索引、材质引用、GPU 资源生命周期
  • 搞清楚法线/切线存在的意义:它们决定光照与法线贴图怎么工作

先决条件


1. 为什么要抽 Mesh:你不想在 main.cpp 里堆 5000 行

当你开始画立方体、画多个物体、加载模型时,代码会迅速变成:

  • “一堆顶点数组 + 一堆 glBind + 一堆 draw”

这会让你无法扩展到:

  • 多个模型
  • 多种顶点格式(有的有 uv,有的有法线)
  • 多材质、多贴图

所以本章最重要的交付,不是“加载某个格式”,而是:

  • 你有一套稳定的 Mesh 数据结构与上传/绘制流程

2. 顶点格式:你至少要包含什么

最小 3D 光照常用的顶点格式:

  • position(vec3)
  • normal(vec3)
  • uv(vec2)

可选但很快会需要:

  • tangent(vec4 或 vec3 + sign):法线贴图需要它

你可以先定义一个 CPU 侧结构(概念示意):

struct Vertex
{
    float px, py, pz;
    float nx, ny, nz;
    float u, v;
};

对应 GPU attribute layout 的 stride/offset 也就确定了。


3. OBJ vs GLTF:怎么选(主线建议)

3.1 OBJ

  • 优点:格式简单、教程多、适合学习几何与法线
  • 缺点:材质/贴图描述能力弱、扩展性差

3.2 GLTF

  • 优点:现代资产交换格式,材质/贴图/动画支持更完整
  • 缺点:解析更复杂(但工具链成熟)

主线建议:

  • 先用 OBJ 把“加载 → 顶点/索引 → 上传 → 渲染”的链路跑通
  • 再用 GLTF 把“材质与贴图组织方式”变成工程化能力

4. 最小 Mesh 抽象(你要的不是框架,是边界清晰)

一个最小 Mesh 至少要表达:

  • CPU 数据:verticesindices
  • GPU 资源:vao/vbo/ebo
  • 绘制参数:索引数量、拓扑类型

行为上至少有两件事:

  • upload():CPU → GPU
  • draw():绑定资源并发起 draw call

当你后面进入多模型/材质时,Mesh 再扩展“材质引用/纹理句柄”即可。


5. 法线:光照计算为什么离不开它

没有法线,你只能做“平面着色”或假光照。

你只需要先掌握两句直觉:

  • 法线是“表面朝向”,决定光从哪个角度打上来
  • 法线必须和位置在同一空间里参与计算(通常在世界空间或视图空间)

后面做光照时,会用到:

  • 法线变换(尤其是有非均匀缩放时)
  • 在 fragment shader 里使用插值后的法线

6. 切线:法线贴图为什么需要它

法线贴图(normal map)存的是“切线空间”的法线,而不是世界空间的法线。

切线空间由三根互相正交的基向量组成:

  • tangent(切线,沿着 UV 的 U 方向)
  • bitangent(副切线,沿着 UV 的 V 方向)
  • normal(法线)

你现在不用马上实现完整 TBN,但要先知道:

  • 没有 tangent,你无法把 normal map 的信息正确转换到世界/视图空间

7. 常见坑

  • 坐标系/单位不一致:模型导入后特别大/特别小/转向奇怪,优先检查导入时的缩放与坐标系约定
  • 法线缺失或错误:光照会看起来像“塑料块”或完全黑
  • 索引绕序不一致:开了 culling 后会缺面
  • 顶点去重策略:一个位置在不同 UV/法线下必须拆成不同顶点,否则会接缝错乱

小练习

练习 1:把立方体抽成一个 Mesh 类

  • 题目:把你之前的立方体顶点/索引从 main.cpp 抽出来,封装 upload/draw
  • 目标:让后续章节可持续扩展

练习 2:加载一个 OBJ 并验证法线

  • 题目:加载一个带法线的 OBJ,并用“法线可视化”方式验证(例如把 normal*0.5+0.5 当颜色输出)
  • 目标:在进入真实光照前先校验数据链路

小结

  • 本章核心是 Mesh 的工程边界:CPU 数据、GPU 资源、upload/draw 行为
  • OBJ 适合先跑通链路,GLTF 适合进入现代资产与材质体系
  • 法线决定基础光照,切线决定法线贴图能否成立

下一篇:见 10-光照基础:Lambert/Phong/Blinn-Phong 与能量直觉