public override void OnInspectorGUI() { MeshSplit myScript = (MeshSplit)target; if (myScript.children != null && myScript.children.Count != 0) { EditorGUILayout.HelpBox("Submesh count: " + myScript.children.Count, MessageType.Info, true); } else { EditorGUILayout.HelpBox("Submesh count: none", MessageType.Info, true); } DrawDefaultInspector(); if (GUILayout.Button("Split")) { myScript.Split(); } if (GUILayout.Button("Clear")) { myScript.Clear(); } }
void Start() { mapJobs = new _MapJobs(); mapJobs.processAsync(t => needUpdate = true); landzs = MeshSplit.createMesh(transform, "map mesh"); }
/// <summary> /// Performs fractal calls of MeshSplit.Split (no dependence on direction yet) /// </summary> public void Fracture(Vector3 point, float energy) { #region Cancellation Checks // If the mass is too small for further fragmentation, disable fractures if (GetComponent <Rigidbody>().mass < fragmentMinMass) { enabled = false; return; } // If the energy is insufficient for fragmentation, return else if (energy < Mathf.PI * minFractureRadius * minFractureRadius * fractureEnergy) { return; } #endregion Cancellation Checks #region Fracture Properties MeshCollider meshCollider = GetComponent <MeshCollider>(); // breaks along lower energy planes should be more common Vector3 extents = meshCollider.bounds.extents * 1.73f; Vector3 normal = Vector3.Scale(Random.onUnitSphere, Vector3.Scale(extents, extents)).normalized; Plane plane = new Plane(normal, point + Random.onUnitSphere * GetFaultDistance()); // need a way to get the center of the bounds; what space is this in again? global? float planeDist2 = plane.GetDistanceToPoint(meshCollider.bounds.center); planeDist2 *= planeDist2; float crossSectionArea; if (planeDist2 / Vector3.Scale(normal, extents).sqrMagnitude > 1) { crossSectionArea = 0; } else if (normal.z == 1) { crossSectionArea = Mathf.PI * extents.x * extents.y * (1 - planeDist2 / (extents.z * extents.z)); } else { Vector3 n2 = Vector3.Scale(normal, normal); Vector3 e2 = Vector3.Scale(extents, extents); float v1 = extents.x * extents.y * extents.z; float v2 = Vector3.Dot(e2, n2); float u1 = n2.x + n2.y; float u2 = e2.x * n2.x + e2.y * n2.y; float u3 = e2.x * e2.x * n2.x + e2.y * e2.y * n2.y; crossSectionArea = Mathf.PI * v1 * (v2 - planeDist2) * Mathf.Sqrt(u1 * (u2 * u2 + u3 * n2.z)) / (u2 * Mathf.Sqrt(v2 * v2 * v2)); } //print(": " + extents + " : " + crossSectionArea); // if the energy is too low to fracture, or the plane cannot intersect the object, cancel fragmentation if (crossSectionArea <= 0f || energy <= fractureEnergy * crossSectionArea) { return; } #endregion Fracture Properties #region Fracturing // set energy value for further fragmentation steps energy = (energy - fractureEnergy + surfaceEnergy * crossSectionArea) * 0.5f; // try to pull the other fragment from the object pool GameObject other = freeFragments.Count > 0 ? freeFragments.Pop() : Instantiate(gameObject); // attempt to fracture the object bool split = MeshSplit.Split(GetComponent <NMesh>(), other.GetComponent <NMesh>(), plane, Space.World); if (split) { other.SetActive(true); other.layer = gameObject.layer; Rigidbody rigidbody = GetComponent <Rigidbody>(); PhysicsFracture otherFracture = other.GetComponent <PhysicsFracture>(); MeshCollider otherMeshCollider = other.GetComponent <MeshCollider>(); Rigidbody otherRigidbody = other.GetComponent <Rigidbody>(); otherFracture.meanFaultDistance = meanFaultDistance; otherFracture.fractureEnergy = fractureEnergy; otherFracture.surfaceEnergy = surfaceEnergy; otherFracture.fragmentMinMass = fragmentMinMass; meshCollider.sharedMesh = GetComponent <MeshFilter>().mesh; otherMeshCollider.sharedMesh = other.GetComponent <MeshFilter>().mesh; otherMeshCollider.sharedMaterial = meshCollider.sharedMaterial; Vector3 b0 = meshCollider.bounds.size; Vector3 b1 = otherMeshCollider.bounds.size; float massFraction = 1.0f / (1.0f + ((b1.x / b0.x) * (b1.y / b0.y) * (b1.z / b0.z))); otherRigidbody.mass = rigidbody.mass * (1 - massFraction); rigidbody.mass *= massFraction; //TODO: Consider copying all component properties. Possible without reflection? otherRigidbody.drag = rigidbody.drag; rigidbody.WakeUp(); otherRigidbody.WakeUp(); //TODO: Consider adding normal force from mesh split. //How much of the surface energy goes toward future fractures, and how much toward normal forces? Why? otherRigidbody.velocity = rigidbody.velocity; otherRigidbody.angularVelocity = rigidbody.angularVelocity; otherFracture.Fracture(point, energy); } else { other.SetActive(false); freeFragments.Push(other); } Fracture(point, energy); #endregion Fracturing }
void Update() { if (Input.GetMouseButtonDown(1)) { start = Input.mousePosition; //start = new Vector3 (971, 247, 0); Ray ray = Camera.main.ScreenPointToRay(start); RaycastHit hit; RaycastHit[] hits = Physics.RaycastAll(ray); if (Physics.Raycast(ray, out hit)) { MeshSplit split = hit.collider.GetComponent <MeshSplit> (); if (split != null) { startPoint = hit.point; _meshsplit = split; faceStart = hit.triangleIndex; started = true; } } } else if (Input.GetMouseButtonUp(1) && started) { end = Input.mousePosition; //end = new Vector3 (1037, 126, 0); UnityEngine.Debug.LogFormat("{0} {1}", start, end); started = false; Ray ray = Camera.main.ScreenPointToRay(end); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { MeshSplit split = hit.collider.GetComponent <MeshSplit> (); if (split != null && split == _meshsplit) { endPoint = hit.point; int fidx = hit.triangleIndex; if (fidx == faceStart) { UnityEngine.Debug.LogWarning("face same!"); return; } float near = Camera.main.nearClipPlane; Vector3 line = Camera.main.ScreenToWorldPoint(new Vector3(end.x, end.y, near)) - Camera.main.ScreenToWorldPoint(new Vector3(start.x, start.y, near)); line.Normalize(); Vector3 planeN = Vector3.Cross(line, ray.direction).normalized; Vector3 center = (startPoint + endPoint) / 2; Vector3 offset = endPoint - startPoint; float distance = Vector3.Dot(offset, line); SplitPlane.transform.localRotation = Quaternion.identity; SplitPlane.transform.forward = planeN; Vector3 dir = (Camera.main.transform.position - center).normalized; float angle = Vector3.Angle(SplitPlane.transform.up, dir); //UnityEngine.Debug.Log ("angle "+angle); if (Vector3.Dot(SplitPlane.transform.right, dir) > 0) { angle = -angle; } Vector3 angles = SplitPlane.transform.eulerAngles; SplitPlane.transform.localRotation = Quaternion.Euler(new Vector3(angles[0], angles[1], angle - angles[2])); SplitPlane.transform.position = (startPoint + endPoint) / 2f; SplitPlane.transform.localScale = new Vector3(distance, 1, 1); // split _meshsplit.Split(planeN, -SplitPlane.transform.up, startPoint, endPoint, faceStart, fidx); } } } }