摘要
二面角是指两平面相交时在交线处形成的夹角,通常通过两平面的法向量计算。平面夹角则是二面角的最小值。二面角在游戏中有广泛应用,如角色与地形的接触角度、物体碰撞反弹、光照与阴影计算、模型拼接与动画、AI视野判断等。例如,角色在斜坡上行走时,脚底与地面的夹角决定了是否打滑或摔倒;光照计算中,光线与物体表面的夹角影响亮度和阴影。通过计算法向量的夹角,可以判断角色能否站稳、物体反弹方向、光照强度等。二面角的计算和运用在游戏开发中至关重要,直接影响游戏的真实感和互动性。
一、什么是二面角和平面夹角?
1. 二面角
生活比喻:
想象你打开一本书,书的两页就是两个平面,书脊就是它们的交线。你把书打开的角度,就是这两个平面之间的“二面角”。
数学定义:
二面角是指两平面相交时,在交线处形成的夹角。
通常用两平面的法向量(垂直于平面的向量)来计算。
2. 平面夹角
其实“平面夹角”就是“二面角”的另一种说法,通常指的是两个平面之间的最小夹角。
二、二面角的形象理解
- 交线:两平面相交的那条线(比如书脊)。
- 夹角:两平面在交线处张开的角度(比如书打开的角度)。
图示:
/|
/ | ← 平面1
/ |
/___|________
|\
| \
| \ ← 平面2
| \
- 交线是竖直的那条线
- 二面角是两平面在交线处张开的角
三、二面角的计算方法
假设两个平面的法向量分别为 n₁ 和 n₂,二面角 θ 的余弦值为:
[
\cos\theta = \frac{|\mathbf{n}_1 \cdot \mathbf{n}_2|}{|\mathbf{n}_1||\mathbf{n}_2|}
]
- 取绝对值是因为二面角取最小的那个角(0~90°)。
四、游戏中的实际应用
1. 角色与地形的接触角度
- 场景:角色在斜坡上行走,判断角色脚底平面与地面的夹角,决定是否打滑、摔倒或能否站立。
- 应用:用二面角判断角色是否能在某个坡度上站稳。
2. 物体碰撞反弹
- 场景:小球撞到墙面,反弹方向取决于入射方向和平面法线的夹角。
- 应用:用平面夹角计算反弹方向和速度。
3. 光照与阴影计算
- 场景:光线照射到物体表面,光线方向与表面法线的夹角决定了亮度和阴影。
- 应用:用夹角计算光照强度(如漫反射公式)。
4. 模型拼接与动画
- 场景:3D建模时,判断两个面之间的夹角,决定是否需要平滑过渡或加上折痕。
- 应用:用二面角判断模型表面是否“锐利”或“平滑”。
5. AI视野判断
- 场景:AI判断玩家是否在自己视野范围内,视线与某个平面的夹角小于一定值才算“看到”。
- 应用:用夹角判断目标是否在视野锥体内。
五、生活化口诀
“二面角,像书脊,
平面夹角最小值;
游戏世界常用它,
碰撞光照全靠你。”
六、简单代码示例
import numpy as np
def dihedral_angle(n1, n2):
# n1, n2: 两个平面的法向量
cos_theta = np.abs(np.dot(n1, n2)) / (np.linalg.norm(n1) * np.linalg.norm(n2))
theta = np.arccos(cos_theta)
return np.degrees(theta) # 返回角度值
七、总结
- 二面角/平面夹角:描述两个平面之间的“张开”程度。
- 游戏应用:角色站立、碰撞反弹、光照阴影、模型拼接、AI视野等都离不开它。
- 本质:用法向量的夹角来衡量两个平面之间的关系。
我们用生动形象的方式,详细讲解“角色与地形的接触角度”这个案例,并结合游戏实际应用、原理、实现方法和常见细节。
一、生活比喻
想象你在爬山:
- 地面很平,你可以轻松站稳。
- 地面有点斜,你还能走,但会觉得费力。
- 地面很陡,你就站不住了,容易滑倒。
这就是“脚底和地面之间的夹角”在起作用!
二、游戏场景举例
-
平台跳跃游戏
角色落在不同坡度的平台上,决定能否站稳、是否滑落。 -
开放世界游戏
角色在山坡、悬崖、屋顶等复杂地形上行走,判断能否攀爬、滑行或摔倒。 -
赛车游戏
车辆在斜坡上行驶,判断是否打滑、翻车。
三、原理解析
1. 角色脚底的“法向量”
- 角色脚底有一个“朝上的方向”,通常就是**(0,1,0)**,即Y轴正方向。
2. 地形表面的“法向量”
- 地形每个三角面都有自己的法向量,表示这个面的“朝上”方向。
3. 夹角的计算
四、实际应用流程
1. 检测角色脚下的地形
- 用射线(Raycast)从角色脚底向下发射,检测碰到的地形面。
2. 获取地形法向量
- 得到碰撞点所在三角面的法向量。
3. 计算夹角
- 角色脚底法向量通常为(0,1,0)。
- 计算夹角θ。
4. 判断能否站立
- 设定一个最大可站立角度(如45°)。
- 如果θ < 45°,角色可以站稳。
- 如果θ ≥ 45°,角色会滑落或无法站立。
五、伪代码示例
import numpy as np
def can_stand_on_surface(surface_normal, max_angle=45):
up = np.array([0, 1, 0]) # 角色脚底法向量
cos_theta = np.dot(up, surface_normal) / (np.linalg.norm(up) * np.linalg.norm(surface_normal))
theta = np.degrees(np.arccos(cos_theta))
return theta < max_angle
# 假设检测到地形法向量为(0.5, 0.866, 0)
surface_normal = np.array([0.5, 0.866, 0])
if can_stand_on_surface(surface_normal):
print("角色可以站稳")
else:
print("角色会滑落")
六、游戏中的细节与扩展
-
动态调整角色动画
- 站在斜坡上时,角色身体会自动倾斜,脚贴合地面。
-
滑落与攀爬机制
- 超过最大夹角时,角色自动滑落或进入攀爬状态。
-
不同角色/载具有不同的最大可站立角度
- 比如蜘蛛可以在更陡的坡上行走,普通人不行。
-
地形材质影响
- 冰面、泥地等材质,最大可站立角度会更小。
七、形象图示
角色脚底法向量 ↑
|
| /
| /
| /
地形法向量 /|
/ |
/ |
/ |
/ |
- 两个向量之间的夹角就是接触角度。
八、口诀总结
“脚底法线对地面,
夹角大小定站稳;
小于阈值能站立,
大于阈值就滑行。”
九、实际效果
- 角色在平地、缓坡上自由移动。
- 角色在陡坡上自动滑落或无法站立。
- 角色在不同地形上有不同的移动体验,增加真实感和挑战性。
我们继续用生动形象的方式,详细讲解“光照与阴影计算”中二面角/平面夹角的应用,结合游戏实际场景、原理、实现方法和常见细节。
一、生活比喻
想象你在阳光下:
- 当太阳直射你的头顶,你的影子最短,身上最亮。
- 当太阳斜着照过来,你的影子变长,身上变暗。
- 如果太阳在你背后,你的正面就完全在阴影里。
这就是光线与物体表面夹角在起作用!
二、游戏场景举例
-
角色在阳光下移动
角色身上的亮度和影子的方向随太阳位置变化。 -
3D场景中的物体投影
建筑、树木等物体根据光源方向投下不同形状和长度的阴影。 -
手电筒、火把等点光源照亮场景
物体表面朝向光源的部分更亮,背光面更暗。
三、原理解析
1. 表面法向量
- 每个三角面(或像素)都有一个“法向量”,表示表面朝向。
2. 光线方向
- 光源(如太阳、手电筒)有一个“入射方向”向量。
四、实际应用流程
1. 获取表面法向量
- 对每个三角面、每个像素(像素级称为“逐像素光照”)计算法向量。
2. 获取光线方向
- 对于定向光(如太阳),方向是固定的。
- 对于点光源(如火把),方向是“光源到表面”的向量。
3. 计算夹角
- 用点积公式计算cosθ。
4. 计算亮度
- 亮度 = max(0, n · l) × 光源强度 × 材质反射率
5. 判断阴影
- 如果表面被其他物体挡住(光线被遮挡),则处于阴影中,亮度为0或很低。
五、伪代码示例
import numpy as np
def compute_lighting(normal, light_dir, light_intensity=1.0, albedo=1.0):
# normal: 表面法向量
# light_dir: 指向表面的光线方向(需归一化)
# light_intensity: 光源强度
# albedo: 材质反射率
n = normal / np.linalg.norm(normal)
l = light_dir / np.linalg.norm(light_dir)
cos_theta = np.dot(n, l)
brightness = max(0, cos_theta) * light_intensity * albedo
return brightness
# 例子:法向量(0,1,0),光线方向(0.5,0.866,0)
normal = np.array([0, 1, 0])
light_dir = np.array([0.5, 0.866, 0])
print("亮度:", compute_lighting(normal, light_dir))
六、游戏中的细节与扩展
-
实时阴影(Shadow Mapping)
- 判断光线是否被其他物体遮挡,决定是否处于阴影中。
-
多光源叠加
- 多个光源时,分别计算每个光源的亮度再相加。
-
高光反射(Specular)
- 除了漫反射,还可以根据视线与反射方向的夹角计算高光。
-
法线贴图(Normal Map)
- 用贴图模拟更细致的表面法线,提升光照细节。
-
环境光(Ambient Light)
- 即使在阴影中,也有微弱的环境光,避免完全黑暗。