提交测试脚本

This commit is contained in:
2026-03-02 00:03:29 +08:00
parent 7712c73be2
commit f07a52f2f0
12 changed files with 1450 additions and 117 deletions

View File

@@ -35,20 +35,12 @@ public class Buoyancy : MonoBehaviour
[Tooltip("When enabled, the net force is applied with a random offset to create an angular velocity.")]
public bool applyForceWithRandomOffset;
[Tooltip("When enabled, the height of the custom mesh is taken into account when fetching water surface height.")]
public bool isWaterSurfaceACustomMesh;
[Tooltip(
"When enabled, a bunch of gizmos will show showing in blue, the position of the sampling for normals, in magenta the computed normal, in green the direction of the deformation force, in red the direction of the current force, and in a yellow sphere, the approximation volume the buoyancy calculations.")]
public bool drawDebug;
private Vector3 currentDirection;
// private Vector3 A;
//
// private Vector3 B;
//
// private Vector3 C;
private Vector3 waterPosition;
@@ -87,83 +79,123 @@ public class Buoyancy : MonoBehaviour
{
if (!_isEnabled)
{
h = (hNormalized = 0f);
h = 0f;
hNormalized = 0f;
rigidbodyComponent.useGravity = true;
return;
}
else if (_water != null)
{
rigidbodyComponent.useGravity = false;
FetchWaterSurfaceData(base.transform.position, out waterPosition, out normal, out currentDirection);
deformationDirection = Vector3.ProjectOnPlane(normal, Vector3.up);
h = Mathf.Clamp(waterPosition.y - (base.transform.position.y - sphereRadiusApproximation), 0f,
2f * sphereRadiusApproximation);
hNormalized = h * 1f / (2f * sphereRadiusApproximation);
float num = MathF.PI * h * h / 3f * (3f * sphereRadiusApproximation - h);
rigidbodyComponent.angularDamping = Mathf.Lerp(overwaterRigidbodyAngularDrag,
underwaterRigidbodyAngularDrag, hNormalized);
Vector3 b = rigidbodyComponent.mass * Physics.gravity;
Vector3 vector = Vector3.Lerp(Physics.gravity, b, hNormalized);
float num2 = 997f;
float num3 = 0.001293f;
// float num4 = 1.81E-05f;
float num4 = 0.0000181f;
float num5 = 0.001f;
float num6 = 0.47f;
Vector3 vector2 = (0f - num2) * num * Physics.gravity;
Vector3 a = MathF.PI * 6f * sphereRadiusApproximation * num4 * -rigidbodyComponent.linearVelocity;
Vector3 b2 = MathF.PI * 6f * sphereRadiusApproximation * num5 * -rigidbodyComponent.linearVelocity;
Vector3 vector3 = Vector3.Lerp(a, b2, hNormalized) * dragMultiplier;
float num7 = Mathf.Lerp(
b: Mathf.Sqrt(2f * rigidbodyComponent.mass * (0f - Physics.gravity.y) /
(num2 * MathF.PI * Mathf.Pow(sphereRadiusApproximation, 2f) * num6)),
a: Mathf.Sqrt(2f * rigidbodyComponent.mass * (0f - Physics.gravity.y) /
(num3 * MathF.PI * Mathf.Pow(sphereRadiusApproximation, 2f) * num6)), t: hNormalized);
Vector3 force = vector + vector2 + vector3;
Vector3 vector4 = (applyForceWithRandomOffset
? (new Vector3(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f),
UnityEngine.Random.Range(-1f, 1f)) * sphereRadiusApproximation / 5f)
: Vector3.zero);
rigidbodyComponent.AddForceAtPosition(force, base.transform.position + vector4, ForceMode.Acceleration);
if (hNormalized > 0f && hNormalized < 1f)
{
Vector3 force2 =
-(Vector3.Dot(rigidbodyComponent.linearVelocity, Physics.gravity.normalized) *
Physics.gravity.normalized) * surfaceTensionDamping;
rigidbodyComponent.AddForce(force2, ForceMode.Acceleration);
rigidbodyComponent.AddForce(deformationDirection * waveForceMultiplier);
rigidbodyComponent.AddForce(currentDirection * currentSpeedMultiplier);
}
if (rigidbodyComponent.linearVelocity.magnitude > num7)
{
rigidbodyComponent.linearVelocity = rigidbodyComponent.linearVelocity.normalized * num7;
}
if (_water == null)
return;
rigidbodyComponent.useGravity = false;
// Cache frequently used values
Vector3 pos = transform.position;
Vector3 velocity = rigidbodyComponent.linearVelocity;
float radius = sphereRadiusApproximation;
float diameter = 2f * radius;
// 1) Sample water surface at current position
FetchWaterSurfaceData(pos, out waterPosition, out normal, out currentDirection);
// Horizontal “wave push” direction derived from surface normal
deformationDirection = Vector3.ProjectOnPlane(normal, Vector3.up);
// 2) Submersion depth of the approximated sphere (0..2R)
float bottomY = pos.y - radius;
h = Mathf.Clamp(waterPosition.y - bottomY, 0f, diameter);
hNormalized = (diameter > 0f) ? (h / diameter) : 0f;
// 3) Submerged volume (spherical cap) V(h) = πh²/3 * (3R - h)
float submergedVolume = MathF.PI * h * h / 3f * (3f * radius - h);
// 4) Angular damping transitions from air to water
rigidbodyComponent.angularDamping = Mathf.Lerp(
overwaterRigidbodyAngularDrag,
underwaterRigidbodyAngularDrag,
hNormalized
);
// 5) Forces (kept identical to your original math/units)
Vector3 gravityAcceleration = Physics.gravity;
// NOTE: this is kept as-is (original mixes accel & force then uses Acceleration mode)
Vector3 weightVector = rigidbodyComponent.mass * gravityAcceleration;
Vector3 gravityTerm = Vector3.Lerp(gravityAcceleration, weightVector, hNormalized);
// Physical constants (as in original)
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;
// Buoyancy: -ρ * V * g
Vector3 buoyancyTerm = (-rhoWater) * submergedVolume * gravityAcceleration;
// Linear viscous drag (Stokes-like): 6πRμ(-v) -> blend air/water by submersion
Vector3 dragAir = MathF.PI * 6f * radius * muAir * (-velocity);
Vector3 dragWater = MathF.PI * 6f * radius * muWater * (-velocity);
Vector3 viscousDragTerm = Vector3.Lerp(dragAir, dragWater, hNormalized) * dragMultiplier;
// Net force (still applied as Acceleration)
Vector3 netAcceleration = gravityTerm + buoyancyTerm + viscousDragTerm;
// Optional random offset to induce angular velocity
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) Extra forces only around the surface transition (0<hN<1)
if (hNormalized > 0f && hNormalized < 1f)
{
Vector3 gravityDir = gravityAcceleration.normalized;
// Surface tension damping: cancels velocity along gravity direction
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) Terminal velocity clamp (same formula, just named)
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)
{
WaterSearchParameters wsp = default(WaterSearchParameters);
WaterSearchResult wsr = default(WaterSearchResult);
wsp.startPositionWS = wsr.candidateLocationWS;
wsp.targetPositionWS = point;
wsp.error = 0.01f;
wsp.maxIterations = 8;
wsp.includeDeformation = includeDeformation;
wsp.outputNormal = true;
positionWS = wsr.candidateLocationWS;
currentDirectionWS = Vector3.zero;
positionWS = Vector3.zero;
normalWS = Vector3.up;
currentDirectionWS = Vector3.right;
if (targetSurface.ProjectPointOnWaterSurface(wsp, out wsr))
{
positionWS = wsr.projectedPositionWS;
currentDirectionWS = wsr.currentDirectionWS;
normalWS = wsr.normalWS;
}
Vector3 vector = (isWaterSurfaceACustomMesh ? (Vector3.up * _water.transform.position.y) : Vector3.zero);
return positionWS + vector;
return point;
}
public Vector3 GetCurrentWaterPosition()
@@ -181,10 +213,6 @@ public class Buoyancy : MonoBehaviour
{
if (drawDebug)
{
// Gizmos.color = Color.blue;
// Gizmos.DrawSphere(A, sphereRadiusApproximation / 10f);
// Gizmos.DrawSphere(B, sphereRadiusApproximation / 10f);
// Gizmos.DrawSphere(C, sphereRadiusApproximation / 10f);
Gizmos.color = Color.magenta;
Gizmos.DrawLine(base.transform.position, base.transform.position + normal);
Gizmos.color = Color.green;