Files
2026-03-04 10:03:45 +08:00

148 lines
7.4 KiB
C#

using System;
using UnityEngine;
namespace AQUAS
{
[AddComponentMenu("AQUAS/Utils/Buoyancy")]
[RequireComponent(typeof(Rigidbody))]
public class AQUAS_Buoyancy : MonoBehaviour
{
public enum debugModes
{
none = 0,
showAffectedFaces = 1,
showForceRepresentation = 2,
showReferenceVolume = 3
}
public float waterLevel;
public float waterDensity;
[Space(5f)]
public bool useBalanceFactor;
public Vector3 balanceFactor;
[Space(20f)]
[Range(0f, 1f)]
public float dynamicSurface = 0.3f;
[Range(1f, 10f)]
public float bounceFrequency = 3f;
[Space(5f)]
[Header("Debugging can be ver performance heavy!")]
public debugModes debug;
private Vector3[] vertices;
private int[] triangles;
private Mesh mesh;
private Rigidbody rb;
private float effWaterDensity;
private float regWaterDensity;
private float maxWaterDensity;
private void Start()
{
mesh = GetComponent<MeshFilter>().mesh;
vertices = mesh.vertices;
triangles = mesh.triangles;
rb = GetComponent<Rigidbody>();
regWaterDensity = waterDensity;
maxWaterDensity = regWaterDensity + regWaterDensity * 0.5f * dynamicSurface;
}
private void FixedUpdate()
{
if (balanceFactor.x < 0.001f)
{
balanceFactor.x = 0.001f;
}
if (balanceFactor.y < 0.001f)
{
balanceFactor.y = 0.001f;
}
if (balanceFactor.z < 0.001f)
{
balanceFactor.z = 0.001f;
}
AddForce();
}
private void Update()
{
regWaterDensity = waterDensity;
maxWaterDensity = regWaterDensity + regWaterDensity * 0.5f * dynamicSurface;
effWaterDensity = (maxWaterDensity - regWaterDensity) / 2f + regWaterDensity + Mathf.Sin(Time.time * bounceFrequency) * (maxWaterDensity - regWaterDensity) / 2f;
}
private void AddForce()
{
for (int i = 0; i < triangles.Length; i += 3)
{
Vector3 vector = vertices[triangles[i]];
Vector3 vector2 = vertices[triangles[i + 1]];
Vector3 vector3 = vertices[triangles[i + 2]];
float num = waterLevel - Center(vector, vector2, vector3).y;
if (num > 0f && Center(vector, vector2, vector3).y > (Center(vector, vector2, vector3) + Normal(vector, vector2, vector3)).y)
{
float y = effWaterDensity * Physics.gravity.y * num * Area(vector, vector2, vector3) * Normal(vector, vector2, vector3).normalized.y;
if (useBalanceFactor)
{
rb.AddForceAtPosition(new Vector3(0f, y, 0f), base.transform.TransformPoint(new Vector3(base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).x / (balanceFactor.x * base.transform.localScale.x * 1000f), base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).y / (balanceFactor.y * base.transform.localScale.x * 1000f), base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).z / (balanceFactor.z * base.transform.localScale.x * 1000f))));
}
else
{
rb.AddForceAtPosition(new Vector3(0f, y, 0f), base.transform.TransformPoint(new Vector3(base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).x, base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).y, base.transform.InverseTransformPoint(Center(vector, vector2, vector3)).z)));
}
if (debug == debugModes.showAffectedFaces)
{
Debug.DrawLine(Center(vector, vector2, vector3), Center(vector, vector2, vector3) + Normal(vector, vector2, vector3), Color.white);
}
if (debug == debugModes.showForceRepresentation)
{
Debug.DrawRay(Center(vector, vector2, vector3), new Vector3(0f, y, 0f), Color.red);
}
if (debug == debugModes.showReferenceVolume)
{
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector).z), new Vector3(base.transform.TransformPoint(vector2).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector2).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector2).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector2).z), new Vector3(base.transform.TransformPoint(vector3).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector3).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector3).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector3).z), new Vector3(base.transform.TransformPoint(vector).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector).x, waterLevel, base.transform.TransformPoint(vector).z), new Vector3(base.transform.TransformPoint(vector2).x, waterLevel, base.transform.TransformPoint(vector2).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector2).x, waterLevel, base.transform.TransformPoint(vector2).z), new Vector3(base.transform.TransformPoint(vector3).x, waterLevel, base.transform.TransformPoint(vector3).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector3).x, waterLevel, base.transform.TransformPoint(vector3).z), new Vector3(base.transform.TransformPoint(vector).x, waterLevel, base.transform.TransformPoint(vector).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector).x, waterLevel, base.transform.TransformPoint(vector).z), new Vector3(base.transform.TransformPoint(vector).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector2).x, waterLevel, base.transform.TransformPoint(vector2).z), new Vector3(base.transform.TransformPoint(vector2).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector2).z), Color.green);
Debug.DrawLine(new Vector3(base.transform.TransformPoint(vector3).x, waterLevel, base.transform.TransformPoint(vector3).z), new Vector3(base.transform.TransformPoint(vector3).x, Center(vector, vector2, vector3).y, base.transform.TransformPoint(vector3).z), Color.green);
}
}
}
}
private Vector3 Center(Vector3 p1, Vector3 p2, Vector3 p3)
{
Vector3 position = (p1 + p2 + p3) / 3f;
return base.transform.TransformPoint(position);
}
private Vector3 Normal(Vector3 p1, Vector3 p2, Vector3 p3)
{
return Vector3.Cross(base.transform.TransformPoint(p2) - base.transform.TransformPoint(p1), base.transform.TransformPoint(p3) - base.transform.TransformPoint(p1)).normalized;
}
private float Area(Vector3 p1, Vector3 p2, Vector3 p3)
{
float num = Vector3.Distance(new Vector3(base.transform.TransformPoint(p1).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p1).z), new Vector3(base.transform.TransformPoint(p2).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p2).z));
float num2 = Vector3.Distance(new Vector3(base.transform.TransformPoint(p3).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p3).z), new Vector3(base.transform.TransformPoint(p1).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p1).z));
return num * num2 * Mathf.Sin(Vector3.Angle(new Vector3(base.transform.TransformPoint(p2).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p2).z) - new Vector3(base.transform.TransformPoint(p1).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p1).z), new Vector3(base.transform.TransformPoint(p3).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p3).z) - new Vector3(base.transform.TransformPoint(p1).x, Center(p1, p2, p3).y, base.transform.TransformPoint(p1).z)) * (MathF.PI / 180f)) / 2f;
}
}
}