Appearance
为什么一个面要 6 个顶点?
因为每个矩形面由 2 个三角形组成
cpp
// 一个矩形面(比如立方体的前面)的 6 个顶点:
-0.5f, -0.5f, 0.5f, // 左下角 ← 三角形1的顶点1
0.5f, -0.5f, 0.5f, // 右下角 ← 三角形1的顶点2
0.5f, 0.5f, 0.5f, // 右上角 ← 三角形1的顶点3
-0.5f, -0.5f, 0.5f, // 左下角 ← 三角形2的顶点1
0.5f, 0.5f, 0.5f, // 右上角 ← 三角形2的顶点2
-0.5f, 0.5f, 0.5f, // 左上角 ← 三角形2的顶点3视觉化理解
text
一个矩形面 = 2个三角形
矩形4个角:A(左下) B(右下) C(右上) D(左上)
三角形1:A → B → C (覆盖矩形下半部分)
A ┌─────┐ D
│╲ │
│ ╲ │
│ ╲ │
B └─────┘ C
三角形2:A → C → D (覆盖矩形上半部分)
A ┌─────┐ D
│ ╱│
│ ╱ │
│ ╱ │
B └─────┘ C为什么不用 4 个顶点画矩形?
cpp
// 理论上似乎可以用4个顶点:
-0.5f, -0.5f, 0.5f, // 左下
0.5f, -0.5f, 0.5f, // 右下
0.5f, 0.5f, 0.5f, // 右上
-0.5f, 0.5f, 0.5f, // 左上
// 然后告诉 GPU:"用这4个点画个矩形!"但 GPU 说:“对不起,我只会画三角形!”
为什么 GPU 只认三角形?
1) 三角形是“最稳定的几何形状”
text
四边形可以变形: 三角形永远稳定:
┌───┐ ┌───┐
│ │ → 压歪 → │ ╲│
└───┘ └───┘2) 三角形保证“永远在一个平面上”
- 任意 3 个点:一定共面;
- 4 个点:可能不共面(会扭曲)。
3) 计算简单、统一
- 有明确“正面/背面”;
- 光照、纹理、裁剪都简单;
- 所有 3D 模型最终都会被拆成三角形。
在代码中的具体体现
cpp
// 立方体有6个面,每个面2个三角形,每个三角形3个顶点
// → 6面 × 2三角形 × 3顶点 = 36 个顶点
const float verts[] = {
// 前面(+Z面)的6个顶点 = 2个三角形
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
// 后面(-Z面)的6个顶点 = 2个三角形(略)
// ...
};为什么“纸片立方体”只画 6 个顶点?
cpp
// 当立方体在 Z 方向很薄时(厚度 <= 0.02)
const GLsizei drawCount = (c.size[2] <= kSquareEps) ? 6 : 36;
// 纸片立方体:只画前面6个顶点(1个面)
// 正常立方体:画全部36个顶点(6个面)原因:避免“深度冲突”(Z-fighting)
text
纸片立方体的问题:
前面和后面两个面距离太近 ↓
GPU 深度测试时无法区分前后 ↓
两个面交替显示,产生闪烁 ↓
解决方案:只画前面,不画后面三角形绘制的优势
1) 渲染效率高
cpp
glDrawArrays(GL_TRIANGLES, 0, 36); // GPU 硬件对三角形有专项优化2) 几何性质好
- 面积/法向量计算一致;
- 裁剪/剔除算法高效。
3) 行业标准
- 建模软件输出三角网格;
- GPU 针对三角形优化;
- 引擎/图形 API 都以三角形为基本图元。
现实世界的类比
就像用乐高积木搭建复杂模型:
- 🧱 三角形 = 最基本的乐高积木块;
- 🏠 复杂模型 = 许多积木块组合而成;
- 🎨 GPU = 只会用“标准积木”的工人。
你不能给工人“奇怪形状”的积木,必须给标准“三角形积木”!
总结
| 概念 | 解释 | 为什么 |
|---|---|---|
| 6 个顶点/面 | 2 个三角形组成 1 个矩形 | GPU 只懂三角形 |
| 三角形绘制 | 最基本 3D 图元 | 稳定、简单、高效 |
| 纸片优化 | 只画 1 个面(6 顶点) | 避免 Z-fighting 闪烁 |