private void CalculateTensilAndCompressive(Matrix <double> stress) { Evd <double> evd = stress.Evd(); Matrix <double> tensileComp = Matrix <double> .Build.Dense(3, 3); Matrix <double> compressiveComp = Matrix <double> .Build.Dense(3, 3); for (int i = 0; i < 3; ++i) { double eval = evd.EigenValues[i].Real; Matrix <double> m = Utilities.BuildM(evd.EigenVectors.Column(i).Normalize(2)); tensileComp += System.Math.Max(0, eval) * m; compressiveComp += System.Math.Min(0, eval) * m; } for (int i = 0; i < 3; ++i) { Vector <double> ftensil = Vector <double> .Build.Dense(3); Vector <double> fcompressive = Vector <double> .Build.Dense(3); CalculatePointForce(ftensil, i, tensileComp); fcompressive = forcesP[i] - ftensil; FracParticle fp = p[i].GetComponent <FracParticle>(); fp.AddTensilLoad(ftensil); fp.AddCompressiveLoad(fcompressive); } }
private void Fracture() { // Reinitialize force accumulators and fracturing information of all particles for (int i = 0; i < particles.Count; ++i) { particles[i].GetComponent <FracParticle>().Reinitialize(); } // Compute all forces applied to a particle and update force accumulators for (int i = 0; i < triangles.Count; ++i) { triangles[i].CalculateForces(); } // Check if there are fractures at a particle's point for (int i = 0; i < particles.Count; ++i) { List <Vector <double> > planes = new List <Vector <double> >(); FracParticle fpi = particles[i].GetComponent <FracParticle>(); if (fpi.isFracturing(tau, planes)) { Vector3 planeN = new Vector3(); planeN.x = (float)planes[0].At(0); planeN.y = (float)planes[0].At(1); planeN.z = (float)planes[0].At(2); // Calculate distance from plane to origin Vector3 pos = particles[i].transform.position; float d = Mathf.Sqrt(pos.x * pos.x + pos.y * pos.y + pos.z * pos.z); for (int tri = 0; tri < triangles.Count; ++tri) { // Check for intersection and assign side; only test on first plane for now Vector3 tip = new Vector3(); GameObject particleOnPlane = null; bool isIntersectingElem = triangles[tri].Intersects(planeN, particles[i], d, tip, ref particleOnPlane); if (isIntersectingElem) { CutElement(i, tip, triangles[tri], particleOnPlane); } } } } // 5. Recalculate the mesh Remeshing(); }
public void Remeshing() { List <int> indices = new List <int>(); for (int i = 0; i < triangles.Count; ++i) { GameObject[] p = triangles[i].Points; FracParticle fp1 = p[0].GetComponent <FracParticle>(); FracParticle fp2 = p[1].GetComponent <FracParticle>(); FracParticle fp3 = p[2].GetComponent <FracParticle>(); Vector3 A = p[0].transform.position; Vector3 B = p[1].transform.position; Vector3 C = p[2].transform.position; int p1 = fp1.Id; int p2 = fp2.Id; int p3 = fp3.Id; Vector3 n = new Vector3(0, 1, 0); float r = Vector3.Dot(n, Vector3.Cross(A - C, B - C)); bool isClockwise = r > 0; if (!isClockwise) { p2 = fp3.Id; p3 = fp2.Id; } indices.Add(p1); indices.Add(p2); indices.Add(p3); } Vector3[] vertices = new Vector3[particles.Count]; for (int i = 0; i < particles.Count; ++i) { vertices[i] = particles[i].transform.position; } // Create the mesh Mesh msh = new Mesh(); msh.vertices = vertices; msh.triangles = indices.ToArray(); msh.RecalculateNormals(); msh.RecalculateBounds(); }
// Intesection accounts only for the triangles adjacent to the planePoint public bool Intersects(Vector3 planeNormal, GameObject fracturePoint, float d, Vector3 tip, ref GameObject intersectingPointIfOnPlane) { intersectingPointIfOnPlane = null; bool intersects = false; bool connected = false; // Verify if one of the 3 points in the mesh are connected to the planepoint // If so, verify if plane intersects 2 other points. No need to continue loop afterward. for (int i = 0; !intersects && i < 3; ++i) { if (p[i] == fracturePoint) { connected = true; // Calculate id of 2 other points int id0 = (i + 1) % 3; int id1 = (i + 2) % 3; // Only have to test once against the 2 other points intersects = GetSegmentPlaneIntersection(id0, id1, planeNormal, d, tip, ref intersectingPointIfOnPlane); } } // If the triangle is connected to the plane point, whether there is an intersection of not, assign a side to the points for (int i = 0; connected && i < 3; ++i) { FracParticle fp = p[i].GetComponent <FracParticle>(); if (!fp.SideIsSet) { float side = Vector3.Dot(p[i].transform.position - fracturePoint.transform.position, planeNormal); fp.Side = side > 0; } } return(intersects); }
public void CutElement(int fracturePointId, Vector3 p1, FracTriangle triangle, GameObject particleOnPlane) { // Duplicate Fracture point GameObject originalP = particles[fracturePointId]; FracParticle fpOriginal = originalP.GetComponent <FracParticle>(); // Duplicate Particle and assign side of plane. // The new particle is defined as always on the positive side of the plane GameObject duplicateP = DuplicateParticle(fracturePointId); FracParticle fpDupplicate = duplicateP.GetComponent <FracParticle>(); fpOriginal.Side = false; fpDupplicate.Side = true; // If the other point is an already existing particle, then no other points to create GameObject secondPoint; if (particleOnPlane != null) { secondPoint = particleOnPlane; // HACK: This is a poor way of doing this search. Just trying to make it work here first. // Check if a spring between the originalPoint and the second point already exists bool alreadyExists = false; for (int i = 0; i < fpOriginal.Springs.Count; ++i) { Spring s = fpOriginal.Springs[i]; if ((s.P2.gameObject == secondPoint && s.P1.gameObject == originalP) || (s.P1.gameObject == secondPoint && s.P2.gameObject == originalP)) { alreadyExists = true; } } if (!alreadyExists) { Spring s = originalP.AddComponent <Spring>(); s.Initialize(originalP.GetComponent <Rigidbody>(), secondPoint.GetComponent <Rigidbody>()); } Spring ds = duplicateP.AddComponent <Spring>(); ds.Initialize(duplicateP.GetComponent <Rigidbody>(), secondPoint.GetComponent <Rigidbody>()); } else { secondPoint = CreateParticle(p1); } // Reassign springs for (int i = 0; i < fpOriginal.Springs.Count; ++i) { Spring s = fpOriginal.Springs[i]; GameObject otherPoint = s.GetOtherPoint(originalP); FracParticle sfp = otherPoint.GetComponent <FracParticle>(); if (sfp.gameObject == secondPoint) { continue; } else { Assert.IsTrue(sfp.SideIsSet, "FracMesh : CutElement : Side is not set. Can't reassign springs"); } // if spring particle doesn't have the same side as the initial particle, then the spring must be // re-assigned to the duplicate. Otherwise, nothing to change if (sfp.Side != fpOriginal.Side) { s.Initialize(otherPoint.GetComponent <Rigidbody>(), duplicateP.GetComponent <Rigidbody>()); } } }