Files
2024-12-18 15:25:43 +01:00

307 lines
9.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class RamBuoyancy : MonoBehaviour
{
public float buoyancy = 30;
public float viscosity = 2;
public float viscosityAngular = 0.4f;
public LayerMask layer = 16;
public new Collider collider;
[Range(2, 10)]
public int pointsInAxis = 2;
new Rigidbody rigidbody;
static RamSpline[] ramSplines;
static LakePolygon[] lakePolygons;
public List<Vector3> volumePoints = new List<Vector3>();
public bool autoGenerateVolumePoints = true;
Vector3[] volumePointsMatrix;
Vector3 lowestPoint;
Vector3 center = Vector3.zero;
public bool debug = false;
void Start()
{
rigidbody = GetComponent<Rigidbody>();
if (ramSplines == null)
ramSplines = FindObjectsOfType<RamSpline>();
if (lakePolygons == null)
lakePolygons = FindObjectsOfType<LakePolygon>();
if (collider == null)
collider = GetComponent<Collider>();
if (collider == null)
{
Debug.LogError("Buoyancy doesn't have collider");
this.enabled = false;
return;
}
if (autoGenerateVolumePoints)
{
Vector3 size = collider.bounds.size;
Vector3 min = collider.bounds.min;
Vector3 step = new Vector3(size.x / (float)pointsInAxis, size.y / (float)pointsInAxis, size.z / (float)pointsInAxis);
for (int x = 0; x <= pointsInAxis; x++)
{
for (int y = 0; y <= pointsInAxis; y++)
{
for (int z = 0; z <= pointsInAxis; z++)
{
Vector3 vertice = new Vector3(min.x + x * step.x, min.y + y * step.y, min.z + z * step.z);
Vector3 closestPoint = collider.ClosestPoint(vertice);
//Debug.DrawLine(closestPoint, vertice, Color.red, 50);
// Debug.Log(Vector3.Distance(closestPoint, vertice));
if (Vector3.Distance(closestPoint, vertice) < float.Epsilon)
{
// Debug.Log(vertice);
volumePoints.Add(transform.InverseTransformPoint(vertice));
}
}
}
}
}
volumePointsMatrix = new Vector3[volumePoints.Count];
}
private void FixedUpdate()
{
WaterPhysics();
}
public void WaterPhysics()
{
if (volumePoints.Count == 0)
{
Debug.Log("Not initiated Buoyancy");
return;
}
Ray ray = new Ray();
ray.direction = Vector3.up;
RaycastHit hit;
bool backFace = Physics.queriesHitBackfaces;
Physics.queriesHitBackfaces = true;
var thisMatrix = transform.localToWorldMatrix;
lowestPoint = volumePoints[0];
float minY = float.MaxValue;
for (int i = 0; i < volumePoints.Count; i++)
{
volumePointsMatrix[i] = thisMatrix.MultiplyPoint3x4(volumePoints[i]);
if (minY > volumePointsMatrix[i].y)
{
lowestPoint = volumePointsMatrix[i];
minY = lowestPoint.y;
}
}
ray.origin = lowestPoint;
center = Vector3.zero;
if (Physics.Raycast(ray, out hit, 100, layer))
{
float width = Mathf.Max(collider.bounds.size.x, collider.bounds.size.z);
int verticesCount = 0;
Vector3 velocity = rigidbody.linearVelocity;
Vector3 velocityDirection = velocity.normalized;
minY = hit.point.y;
for (int i = 0; i < volumePointsMatrix.Length; i++)
{
if (volumePointsMatrix[i].y <= minY)
{
center += volumePointsMatrix[i];
verticesCount++;
}
}
center /= verticesCount;
//Debug.Log(minY - center.y);
rigidbody.AddForceAtPosition(Vector3.up * buoyancy * (minY - center.y), center);
rigidbody.AddForce(velocity * -1 * viscosity);
if (velocity.magnitude > 0.01f)
{
Vector3 v1 = Vector3.Cross(velocity, new Vector3(1, 1, 1)).normalized;
Vector3 v2 = Vector3.Cross(velocity, v1).normalized;
Vector3 pointFront = velocity.normalized * 10;
Ray rayCollider;
//int test = 0;
RaycastHit hitCollider;
foreach (var item in volumePointsMatrix)
{
Vector3 start = pointFront + item;
rayCollider = new Ray(start, -velocityDirection);
//Debug.Log(start + " " + v1 + " " + v2);
//Debug.DrawRay(start, -velocityDirection * 50, Color.cyan);
if (collider.Raycast(rayCollider, out hitCollider, 50))
{
Vector3 pointVelocity = rigidbody.GetPointVelocity(hitCollider.point);
rigidbody.AddForceAtPosition(-pointVelocity * viscosityAngular, hitCollider.point);
//Debug.Log(hitCollider.point);
if (debug)
Debug.DrawRay(hitCollider.point, -pointVelocity * viscosityAngular, Color.red, 0.1f);
}
}
//verticesMatrix
//for (float x = -width; x < width; x += width * 0.1f)
//{
// for (float y = -width; y < width; y += width * 0.1f)
// {
// test++;
// Vector3 start = pointFront + (v1 * x) + (v2 * y);
// rayCollider = new Ray(start, -velocityDirection);
// //Debug.Log(start + " " + v1 + " " + v2);
// //Debug.DrawRay(start, -velocityDirection*50, Color.cyan);
// if (collider.Raycast(rayCollider, out hitCollider, 50))
// {
// Vector3 pointVelocity = rigidbody.GetPointVelocity(hitCollider.point);
// rigidbody.AddForceAtPosition(-pointVelocity * viscosityAngular, hitCollider.point);
// //Debug.Log(hitCollider.point);
// if (debug)
// Debug.DrawRay(hitCollider.point, -pointVelocity * viscosityAngular, Color.red, 0.1f);
// }
// }
//}
//Debug.Log(test);
}
RamSpline ramSpline = hit.collider.GetComponent<RamSpline>();
LakePolygon lakePolygon = hit.collider.GetComponent<LakePolygon>();
if (ramSpline != null)
{
Mesh meshRam = ramSpline.meshfilter.sharedMesh;
int verticeId1 = meshRam.triangles[hit.triangleIndex * 3];
Vector3 verticeDirection = ramSpline.verticeDirection[verticeId1];
Vector2 uv4 = meshRam.uv4[verticeId1];
verticeDirection = verticeDirection * uv4.y - new Vector3(verticeDirection.z, verticeDirection.y, -verticeDirection.x) * uv4.x;
rigidbody.AddForce(new Vector3(verticeDirection.x, 0, verticeDirection.z) * ramSpline.floatSpeed);
if (debug)
Debug.DrawRay(center, Vector3.up * buoyancy * (minY - center.y) * 5, Color.blue);
if (debug)
Debug.DrawRay(transform.position, velocity * -1 * viscosity * 5, Color.magenta);
if (debug)
Debug.DrawRay(transform.position, velocity * 5, Color.grey);
if (debug)
Debug.DrawRay(transform.position, rigidbody.angularVelocity * 5, Color.black);
}
else if (lakePolygon != null)
{
Mesh meshLake = lakePolygon.meshfilter.sharedMesh;
int verticeId1 = meshLake.triangles[hit.triangleIndex * 3];
Vector2 uv4 = -meshLake.uv4[verticeId1];
//Debug.Log(uv4);
Vector3 verticeDirection = new Vector3(uv4.x, 0, uv4.y);// Vector3.forward * uv4.y + new Vector3(0, 0, 1) * uv4.x;
rigidbody.AddForce(new Vector3(verticeDirection.x, 0, verticeDirection.z) * lakePolygon.floatSpeed);
if (debug)
Debug.DrawRay(transform.position + Vector3.up, verticeDirection * 5, Color.red);
if (debug)
Debug.DrawRay(center, Vector3.up * buoyancy * (minY - center.y) * 5, Color.blue);
if (debug)
Debug.DrawRay(transform.position, velocity * -1 * viscosity * 5, Color.magenta);
if (debug)
Debug.DrawRay(transform.position, velocity * 5, Color.grey);
if (debug)
Debug.DrawRay(transform.position, rigidbody.angularVelocity * 5, Color.black);
}
}
Physics.queriesHitBackfaces = backFace;
}
void OnDrawGizmosSelected()
{
if (!debug)
return;
if (collider != null && volumePointsMatrix != null)
{
var thisMatrix = transform.localToWorldMatrix;
foreach (var item in volumePointsMatrix)
{
Gizmos.color = Color.red;
Gizmos.DrawSphere(item, .08f);
}
}
if (lowestPoint != null)
{
Gizmos.color = Color.blue;
Gizmos.DrawSphere(lowestPoint, .08f);
}
if (center != null)
{
Gizmos.color = Color.green;
Gizmos.DrawSphere(center, .08f);
}
}
}