using UnityEngine; using System.Collections; using System.Collections.Generic; public class WaterField : MonoBehaviour { public List capturedObjects = new List(); 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(); 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(); if(mat != null){ objDensity = mat.matter.Density; } var tf = obj.transform.localToWorldMatrix; Vector3[] vertices; int[] indices; var mf = obj.GetComponent(); 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 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); } } }