Unity中实现物体水面漂浮 解决波浪Shader下浮力计算异常问题
波浪水面船只浮力逻辑修复方案
你当前的问题根源是水面波浪仅在Shader渲染阶段修改了网格顶点位置,并未同步修改Transform或物理层数据,因此原有逻辑无法识别动态水面高度。可通过以下方案实现准确的动态浮力计算:
核心思路
复用Shader中使用的波浪计算逻辑,在C#侧实时计算每个漂浮点对应(x,z)坐标位置的水面高度,替换原有固定的Water.position.y进行浮力判定。
实现代码示例
以下为修改后的Floater脚本,默认适配最常用的多层正弦波波浪效果,你只需将波浪参数调整为和Shader中一致即可:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Floater : MonoBehaviour { public float depthBeforeSubmerged = 1f; public float displacementAmount = 3f; public Transform[] floatPoints; public Transform Water; // 波浪参数,需和Shader内参数完全一致 public float waveAmplitude = 0.5f; // 浪高 public float waveFrequency = 2f; // 浪密度 public float waveSpeed = 1f; // 浪移动速度 private Rigidbody rb; private void Start() { rb = GetComponent<Rigidbody>(); } void FixedUpdate() { foreach (Transform t in floatPoints) { // 计算当前漂浮点对应位置的水面高度 float waterY = GetWaveHeight(t.position.x, t.position.z); if (t.position.y < waterY) { // 用动态水面高度替换原有固定高度计算浮力 float submergeDepth = waterY - t.position.y; float displacementMultiplyer = Mathf.Clamp01(submergeDepth / depthBeforeSubmerged) * displacementAmount; rb.AddForceAtPosition(new Vector3(0f, Mathf.Abs(Physics.gravity.y) * displacementMultiplyer, 0f), t.position,ForceMode.Acceleration); } } } // 波浪高度计算方法,逻辑和Shader内保持完全一致 private float GetWaveHeight(float x, float z) { // 基础正弦波计算,如果你用的是Gerstner波或其他波浪逻辑,替换此处即可 float wave1 = Mathf.Sin(x * waveFrequency + Time.time * waveSpeed) * waveAmplitude; float wave2 = Mathf.Sin(z * waveFrequency * 0.7f + Time.time * waveSpeed * 1.2f) * waveAmplitude * 0.6f; return Water.position.y + wave1 + wave2; } }
可选方案
- 如果你的波浪逻辑非常复杂不想重复写两遍,可以将波浪计算逻辑放到Compute Shader中,同时输出高度数据给渲染管线和C#逻辑层,适合大范围水面、多漂浮物的场景
- 临时测试可以给水面添加Mesh Collider,每帧同步Shader变形后的网格到碰撞体,通过射线检测获取对应位置的水面高度,但性能开销较高,不建议正式版本使用
注意事项
- 所有波浪参数必须和Shader中的参数完全同步,否则会出现浮力计算和水面渲染错位的问题
- 船只漂浮点建议控制在4~16个,足够覆盖中小型船只的浮力模拟,过多会造成不必要的性能损耗
- 如果使用Gerstner波,需要同步计算顶点的横向偏移,避免浪尖位置浮力计算偏差
内容的提问来源于stack exchange,提问作者Eternal hunter
相关产品推荐
相关产品推荐

