229 lines
7.0 KiB
C#
229 lines
7.0 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
public class WaterField : MonoBehaviour {
|
|
public List<GameObject> capturedObjects = new List<GameObject>();
|
|
public bool enableDrag = true;
|
|
float maxDrag = 0.0f;
|
|
float vel = 0.0f;
|
|
|
|
// Use this for initialization
|
|
void Start () {
|
|
if (collider == null) {
|
|
var c = gameObject.AddComponent<BoxCollider>();
|
|
c.center = new Vector3(0, -0.5f, 0);
|
|
c.isTrigger = true;
|
|
}
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void FixedUpdate () {
|
|
|
|
float envDensity = AdvancedPhysics.Matters.Water.Density;
|
|
|
|
|
|
|
|
Plane p = new Plane(transform.up, transform.position);
|
|
|
|
foreach (var obj in capturedObjects) {
|
|
if(obj.collider is SphereCollider){
|
|
float objDensity = AdvancedPhysics.Matters.Water.Density * 1.05f;
|
|
Vector3 sphereCenter;
|
|
float sphereRadius;
|
|
SphereCollider c = obj.collider as SphereCollider;
|
|
if(c != null){
|
|
sphereCenter = c.transform.position;
|
|
sphereRadius = c.radius;
|
|
}else{
|
|
sphereCenter = obj.collider.bounds.center;
|
|
Vector3 ext = obj.collider.bounds.extents;
|
|
|
|
sphereRadius = ext.x > ext.y ? ext.x : (ext.y > ext.z ? ext.y : ext.z);
|
|
}
|
|
|
|
|
|
float underwaterVolume = SphereVolumeUnderPlane(p, sphereCenter, sphereRadius);
|
|
|
|
float forceMagnitude = AdvancedMath.BuoyantForce(underwaterVolume, objDensity, envDensity, Physics.gravity.magnitude);
|
|
|
|
Vector3 force = Physics.gravity.normalized * -forceMagnitude;
|
|
|
|
Vector3 sphereDragForce = -obj.rigidbody.velocity.normalized * AdvancedMath.SphereDrag(envDensity, obj.rigidbody.velocity.magnitude, sphereRadius);
|
|
|
|
float sphereVolume = AdvancedMath.SphereVolume(sphereRadius);
|
|
Vector3 speedForce = Vector3.zero;
|
|
if(underwaterVolume < sphereVolume){
|
|
if(underwaterVolume > 0.0f)
|
|
speedForce = Vector3.Cross(obj.rigidbody.angularVelocity, transform.up) * 30;
|
|
}else{
|
|
speedForce = Vector3.Cross(obj.rigidbody.angularVelocity, transform.up) * 10;
|
|
|
|
}
|
|
|
|
obj.rigidbody.AddForce(force + sphereDragForce + speedForce);
|
|
|
|
}if(obj.collider is BoxCollider){
|
|
float objDensity = AdvancedPhysics.Matters.Water.Density * 1.05f;
|
|
var mat = obj.GetComponent<AdvancedPhysicsMaterial>();
|
|
if(mat != null){
|
|
objDensity = mat.matter.Density;
|
|
}
|
|
|
|
var tf = obj.transform.localToWorldMatrix;
|
|
|
|
Vector3[] vertices;
|
|
int[] indices;
|
|
|
|
var mf = obj.GetComponent<MeshFilter>();
|
|
if(mf != null && mf.sharedMesh != null){
|
|
vertices = mf.mesh.vertices;
|
|
indices = mf.mesh.triangles;
|
|
int cnt = vertices.Length;
|
|
for(int i = 0; i < cnt; ++i){
|
|
vertices[i] = tf.MultiplyPoint3x4(vertices[i]);
|
|
}
|
|
}else{
|
|
AdvancedUtils.CreateMeshCube (obj.transform.localToWorldMatrix, out vertices, out indices);
|
|
}
|
|
|
|
|
|
|
|
List<Vector3> cuttedTriangles = AdvancedUtils.CutMesh (vertices, indices, p);
|
|
|
|
//AdvancedGizmo.DrawMesh(cuttedTriangles.ToArray(), true);
|
|
|
|
float totalVolume = 0;
|
|
Vector3 totalBuoyantForce = Vector3.zero;
|
|
|
|
for (int i = 0; i < cuttedTriangles.Count; i+=3) {
|
|
Vector3 v0 = cuttedTriangles[i + 0];
|
|
Vector3 v1 = cuttedTriangles[i + 1];
|
|
Vector3 v2 = cuttedTriangles[i + 2];
|
|
Vector3 normal = AdvancedMath.TriangleNormal(v0, v1, v2);
|
|
|
|
float dot = Vector3.Dot (normal, p.normal);
|
|
if(Mathf.Abs(dot) >= 0.0001f){
|
|
float sign = Mathf.Sign(dot);
|
|
|
|
float h0 = p.GetDistanceToPoint(v0);
|
|
float h1 = p.GetDistanceToPoint(v1);
|
|
float h2 = p.GetDistanceToPoint(v2);
|
|
float avgH = (h0 + h1 + h2) / 3.0f;
|
|
|
|
Vector3 vp0 = v0 - p.normal * h0;
|
|
Vector3 vp1 = v1 - p.normal * h1;
|
|
Vector3 vp2 = v2 - p.normal * h2;
|
|
|
|
float triangleSquare = AdvancedMath.TriangleSquare(vp0, vp1, vp2);
|
|
float prismVolume = AdvancedMath.PrismVolume(triangleSquare, avgH) * sign;
|
|
float prismBuoyantMagnitude = AdvancedMath.BuoyantForce(prismVolume, objDensity, envDensity, Physics.gravity.magnitude);
|
|
Vector3 prismBuoyantForce = Physics.gravity.normalized * -prismBuoyantMagnitude;
|
|
|
|
totalBuoyantForce += prismBuoyantForce;
|
|
totalVolume += prismVolume;
|
|
Vector3 com = AdvancedMath.PrismCenterOfMass(vp0, vp1, vp2, p.normal, h0, h1, h2);
|
|
obj.rigidbody.AddForceAtPosition(prismBuoyantForce, com, ForceMode.Force);
|
|
//obj.rigidbody.d
|
|
//Physics.
|
|
}
|
|
}
|
|
if(obj.name == "CubeTest"){
|
|
// Debug.Log("Total underwater volume: " + totalVolume);
|
|
//Debug.Log("Total buoyant force: " + totalBuoyantForce);
|
|
}
|
|
|
|
|
|
|
|
Vector3 ext = obj.collider.bounds.extents;
|
|
float sphereRadius = ext.x > ext.y ? ext.x : (ext.y > ext.z ? ext.y : ext.z);
|
|
|
|
float v = obj.rigidbody.velocity.magnitude;
|
|
|
|
float dragMagnitude = AdvancedMath.Drag(envDensity, v, 1.02f, Mathf.PI * sphereRadius * sphereRadius);
|
|
if(v < 0.01f){
|
|
dragMagnitude = 0.0f;
|
|
}
|
|
|
|
if( dragMagnitude > v*v*obj.rigidbody.mass){
|
|
dragMagnitude = v*v*obj.rigidbody.mass;
|
|
}
|
|
/* if(dragMagnitude > obj.rigidbody.velocity.magnitude){
|
|
dragMagnitude = obj.rigidbody.velocity.magnitude;
|
|
}*/
|
|
|
|
if(enableDrag){
|
|
Vector3 sphereDragForce = -obj.rigidbody.velocity.normalized * dragMagnitude;
|
|
obj.rigidbody.AddForce(sphereDragForce, ForceMode.Force);
|
|
Debug.DrawRay(obj.transform.position,obj.rigidbody.velocity, Color.green);
|
|
Debug.DrawRay(obj.transform.position,sphereDragForce, Color.red);
|
|
if(obj.name == "CubeTest"){
|
|
if(maxDrag < dragMagnitude){
|
|
maxDrag = dragMagnitude;
|
|
vel = v;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// obj.rigidbody.velocity -= (sphereDragForce / obj.rigidbody.mass) * Time.fixedDeltaTime;
|
|
|
|
|
|
|
|
|
|
|
|
AdvancedGizmo.DrawMesh(cuttedTriangles.ToArray(), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnGUI(){
|
|
GUI.Label (new Rect(0,0,100,100), "Max drag = " + maxDrag);
|
|
GUI.Label (new Rect(0,30,100,100), "Vel = " + vel);
|
|
}
|
|
|
|
void OnDrawGizmos(){
|
|
Gizmos.matrix = transform.localToWorldMatrix;
|
|
|
|
Gizmos.DrawWireCube (new Vector3 (0, -0.5f, 0), Vector3.one);
|
|
Gizmos.matrix = Matrix4x4.identity;
|
|
|
|
//AdvancedGizmo.DrawGrid (transform.position, width, height);
|
|
|
|
int waveLineCount = 5;
|
|
int wavesCount = 7;
|
|
|
|
float hLineOffset = (1.0f / (float)(waveLineCount + 1));
|
|
for (int i = 0; i < waveLineCount; ++i) {
|
|
float hOffset = -hLineOffset * (float)(i + 1);
|
|
|
|
AdvancedGizmo.Plot2D (Mathf.Sin, transform.localToWorldMatrix, new Vector3(-0.5f, 0, 0.5f + hOffset), Vector3.right, Vector3.forward, 1, Mathf.PI * wavesCount, 0.05f, 40, Color.blue);
|
|
}
|
|
}
|
|
|
|
float SphereVolumeUnderPlane(Plane p, Vector3 sphereCenter, float r){
|
|
float distance = p.GetDistanceToPoint (sphereCenter);
|
|
if (distance >= r) {
|
|
return 0;
|
|
} else if (distance <= -r) {
|
|
return AdvancedMath.SphereVolume (r);
|
|
} else {
|
|
float h = Mathf.Abs(distance - r);
|
|
return AdvancedMath.SphereSegmentVolume(r, h);
|
|
}
|
|
}
|
|
|
|
void OnTriggerEnter(Collider other){
|
|
if (other.rigidbody != null && !other.rigidbody.isKinematic) {
|
|
capturedObjects.Add(other.gameObject);
|
|
}
|
|
}
|
|
|
|
void OnTriggerExit(Collider other){
|
|
if (other.rigidbody != null && !other.rigidbody.isKinematic) {
|
|
capturedObjects.Remove(other.gameObject);
|
|
}
|
|
}
|
|
}
|