首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
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<Rigidbody>();
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);
}
}
}