点乘符号直接反映向量朝向关系:dot>0为锐角(同向),dot==0为正交,dot

点乘结果的正负号直接反映朝向关系
两个单位向量的点乘值在 [-1, 1] 范围内,符号本身就能快速判断相对朝向:dot > 0 表示夹角小于 90°(大致“朝向相同”),dot == 0 是正交,dot 表示夹角大于 90°(存在“背向”成分)。注意:这不是“面向/背向”的绝对判定,而是对两向量方向一致性的量化——比如一个角色朝向向量和它视野锥方向向量点乘为 0.8,说明视线基本对准目标;若为 -0.9,则目标大概率在背后。
常见错误是直接拿原始位置差向量做点乘而不归一化。此时点乘结果受距离影响,无法反映纯角度关系。必须先标准化:
vec3 a = normalize(dirA); // 如角色前向 vec3 b = normalize(dirB); // 如目标相对于角色的位置向量 float dot = dot(a, b); // GLM 或自定义 dot 函数
用 acosf 算夹角要注意输入范围与单位
acosf 只接受 [-1, 1] 输入,但浮点误差可能导致 dot 略微超出该范围(如 1.0000001),直接传入会返回 NaN。必须截断:
- 用
clamp(dot, -1.0f, 1.0f)(GLM)或手动dot = fmaxf(-1.0f, fminf(1.0f, dot)) - 返回值是弧度,要转角度需乘
180.0f / M_PI(C++20 可用std::numbers::pi_v<float></float>) - 若只关心是否在某个角度阈值内(如 60° 视野),优先比较
dot >= cosf(60 * M_PI / 180),避免调用acosf的开销和精度问题
实际场景中别忘了参考系一致性
点乘对坐标系极其敏感。常见坑:
立即学习“C++免费学习笔记(深入)”;
- 角色朝向是世界空间向量,但目标位置差算的是局部空间(如没用
inverse(modelMatrix) * worldPos转换),点乘结果无意义 - 引擎中 Y 轴可能向上或向前(如 Unity Y-up,Unreal Z-forward),导致
forward向量定义不同,点乘前务必确认两向量在同一坐标系、同一起点(通常都以物体自身原点为起点) - 摄像机朝向常用
lookAt构造,其front向量通常是normalize(target - eye),而角色朝向可能是模型自身的+Z轴——二者方向约定不一致时需统一(例如都转成世界空间的单位前向)
性能与精度取舍:整数角度比较比 acosf 更快更稳
游戏逻辑里极少需要精确到 0.1° 的夹角,多数是“是否在 45° 内”“是否背向(>135°)”这类判断。此时应避免 acosf:
- 计算
cosf(threshold_rad)一次,存为常量(如cosf(45 * M_PI / 180) ≈ 0.7071f) - 直接比较
dot >= 0.7071f判断是否在 45° 内 - 背向判断用
dot (对应 135°) - 这省去反三角函数、避免 NaN 风险、且 CPU 指令更少——在每帧处理数百个 AI 视野检测时差异明显
真正需要角度数值的场合(如 UI 显示、平滑旋转插值)才用 acosf,且务必加 clamp。


















