using System; using UnityEngine; using WaveHarmonic.Crest; [ExecuteInEditMode] [RequireComponent(typeof(Rigidbody))] public class Buoyancy : MonoBehaviour { // public WaterSurface targetSurface; public WaterRenderer _water; [Tooltip("物体浮力的近似半径")] public float sphereRadiusApproximation = 0.25f; [Tooltip("指定由其他变形(波浪、涌浪等)引起的运动乘数。")] public float waveForceMultiplier = 1f; [Tooltip("指定由水面水流引起的移动的乘数。")] public float currentSpeedMultiplier = 1f; [Tooltip("指定由介质黏性所引起的阻力的乘数。")] public float dragMultiplier = 1f; public float defaultRigidbodyDrag = 0.1f; public float underwaterRigidbodyAngularDrag = 1f; public float overwaterRigidbodyAngularDrag = 0.05f; [Tooltip("指定表面张力的数值。数值过高时,物体在水面上弹跳的速度会减慢。")] public float surfaceTensionDamping = 10f; [Tooltip("启用后,净力会以随机偏移量施加出来,从而产生角速度。")] public bool applyForceWithRandomOffset; [Tooltip("启用调试绘制")] public bool drawDebug; private Vector3 currentDirection; private Vector3 waterPosition; private Vector3 normal; private Vector3 deformationDirection; private Rigidbody rigidbodyComponent; private float h; private float hNormalized; private bool _isEnabled = true; readonly SampleFlowHelper _SampleFlowHelper = new(); private void Start() { rigidbodyComponent = GetComponent(); rigidbodyComponent.useGravity = false; rigidbodyComponent.linearDamping = defaultRigidbodyDrag; if (_water == null) { Debug.LogWarning("没有找到水组件"); } } public void EnablePhysics(bool set) { _isEnabled = set; } private void FixedUpdate() { if (!_isEnabled) { h = 0f; hNormalized = 0f; rigidbodyComponent.useGravity = true; return; } if (_water == null) return; rigidbodyComponent.useGravity = false; // 缓存常用值 Vector3 pos = transform.position; Vector3 velocity = rigidbodyComponent.linearVelocity; float radius = sphereRadiusApproximation; float diameter = 2f * radius; // 1) 当前位置的水面示例图 FetchWaterSurfaceData(pos, out waterPosition, out normal, out currentDirection); // 水平“波浪推动”方向源自表面法线 deformationDirection = Vector3.ProjectOnPlane(normal, Vector3.up); // 2) 近似球体的浸没深度(0 至 2R) float bottomY = pos.y - radius; h = Mathf.Clamp(waterPosition.y - bottomY, 0f, diameter); hNormalized = (diameter > 0f) ? (h / diameter) : 0f; // 3) 浸没体积(球冠形) V(h) = πh²/3 * (3R - h) float submergedVolume = MathF.PI * h * h / 3f * (3f * radius - h); // 4)角向阻尼从空气状态转变为水状态 rigidbodyComponent.angularDamping = Mathf.Lerp( overwaterRigidbodyAngularDrag, underwaterRigidbodyAngularDrag, hNormalized ); // 5) 力(保持与您原始的数学计算/单位一致) Vector3 gravityAcceleration = Physics.gravity; // 注意:保持原样(先将加速度和力相加,然后使用加速度模式) Vector3 weightVector = rigidbodyComponent.mass * gravityAcceleration; Vector3 gravityTerm = Vector3.Lerp(gravityAcceleration, weightVector, hNormalized); // 物理常数(与原文相同) const float rhoWater = 997f; // kg/m^3 const float rhoAir = 0.001293f; // kg/m^3 const float muAir = 0.0000181f; // Pa·s const float muWater = 0.001f; // Pa·s const float dragCoefficient = 0.47f; // 浮力: -ρ * V * g Vector3 buoyancyTerm = (-rhoWater) * submergedVolume * gravityAcceleration; // 线性粘性阻力(类似斯托克斯效应):6πRμ(-v) -> 通过浸入使空气/水混合 Vector3 dragAir = MathF.PI * 6f * radius * muAir * (-velocity); Vector3 dragWater = MathF.PI * 6f * radius * muWater * (-velocity); Vector3 viscousDragTerm = Vector3.Lerp(dragAir, dragWater, hNormalized) * dragMultiplier; // 合力(仍被视为加速度) Vector3 netAcceleration = gravityTerm + buoyancyTerm + viscousDragTerm; // 可选的随机偏移量,用于产生角速度 Vector3 randomOffset = Vector3.zero; if (applyForceWithRandomOffset) { randomOffset = new Vector3( UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f) ) * (radius / 5f); } rigidbodyComponent.AddForceAtPosition( netAcceleration, pos + randomOffset, ForceMode.Acceleration ); // 6) 仅在表面过渡区域(0 < hN < 1)存在额外的力作用。 if (hNormalized > 0f && hNormalized < 1f) { Vector3 gravityDir = gravityAcceleration.normalized; // 表面张力阻尼:抵消沿重力方向的速度 Vector3 verticalVelocity = Vector3.Dot(velocity, gravityDir) * gravityDir; Vector3 surfaceTensionAccel = -verticalVelocity * surfaceTensionDamping; rigidbodyComponent.AddForce(surfaceTensionAccel, ForceMode.Acceleration); rigidbodyComponent.AddForce(deformationDirection * waveForceMultiplier, ForceMode.Acceleration); rigidbodyComponent.AddForce(currentDirection * currentSpeedMultiplier, ForceMode.Acceleration); } // 7) 终端速度夹具(公式相同,只是命名不同) float area = MathF.PI * radius * radius; float g = -gravityAcceleration.y; // positive value float terminalVelocityInAir = Mathf.Sqrt(2f * rigidbodyComponent.mass * g / (rhoAir * area * dragCoefficient)); float terminalVelocityInWater = Mathf.Sqrt(2f * rigidbodyComponent.mass * g / (rhoWater * area * dragCoefficient)); float terminalVelocity = Mathf.Lerp(terminalVelocityInAir, terminalVelocityInWater, hNormalized); float speed = rigidbodyComponent.linearVelocity.magnitude; if (speed > terminalVelocity && speed > 1e-6f) { rigidbodyComponent.linearVelocity = rigidbodyComponent.linearVelocity / speed * terminalVelocity; } } private Vector3 FetchWaterSurfaceData(Vector3 point, out Vector3 positionWS, out Vector3 normalWS, out Vector3 currentDirectionWS) { currentDirectionWS = Vector3.zero; positionWS = Vector3.zero; normalWS = Vector3.up; return point; } public Vector3 GetCurrentWaterPosition() { return waterPosition; } public float GetNormalizedHeightOfSphereBelowSurface() { return hNormalized; } private void OnDrawGizmosSelected() { if (drawDebug) { Gizmos.color = Color.magenta; Gizmos.DrawLine(base.transform.position, base.transform.position + normal); Gizmos.color = Color.green; Gizmos.DrawLine(base.transform.position, base.transform.position + deformationDirection * 10f); Gizmos.color = Color.red; Gizmos.DrawLine(base.transform.position, base.transform.position + currentDirection); Gizmos.color = Color.yellow; Gizmos.DrawSphere(base.transform.position, sphereRadiusApproximation); // 绘制 Rigidbody 的重心点位 Vector3 centerOfMassWorld = transform.TransformPoint(rigidbodyComponent != null ? rigidbodyComponent.centerOfMass : Vector3.zero); Gizmos.color = Color.cyan; Gizmos.DrawSphere(centerOfMassWorld, 0.1f); Gizmos.DrawLine(centerOfMassWorld, centerOfMassWorld + Vector3.up * 0.5f); } } }