直接用角色位置加固定偏移计算相机位置会穿墙,因其未检测路径障碍;正确做法是先算理想位置,再通过射线反向拉回至最近安全点,并辅以相机碰撞体扫掠测试和动态偏移调整。

为什么直接用角色位置计算相机位置会穿墙
第三人称相机通常基于角色位置和朝向做偏移(比如 cameraPos = playerPos + offset),但这个偏移是固定向量,不考虑中间是否有墙。一旦角色靠近墙壁、柱子或斜坡,相机就可能被“推”到几何体内部,导致穿墙渲染——本质是没做射线检测或体积裁剪。
关键不是“相机要不要动”,而是“相机能合法停留的位置在哪”。真实做法是:先按理想偏移算出目标点,再沿该方向反向“拉回”到可观察的最近安全位置。
用 raycast 检测相机与场景之间的阻挡
主流引擎(Unity/Unreal)提供物理射线检测接口;纯 C++ 游戏若用 Bullet 或 PhysX,也需调用对应 rayTest 或 rayCast。核心逻辑是:从角色位置朝相机理想位置发射一条射线,检查是否击中碰撞体。
- 射线起点必须是角色中心(或肩部/头部等参考点),终点是未修正的相机目标位置
- 忽略角色自身碰撞体(否则总命中自己),可通过
filterGroup或mask排除 - 若命中,取命中点前 0.1~0.3 米作为最终相机位置(留出缓冲,避免贴面抖动)
- 若未命中,直接使用理想位置——说明视野开阔,无需干预
示例伪代码:
立即学习“C++免费学习笔记(深入)”;
vec3 idealPos = playerPos + quat_rotate(playerRot, cameraOffset);
vec3 hitPos;
if (physicsWorld.raycast(playerPos, idealPos, &hitPos)) {
cameraPos = hitPos - normalize(idealPos - playerPos) * 0.2f;
} else {
cameraPos = idealPos;
}为什么不能只靠射线?得加 capsule 或 sphere 碰撞体包裹相机
射线只能防“穿墙看透”,但挡不住“卡进角落”或“被斜坡顶飞”。比如相机被挤在墙角时,射线可能没命中,但相机模型实际已嵌入几何体——此时需要给相机本身赋予一个微小的碰撞体(常为半径 0.1~0.2 的 sphere 或 capsule),并启用其运动学(kinematic)模式。
- 每次设置相机位置前,先用该碰撞体做
sweepTest(扫掠测试):模拟从旧位置移动到新位置的过程,检测路径上是否发生碰撞 - 若扫掠命中,取最短分离向量(MTD)把相机“推离”障碍物,而非粗暴截断
- 注意:此碰撞体仅用于检测,不参与物理响应,也不影响角色运动
容易被忽略的三个细节
一是角色蹲下/攀爬时,cameraOffset 的 Z 分量必须动态缩放,否则射线起点偏低,导致相机被地板“吞掉”;二是多层建筑中,射线需设最大距离(如 5 米),否则穿过天花板打到上层地板,造成误拉回;三是相机旋转(如鼠标拖拽)后,offset 应始终在角色局部空间计算,再转到世界空间——否则绕角色转一圈后,偏移方向会错乱。
真正难的不是实现单次检测,而是让相机在狭窄走廊、楼梯、密集掩体间持续稳定停驻——这要求射线 + 扫掠 + 局部空间偏移三者严格同步,且所有偏移量都带平滑插值,否则会有“咔哒”跳变。



















