法向量方向的“自由意志“:为什么“约定“重于“绝对“
引子:一个看似"荒谬"的问题
有一天,一位学习图形学的新手,向我提出了一个特别有意思的问题:
“视锥体的6个平面的法向量都指向内部——这不是一个确定的、必然的事实吗?为什么你说这是一个’约定’?为什么可以’自己选择’?”
我愣了一下。
这个问题看似天真——但它直击一个极其深刻的本质。
表面上:视锥体的形状是确定的,边界是确定的,一切好像都是"客观存在"的。
但真的是这样吗?
让我先反问一个问题:一堵墙,它的"法向量"到底指向哪里?
- 朝内?
- 朝外?
你会发现——这个问题没有"客观答案"。墙就是墙,它没有"天然朝向"。
"朝向"是我们赋予它的。
今天,我们就来彻底搞懂:为什么"法向量指向内部"是一个"约定",而不是"绝对真理"?这个看似哲学的问题,背后藏着什么样的工程智慧?
一、几何客体 vs 数学描述
让我们从最根本的地方开始——几何客体和它的数学描述,是两件事。
几何客体:客观存在
"视锥体"作为一个几何形状,它是客观存在的:
- 它有确定的形状(梯形柱)
- 它有确定的位置(相机能看到的空间)
- 它有确定的边界(6个平面)
这些是"事实"——不管你怎么描述它,视锥体就在那里。
就像:一块砖头就是一块砖头——不管你叫它"brick"还是"砖",它的形状和位置都不会变。
数学描述:人为选择
但当我们用"数学"去描述这个几何客体时——描述的方式,是我们选择的。
同一块砖头,可以有很多种描述方式:
- 用"长×宽×高"描述
- 用"8个顶点的坐标"描述
- 用"6个面的方程"描述
- 用"体积和重心"描述
这些描述都能唯一确定这块砖头——但描述本身是"人造的"。
同样地:视锥体作为几何客体是客观的——但"用什么数学方式描述它",是人为的。
“法向量的方向”,就在这个"人为选择"的层面。
二、平面的"双向性":一个哲学问题
让我们聚焦到"平面"这个概念。
问题:一个平面,有几个"法向量方向"?
答案:两个。
想象一块玻璃:
↑ 方向A │ │ │ ══════════╪══════════ 玻璃 │ │ │ ↓ 方向B这块玻璃有两个"法向"方向——A和B。它们相反,但都垂直于玻璃。
问题:哪一个是"法向量"?
答案:都是——或者说,任选一个作为"法向量",都可以。
这就是问题的核心:
一个平面本身,没有"内在的法向量方向"。“哪个方向是法向量”,是一个人为的选择。
这不是随便说的——这是数学上的严格事实。
平面方程Ax+By+Cz+D=0Ax + By + Cz + D = 0Ax+By+Cz+D=0,和−Ax−By−Cz−D=0-Ax - By - Cz - D = 0−Ax−By−Cz−D=0,描述的是同一个平面。
但它们的"法向量"(A,B,C)(A, B, C)(A,B,C)和(−A,−B,−C)(-A, -B, -C)(−A,−B,−C)——方向完全相反。
同一个平面,两种描述,两种法向量方向——两种都是正确的。
三、"约定"从何而来?
既然平面本身没有"天然法向量方向",那我们为什么要"约定"一个?
因为——不约定,就没法做判断。
回忆一下我们上一篇讲的:用ddd值判断点在平面的哪一面:
d=Ax+By+Cz+Dd = Ax + By + Cz + Dd=Ax+By+Cz+D
- d>0d > 0d>0:正面(法向量指向的一侧)
- d<0d < 0d<0:背面
“正面"和"背面"这两个词——它们的含义完全取决于"法向量指向哪里”。
如果法向量指向A方向——A方向就是"正面"
如果法向量指向B方向——B方向就是"正面"
“正面"不是绝对的,是相对的——相对于"我们选择的法向量方向”。
所以:"约定"不是可有可无的——它是"判断能进行"的前提。
没有约定,你无法说"点在平面的哪一面"——因为"哪一面"本身没有意义。
四、视锥体的"约定":两种可能
回到视锥体的6个平面——理论上,每个平面的法向量都有两个可选方向。
这意味着——理论上,视锥体的法向量约定,有26=642^6 = 6426=64种可能!
但实际上,我们只会考虑两种"自洽"的约定:
约定A:全部指向内部
↓ ═══════════ ║ ║ → ║ ║ ← ║ ║ ═══════════ ↑ [相机]6个法向量全部指向视锥体内部。
判断"点在视锥体内"的逻辑:
点在所有6个平面的"正面"(d>0d > 0d>0)
约定B:全部指向外部
↑ ═══════════ ║ ║ ← ║ ║ → ║ ║ ═══════════ ↓ [相机]6个法向量全部指向视锥体外部。
判断"点在视锥体内"的逻辑:
点在所有6个平面的"背面"(d<0d < 0d<0)
两种约定,都能用
关键的洞察:这两种约定,都能正确完成剔除。
它们只是"语言的选择"——就像英语说 “inside”,法语说 “à l’intérieur”,中文说"里面"——描述的是同一件事。
Unity选择"约定A"(法向量朝内),d>0d > 0d>0表示在内。
Unreal选择的具体约定可能不同,但本质上都是从两种可能中选一种。
这就是为什么我说这是"约定"——因为它是从多种自洽方案中,选择了一种作为标准。
五、为什么Unity选"法向量朝内"?
既然两种约定都能用,为什么大多数引擎选择"法向量朝内"?
这背后有三个"选择的理由"——都是工程和直觉上的:
理由1:与"d>0d > 0d>0= 在内"对齐
人类的直觉:“正的” = “好的” = “在里面”。
“在视锥体内 =d>0d > 0d>0”比“在视锥体内 =d<0d < 0d<0”更符合直觉。
如果剔除失败(在外),我们更愿意说"ddd是负的"——“负的 = 不好的 = 被拒绝”。
这是一种"心理上的和谐"。
理由2:与其他凸体判断保持一致
Unity不止有视锥体——还有AABB、OBB、Sphere等凸体。
对于所有这些凸体,Unity都采用"法向量朝内"的约定——这样,所有的"点在内"判断,逻辑完全一致。
统一的约定,减少了程序员的认知负担。
理由3:与"包含关系"的语义一致
“法向量朝内”,天然地表达了"面向物体内部"的语义。
“在视锥体内”,就是"在所有面的’内侧’"——语言上非常自然。
这种"语义一致性",让代码读起来像自然语言:
if(IsInsideAllPlanes(point,frustum))// ...读者一看就懂——因为"约定和语义"完美吻合。
六、举反例:如果Unity选"法向量朝外"
为了更深刻地理解"约定"的价值,我们来想象一下"如果Unity选了另一种约定":
假设Unity选择"法向量朝外":
// 假设的Unity API(法向量朝外)boolIsPointInFrustum(Point p,Frustum f){for(inti=0;i<6;i++){floatd=f.planes[i].DistanceTo(p);if(d>0)returnfalse;// 在法向量方向 = 在外}returntrue;}这段代码:
- ✅完全正确
- ❌反直觉:“d>0d > 0d>0表示在外”?这不奇怪吗?
如果Unity选了这个约定——每一个新手都会疑惑:“为什么正的是外,负的是内?”
这就是"约定选择"的价值——好的约定,降低认知负担。
七、"约定"的哲学:工程学的自由意志
从更高的层面看,“法向量方向的约定”,反映了工程学的一个深刻哲学:
在数学上等价的方案中,选择"最符合人类直觉、最便于工程实现"的那一个。
类似的"约定"无处不在
图形学里,充满了这样的"约定":
约定1:坐标系的手性
- Unity 用左手坐标系
- OpenGL 用右手坐标系
- 数学上都能工作——只是"约定"不同
约定2:矩阵的存储
- OpenGL 用列主序
- DirectX 用行主序
- 本质是同一个矩阵——只是"约定"不同
约定3:三角形的正面
- 顺时针(Clockwise)绕序 = 正面?
- 逆时针(Counter-Clockwise)绕序 = 正面?
- 不同引擎有不同"约定"
约定4:深度值的方向
- 近处 = 0,远处 = 1?
- 近处 = 1,远处 = 0?(“反向深度”)
- 不同API、不同优化目的,采用不同"约定"
约定5:纹理坐标的Y轴
- OpenGL:Y轴向上
- DirectX:Y轴向下
- 同一张图,坐标"约定"相反
这些"约定",都不是"客观真理"——都是"人为选择"。但一旦选定,整个引擎都要围绕它设计。
约定的"锚定效应"
约定一旦确立,就产生"锚定效应"——所有相关的代码、API、文档,都要围绕这个约定展开。
比如:
- Unity 选了"法向量朝内" →所有API返回的Frustum平面,都是法向量朝内的
- Unity 选了"左手坐标系" →所有旋转、变换的方向,都要匹配左手规则
约定不能随便改——因为改一个约定,会撬动整个引擎。
这就是:“约定的力量”——它看似自由,实则约束一切。
八、几何客体不变,数学描述随人
让我们最后总结一下这个深刻的哲学:
┌─────────────────────────────────────┐ │ │ │ 几何客体(视锥体) │ │ ↑ │ │ │ 是客观的、唯一的 │ │ │ │ ├────────┼────────────────────────────┤ │ │ │ │ │ 是人为的、有选择的 │ │ ↓ │ │ 数学描述(平面方程 + 法向量方向) │ │ ↑ │ │ │ │ │ │ 影响 │ │ ↓ │ │ 判断逻辑(d > 0 or d < 0) │ │ │ └─────────────────────────────────────┘视锥体本身:客观、唯一。
用什么方程描述:人为选择。
法向量朝哪里:人为约定。
"正面"和"背面"的定义:由约定决定。
判断代码的写法:跟随约定。
这就是"约定"的层次——它介于"客体"和"代码"之间,起着桥梁的作用。
九、一个绝妙的比喻:地图上的"北"
为了让这个抽象的哲学更具体,让我用一个比喻——地图上的"北"。
地球是一个球——它是客观存在的。它有一个自转轴——两端就是"北极"和"南极"。
但——“哪个极点叫’北极’”?
这是人类的约定!
在地球的物理层面——两个极点是完全对称的——没有一个天然的"北"和"南"。
是我们(人类)选择:
- 让"北"指向某一个特定方向
- 让地图上"上方是北"
- 让指南针的红针指向"北"
这些都是"约定"——但一旦约定确立,全世界的地图、导航、天文,都围绕它建立。
如果外星人来到地球——他们可能会把我们的"北"叫"南"。这不是错误——只是"约定"不同。
视锥体的法向量方向,也是一样的:
几何客体(视锥体)是客观的——就像地球是客观的。
"法向量朝哪里"是人为的——就像"北在哪里"是人为的。
一旦约定确立,整个引擎都要围绕它建立——就像地图和导航系统一样。
十、回答最初的疑问
回到本文开头的问题:
“视锥体的6个平面的法向量都指向内部——这不是一个确定的、必然的事实吗?”
答案是:
"确定"和"必然"的层次要分清:
- “视锥体的形状是确定的”→对(几何客体的性质)
- “法向量指向内部”→不是确定的(这是数学描述的选择)
- “Unity选择了’法向量朝内’的约定”→这是确定的(Unity的具体选择)
- “约定一旦确立,判断逻辑就随之确定”→对(约定的锚定效应)
所以:“法向量指向内部"不是"几何真理”,而是"Unity的工程选择"——它是从多种可能中,选择了一种最符合直觉、最便于实现的方案。
这就是"约定"和"事实"的边界。
结语:约定的智慧
从"平面的两面性",
到"数学描述的自由度",
到"法向量方向的选择",
到"约定的锚定效应"——
我们看到:看似"绝对"的技术细节背后,往往藏着"约定"的自由意志。
约定,不是"真理"——它是"工程学的智慧":
- 它承认"数学的多样性"
- 它选择"最便于人类使用的那一种"
- 它通过"统一"带来"简洁"
- 它通过"锚定"带来"稳定"
Unity选择了"法向量朝内"——这是它的自由。
Unreal可能有别的选择——这也是它的自由。
两者都能做出精彩的画面——只是"约定"不同。
下次当你在图形学里看到某个"看似必然"的技术细节,请多问一句:
“这真的是必然的吗?还是它只是一个’约定’?”
很多时候,你会发现——它其实是"约定"。
而理解"约定",就是理解图形学(乃至整个工程学)的重要一步。
因为工程学的美,不在于"唯一的真理"——而在于"多种可能中,选出最好的那一个,并让所有人围绕它协作"。
这,就是"约定的智慧"。 🎯🌍✨
