public void CollisionStay(PhysXCollision collision) { if (collision.contactCount > 0 && collision.GetContact(0).separation < -minPenetration) { if ((collision.rigidBody == null || collision.rigidBody.mass >= minDeformationMass) && !collision.collider.gameObject.CompareTag("DustGround")) { meshDeformationMarker.Begin(); bool isInconvenient = collision.collider is PhysXMeshCollider && !((PhysXMeshCollider)collision.collider).convex; Vector3 collisionSurfaceNormal = Vector3.zero; Vector3 collisionSurfacePoint = Vector3.zero; for (int i = 0; i < collision.contactCount; i++) { PhysXContactPoint contactPoint = collision.GetContact(i); float impulseMagnitude = contactPoint.impulse.magnitude; collisionSurfaceNormal += contactPoint.normal; collisionSurfacePoint += contactPoint.point; } collisionSurfaceNormal /= collision.contactCount; collisionSurfacePoint /= collision.contactCount; collisionSurfaceNormal = transform.InverseTransformDirection(collisionSurfaceNormal); collisionSurfacePoint = transform.InverseTransformPoint(collisionSurfacePoint); gizmoSurfaceNormal = collisionSurfaceNormal; gizmoSurfacePoint = collisionSurfacePoint; Vector3 oldPosition = collision.body.position; Quaternion oldRotation = collision.body.rotation; collision.body.position = transform.InverseTransformPoint(collision.body.position); collision.body.rotation = Quaternion.Inverse(transform.rotation) * collision.body.rotation; VertexGroup[] groups = meshGraph.groups; for (int i = 0; i < groups.Length; i++) { VertexGroup current = groups[i]; Vector3 vertex = current.pos; if (IsBeyondCollisionSurface(collisionSurfaceNormal, collisionSurfacePoint, vertex)) { if (isInconvenient || collision.collider.ClosestPoint(vertex) == vertex) { Vector3 deformation = DeformationFromCollisionSurface(collisionSurfaceNormal, collisionSurfacePoint, vertex); // if (addNoise) deformation *= Random.value * multiplier + addition; current.MoveBy(vertices, deformation, false); current.SetWasMoved(teamId, true); if (!current.GetEnqueued(teamId)) { vertexQueue.Enqueue(current); current.SetEnqueued(teamId, true); // Debug.Log("Vertex group " + current.vertexIndices[0] + " enqueued due to collision"); } } } } collision.body.position = oldPosition; collision.body.rotation = oldRotation; dissipationNeeded = true; meshDeformationMarker.End(); } } }
// Explode the mesh at a given position, with a given force public void ExplodeMeshAt(Vector3 pos, float force, bool addNoise = true) { pos = transform.InverseTransformPoint(pos); VertexGroup closest = GetClosestVertexGroup(pos); // Make a queue (it breadth first traversal time) vertexQueue.Enqueue(closest); closest.SetEnqueued(teamId, true); // Move each vertex, making sure that it doesn't stretch too far from its neighbours while (vertexQueue.Count > 0) { VertexGroup current = vertexQueue.Dequeue(); current.SetEnqueued(teamId, false); oldEdgeSqrLengths.Clear(); for (int j = 0; j < current.connectingEdges.Count; j++) { oldEdgeSqrLengths.Add(current.connectingEdges[j].sqrLength); } // Calculate deformation vector Vector3 deformation = current.pos - pos; float deformationForce = force / deformation.sqrMagnitude; if (addNoise) { deformationForce *= Random.value * 0.2f + 0.9f; } deformation.Normalize(); deformation *= Mathf.Clamp(deformationForce / vertexWeight, 0, 0.5f); current.MoveBy(vertices, deformation, false); for (int j = 0; j < current.connectingEdges.Count; j++) { VertexGroup adjacent = current.connectingEdges[j].OtherVertexGroup(current); // Check if adjacent vertex has been moved. if (adjacent.GetWasMoved(teamId)) { // Get vector of edge between vertices. Vector3 edge = current.pos - adjacent.pos; // ohno edge too long if (edge.sqrMagnitude > stretchiness * stretchiness * oldEdgeSqrLengths[j]) { // make edge right length edge.Normalize(); float randomNoise = 1; if (addNoise) { randomNoise = Random.value * 0.2f + 0.9f; } float edgeStretchiness = stretchiness * randomNoise; edge *= edgeStretchiness * Mathf.Sqrt(oldEdgeSqrLengths[j]); // move vertices so edge is not too long. current.MoveTo(vertices, adjacent.pos + edge, false); current.connectingEdges[j].UpdateEdgeLength(); } } } current.SetWasMoved(teamId, true); // Add adjacent, unmoved vertices into the queue for traversal for (int j = 0; j < current.connectingEdges.Count; j++) { // Get adjacent vertex group VertexGroup adjacent = current.connectingEdges[j].OtherVertexGroup(current); // Add it to the queue if it hasn't already been moved if (!adjacent.GetEnqueued(teamId) && !adjacent.GetWasMoved(teamId)) { vertexQueue.Enqueue(adjacent); adjacent.SetEnqueued(teamId, true); } } } for (int i = 0; i < meshGraph.groups.Length; i++) { meshGraph.groups[i].SetWasMoved(teamId, false); if (meshGraph.groups[i].GetEnqueued(teamId)) { Debug.LogWarning("Vertex marked as still in queue."); meshGraph.groups[i].SetEnqueued(teamId, false); } } // Update the mesh deformableMeshes[0].GetMeshFilter().mesh.SetVertices(vertices); deformableMeshes[0].GetMeshFilter().mesh.RecalculateNormals(); }