Files
Fishing2/Assets/Scripts/Test/Buoyancy.cs
2026-03-01 17:32:12 +08:00

198 lines
7.9 KiB
C#

using System;
using UnityEngine;
using WaveHarmonic.Crest;
[ExecuteInEditMode]
[RequireComponent(typeof(Rigidbody))]
public class Buoyancy : MonoBehaviour
{
// public WaterSurface targetSurface;
public WaterRenderer _water;
public bool includeDeformation = true;
[Tooltip("Approxative radius of object for buoyancy.")]
public float sphereRadiusApproximation = 0.25f;
[Tooltip("Specifies the multiplier for the movement induced by other deformation (waves, swell... etc).")]
public float waveForceMultiplier = 1f;
[Tooltip("Specifies the multiplier for the movement induced by the current of the water surface.")]
public float currentSpeedMultiplier = 1f;
[Tooltip("Specifies the multiplier for the drag forces induced by the viscosity of the mediums.")]
public float dragMultiplier = 1f;
public float defaultRigidbodyDrag = 0.1f;
public float underwaterRigidbodyAngularDrag = 1f;
public float overwaterRigidbodyAngularDrag = 0.05f;
[Tooltip("Specifies the value for surface tension. A high value will stop the object bouncing faster on water.")]
public float surfaceTensionDamping = 10f;
[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;
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(
"The variable '_water' needs a valid Water Surface to be assigned for the script to work properly.");
}
}
public void EnablePhysics(bool set)
{
_isEnabled = set;
}
private void FixedUpdate()
{
if (!_isEnabled)
{
h = (hNormalized = 0f);
rigidbodyComponent.useGravity = true;
}
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;
}
}
}
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;
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;
}
public Vector3 GetCurrentWaterPosition()
{
return waterPosition;
}
public float GetNormalizedHeightOfSphereBelowSurface()
{
return hNormalized;
}
private void OnDrawGizmosSelected()
{
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;
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);
}
}
}