相机碰撞检测须用射线定位障碍物位置,unity用physics.raycast、unreal用linetracesinglebychannel、自研引擎调用对应接口;射线起点为相机实际位置(需transformpoint),方向为归一化forward;检测距离设为视野深度1.2–1.5倍;命中后以mathf.smoothdamp插值推进至命中点减安全余量处,currentvelocity须为成员变量,smoothtime取0.1–0.3秒;需覆盖动态物体图层、禁用istrigger,并考虑spherecast或包围盒优化性能。

相机碰撞检测要用射线而非固定距离
直接增加 camera.position.z 会导致穿模或突兀跳变,真正要解决的是“障碍物在哪”——得用射线从相机位置朝前发射,查最近的可碰撞物体。Unity 中用 Physics.Raycast,Unreal 用 LineTraceSingleByChannel,自研引擎则需调用你自己的碰撞检测接口(比如 world->raycast(origin, direction, maxDistance))。关键不是“推多远”,而是“推到哪刚好不穿墙”。
- 射线起点必须是相机实际位置,不是
transform.position(若相机有父节点偏移,需用transform.TransformPoint(Vector3.zero)) - 方向必须是相机本地
forward向量,且归一化(camera.transform.forward.normalized),否则距离计算失准 - 最大检测距离建议设为当前视野深度的 1.2–1.5 倍,太小会漏检近处凸起,太大拖慢性能
平滑推进得靠插值,不是每帧加固定值
检测到障碍物后,目标距离 = 射线命中点距离 − 安全余量(如 0.1f)。但直接赋值会导致镜头“咔”一下拉近。必须用插值过渡:用 Vector3.Lerp 或 Mathf.SmoothDamp(推荐后者,它带速度记忆,更自然)。
-
Mathf.SmoothDamp的currentVelocity必须是成员变量(不能每次新建),否则失去缓动惯性 - 时间常数
smoothTime建议设在 0.1–0.3 秒之间:太小像抖动,太大响应迟钝 - 不要对
camera.transform.localPosition.z插值——若相机挂载在角色上,应插值其相对于父节点的localPosition,否则世界坐标插值会受父节点旋转干扰
常见错误:忽略动态物体与层级掩码
很多项目只检测静态几何体,结果玩家举起盾牌、NPC 突然走近时镜头照样穿过去。错误日志里常看到 Raycast hit nothing 却仍有穿模,大概率是射线没打中动态物体。
- 确保障碍物 Collider 的
isTrigger为false(触发器默认不参与物理射线) - 检查射线的
layerMask是否包含障碍物所在图层(Unity)或ECollisionChannel是否设为ECC_WorldStatic | ECC_WorldDynamic(Unreal) - 若用自研引擎,确认你的射线检测函数是否默认跳过运动中的刚体——有些实现为性能默认忽略
dynamic类型,需显式开启
性能敏感点:避免每帧全场景射线
在开放世界或密集场景里,每帧从相机发一条射线没问题;但若同时处理多个相机(分屏、监控视角),或在 VR 中每眼都射,开销会陡增。这时得做裁剪。
- 加一个简单距离剔除:若相机与上一帧命中点距离 > 2 米,才重新射线;否则沿用上一帧结果并微调
- 用
Physics.SphereCast替代Raycast(Unity),模拟镜头“体积”,提前拦住窄缝或细杆类障碍,减少误穿 - 如果障碍物是规则网格(如围墙、栅栏),可预生成简化包围盒,射线先打包围盒再细分,比直接打原始 Mesh 快一个数量级
currentVelocity 声明在函数内,插值就退化成硬切。这两个点不调准,平滑就是假象。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











