Unity海盗船无法平滑贴合波浪网格法线旋转问题求助
实现船只平滑贴合波浪的可落地方案
核心问题根源
你当前碰到的旋转跳变,本质是两个原因导致的:
- 仅使用中心点单条射线采样,直接匹配当前三角面的法线,大尺寸三角面的法线是离散值,船移动时跨三角面就会出现跳变
- 旋转没有做平滑过渡,直接赋值当前帧法线对应的旋转量,没有过渡动画
可直接复用的优化方案
1. 多点采样计算目标姿态
放弃单点法线,在船体的船头、船尾、左舷、右舷4个位置分别发射射线采样水面高度,通过4个点的高度差计算船体的目标俯仰和横滚角度,比直接用碰撞法线兼容性更强,也不会受三角面尺寸影响。
2. 增加旋转平滑阻尼
使用Quaternion.Slerp对当前旋转和目标旋转做球面插值,控制平滑系数即可平衡跟随速度和流畅度。
优化后完整代码
// 船体波浪适配脚本 [SerializeField] private LayerMask m_whatIsSea; [SerializeField] private float m_offsetFromWaterSurface; // 新增:四个采样点相对于船体中心点的本地偏移,根据船体实际尺寸调整 [SerializeField] private Vector3 m_bowOffset = new Vector3(0, 0, 2f); // 船头偏移 [SerializeField] private Vector3 m_sternOffset = new Vector3(0, 0, -2f); // 船尾偏移 [SerializeField] private Vector3 m_portOffset = new Vector3(-1f, 0, 0); // 左舷偏移 [SerializeField] private Vector3 m_starboardOffset = new Vector3(1f, 0, 0); // 右舷偏移 [SerializeField] private float m_rotationSmooth = 0.1f; // 旋转平滑系数,值越小越平滑 private void Update() { // 分别采样四个点的水面高度 float bowHeight = GetWaterHeight(transform.TransformPoint(m_bowOffset)); float sternHeight = GetWaterHeight(transform.TransformPoint(m_sternOffset)); float portHeight = GetWaterHeight(transform.TransformPoint(m_portOffset)); float starboardHeight = GetWaterHeight(transform.TransformPoint(m_starboardOffset)); // 计算中心点高度,用于位置更新 float centerHeight = (bowHeight + sternHeight + portHeight + starboardHeight) / 4f; transform.position = new Vector3(transform.position.x, centerHeight + m_offsetFromWaterSurface, transform.position.z); // 计算目标旋转:俯仰角(前后高度差)、横滚角(左右高度差) float pitchAngle = Mathf.Atan2(sternHeight - bowHeight, m_bowOffset.z - m_sternOffset.z) * Mathf.Rad2Deg; float rollAngle = Mathf.Atan2(portHeight - starboardHeight, m_starboardOffset.x - m_portOffset.x) * Mathf.Rad2Deg; Quaternion targetRotation = Quaternion.Euler(pitchAngle, transform.eulerAngles.y, rollAngle); // 平滑过渡旋转 transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, m_rotationSmooth); } // 单独封装采样水面高度的方法 private float GetWaterHeight(Vector3 samplePoint) { RaycastHit hit; // 从采样点上方足够高度向下打射线 if (Physics.Raycast(samplePoint + Vector3.up * Mathf.Abs(m_offsetFromWaterSurface * 4), -Vector3.up, out hit, 100f, m_whatIsSea)) { return hit.point.y; } // 没检测到水面时返回当前高度,避免报错 return transform.position.y - m_offsetFromWaterSurface; }
调试注意事项
- 四个采样点的偏移值要匹配你船体的实际尺寸,不要超出船体的轮廓范围
- 若需要更高的贴合精度,可以新增船身中部的采样点,加权平均计算高度即可
- 如果波浪运动速度很快,可以适当调大
m_rotationSmooth的值,避免旋转延迟过大导致穿模

内容的提问来源于stack exchange,提问作者jazzhar
相关产品推荐
相关产品推荐

