public SoftbodyData(Mesh bodyMesh, Transform transform, List <Verlet.DistConstraint> constraintsList, Vector3 scaledGravity, Transform ground) { bodyVerts = new NativeArray <Vector3>(bodyMesh.vertices, Allocator.Persistent); kabschVerts = new NativeArray <Vector4>(Array.ConvertAll(bodyVerts.ToArray(), (p => new Vector4(p.x, p.y, p.z, 1f))), Allocator.Persistent); int[] triangles = bodyMesh.triangles; Vector3Int[] tris = new Vector3Int[triangles.Length / 3]; for (int i = 0; i < tris.Length; i++) { tris[i] = new Vector3Int(triangles[i * 3], triangles[(i * 3) + 1], triangles[(i * 3) + 2]); } bodyTriangles = new NativeArray <Vector3Int>(tris, Allocator.Persistent); bodyNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); renderNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); prevBodyVerts = new NativeArray <Vector3>(new Vector3[bodyVerts.Length], Allocator.Persistent); accumulatedDisplacements = new NativeArray <Vector4>(new Vector4[bodyVerts.Length], Allocator.Persistent); for (int i = 0; i < bodyVerts.Length; i++) { prevBodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } constraintsArray = new NativeArray <Verlet.DistConstraint>(constraintsList.ToArray(), Allocator.Persistent); dilationDistance = new NativeArray <float>(new float[1], Allocator.Persistent); initialVolume = Verlet.VolumeOfMesh(bodyVerts, bodyTriangles); initialSurfaceArea = 4f * 3.14159f; previousDeltaTime = 1f; dilationDistance[0] = 0f; this.scaledGravity = scaledGravity; localToWorld = transform.localToWorldMatrix; worldToLocal = transform.worldToLocalMatrix; groundPlanePos = ground.position; groundPlaneNormal = -ground.forward; }
public DistanceConstraint(Verlet a, Verlet b, float distance) { A = a; B = b; MaxDistance = distance; MinDistance = distance; }
void Start() { //Initialize mesh and state variables radius = transform.lossyScale.x; transform.localScale = Vector3.one; MeshFilter filter = GetComponent <MeshFilter>(); bodyMesh = Instantiate(filter.mesh); bodyMesh.MarkDynamic(); originalVerts = bodyMesh.vertices; filter.mesh = bodyMesh; renderNormalsArray = new Vector3[originalVerts.Length]; bodyVertsArray = new Vector3[originalVerts.Length]; kabschVertsArray = new Vector4[originalVerts.Length]; //Create Distance Constraints from Triangles in Mesh constraintsList = new List <Verlet.DistConstraint>(originalVerts.Length * 3); Verlet.setUpConstraints(bodyMesh, constraintsList, false, radius); softbodyData = new SoftbodyData(bodyMesh, transform, constraintsList, new Vector3(Physics.gravity.x / transform.lossyScale.x, Physics.gravity.y / transform.lossyScale.y, Physics.gravity.z / transform.lossyScale.z), groundPlane, radius, friction); priorDebuggerState = JobsUtility.JobDebuggerEnabled; JobsUtility.JobDebuggerEnabled = false; }
void Start() { //Initialize mesh and state variables MeshFilter filter = GetComponent <MeshFilter>(); bodyMesh = Instantiate(filter.mesh); bodyMesh.MarkDynamic(); bodyVerts = bodyMesh.vertices; kabschVerts = Array.ConvertAll(bodyVerts, (p => new Vector4(p.x, p.y, p.z, 1f))); originalVerts = bodyMesh.vertices; bodyTriangles = bodyMesh.triangles; bodyNormals = bodyMesh.normals; renderNormals = bodyMesh.normals; prevBodyVerts = new Vector3[bodyVerts.Length]; accumulatedDisplacements = new Vector4[bodyVerts.Length]; for (int i = 0; i < bodyVerts.Length; i++) { prevBodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } filter.mesh = bodyMesh; //Create Distance Constraints from Triangles in Mesh constraints = new List <Verlet.DistConstraint>(bodyVerts.Length * 3); Verlet.setUpConstraints(bodyMesh, constraints, false); //Scale gravity by the size of this Mesh Renderer scaledGravity = new Vector3(Physics.gravity.x / transform.lossyScale.x, Physics.gravity.y / transform.lossyScale.y, Physics.gravity.z / transform.lossyScale.z); initialVolume = Verlet.VolumeOfMesh(bodyVerts, bodyTriangles); }
void Update() { //Translate the points into world space for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } for (int i = 0; i < solverIterations; i++) { //First, ensure that the surface area is what we think it is Verlet.resolveDistanceConstraints(constraints, ref bodyVerts, ref accumulatedDisplacements, 1); //Next, set the volume of the soft body Verlet.setVolume(inflationAmount * initialVolume, bodyVerts, bodyNormals, bodyTriangles, initialSurfaceArea, true, fastButGarbage); } //Also clamp to the intersection of capsules for shits for (int j = 0; j < bodyVerts.Length; j++) { Vector3 capOne = Constraints.ConstrainToCapsule(bodyVerts[j], Vector3.zero, Vector3.up, 0.25f) - bodyVerts[j]; Vector3 capTwo = Constraints.ConstrainToCapsule(bodyVerts[j], Vector3.zero, Vector3.right * 1.15f, 0.25f) - bodyVerts[j]; if (capOne.sqrMagnitude < capTwo.sqrMagnitude) { bodyVerts[j] += capOne; } else { bodyVerts[j] += capTwo; } } //Calculate the the position and rotation of the body for (int i = 0; i < bodyVerts.Length; i++) { kabschVerts[i] = new Vector4(bodyVerts[i].x, bodyVerts[i].y, bodyVerts[i].z, 1f); } ; Matrix4x4 toWorldSpace = kabschSolver.SolveKabsch(originalVerts, Array.ConvertAll(bodyVerts, (p => (Vector4)p))); transform.position = toWorldSpace.GetVector3(); transform.rotation = toWorldSpace.GetQuaternion(); //Move the points into local space for rendering for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.InverseTransformPoint(bodyVerts[i]); renderNormals[i] = transform.InverseTransformDirection(bodyNormals[i]); } Debug.Log(Verlet.VolumeOfMesh(bodyVerts, bodyTriangles)); //Graphics bodyMesh.vertices = bodyVerts; bodyMesh.normals = renderNormals; bodyMesh.RecalculateBounds(); bodyMesh.UploadMeshData(false); }
void Awake() { partObDict = new Dictionary <Particle, GameObject>(); compObDict = new Dictionary <Composite, GameObject>(); compositeConstraintCounts = new Dictionary <Composite, int>(); World = new Verlet(width, height); World.friction = 0.99f; World.gravity.y = -1f; }
//private Rectangle boundBox; public VerletPoint(Verlet ghost, int index, float xprev, float yprev, float xcurr, float ycurr) { this.ghost = ghost; this.myIndex = index; this.xprev = xprev; this.yprev = yprev; this.xcurr = xcurr; this.ycurr = ycurr; setNext(); }
void Update() { foreach (VerletPoint p in points) { p.PseudoUpdate(); } foreach (VerletPoint p in points) { p.CheckConstraints(points); } foreach (VerletPoint p in points) { p.Fixed = false; // p.CheckConstraints(points); collisionWithCannonballs(p); } for (int i = 0; i < points.Count; i++) { ghostCollisionResolution(points[i % points.Count], points[(i + 1) % points.Count]); } j = 0; foreach (VerletPoint p in points) { //p.PseudoUpdate(); //p.CheckConstraints(); lr.SetPosition(p.myIndex, new Vector3(p.xcurr, p.ycurr, 0)); dots[j].transform.position = new Vector3(p.xcurr, p.ycurr, 0); j++; } if (destroy) { // mg.destroy = destroy; //create a ghost right before i destroy gameObject GameObject v = Instantiate(this.gameObject, new Vector3(0, 0, 0), Quaternion.identity); Verlet vv = v.GetComponent <Verlet>(); vv.randomPosition.x = -Random.value * 13 + -5; vv.randomPosition.y = Random.value * 3 + 0.5f; Destroy(this.gameObject); } }
void OnBecameInvisible() { if (!isQuitting) { GameObject v = Instantiate(this.gameObject, new Vector3(0, 0, 0), Quaternion.identity); Verlet vv = v.GetComponent <Verlet>(); vv.randomPosition.x = -Random.value * 13 + -5; vv.randomPosition.y = Random.value * 3 + 0.5f; foreach (GameObject dot in dots) { Destroy(dot); } Destroy(this.gameObject); } }
public Heli() { float L = 2, W = 1, H = 1, D = 0.5f, HH = 50; var vs = new Verlet[] { new Verlet(L,HH+0,W), new Verlet(L,HH+0,-W), new Verlet(-L,HH+0,-W), //tail rotor push (e) 3 new Verlet(-L,HH+0, W), //tail rotor pull (q) 5 new Verlet(-0.4f,HH+H,0), //rotor 4 new Verlet(-L,HH-D,0) }; Init(vs); }
public Heli() { float L = 2, W = 1, H = 1, D = 0.5f, HH = 50; var vs = new Verlet[] { new Verlet(L, HH + 0, W), new Verlet(L, HH + 0, -W), new Verlet(-L, HH + 0, -W), //tail rotor push (e) 3 new Verlet(-L, HH + 0, W), //tail rotor pull (q) 5 new Verlet(-0.4f, HH + H, 0), //rotor 4 new Verlet(-L, HH - D, 0) }; Init(vs); }
void Start() { MeshFilter filter = GetComponent <MeshFilter>(); clothMesh = Instantiate(filter.mesh); clothMesh.MarkDynamic(); clothVerts = clothMesh.vertices; prevClothVerts = clothMesh.vertices; accumulatedDisplacements = new Vector4[clothVerts.Length]; filter.mesh = clothMesh; //Create Distance Constraints from Triangles in Mesh constraints = new List <Verlet.DistConstraint>(clothVerts.Length * 3); Verlet.setUpConstraints(clothMesh, constraints, false); //Scale gravity by the size of this Mesh Renderer scaledGravity = new Vector3(Physics.gravity.x / transform.lossyScale.x, Physics.gravity.y / transform.lossyScale.y, Physics.gravity.z / transform.lossyScale.z); }
void Start() { //Initialize mesh and state variables MeshFilter filter = GetComponent <MeshFilter>(); bodyMesh = Instantiate(filter.mesh); bodyMesh.MarkDynamic(); bodyVerts = new NativeArray <Vector3>(bodyMesh.vertices, Allocator.Persistent); kabschVerts = new NativeArray <Vector4>(Array.ConvertAll(bodyVerts.ToArray(), (p => new Vector4(p.x, p.y, p.z, 1f))), Allocator.Persistent); originalVerts = bodyMesh.vertices; int[] triangles = bodyMesh.triangles; Vector3Int[] tris = new Vector3Int[triangles.Length / 3]; for (int i = 0; i < tris.Length; i++) { tris[i] = new Vector3Int(triangles[i * 3], triangles[(i * 3) + 1], triangles[(i * 3) + 2]); } bodyTriangles = new NativeArray <Vector3Int>(tris, Allocator.Persistent); bodyNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); renderNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); prevBodyVerts = new NativeArray <Vector3>(new Vector3[bodyVerts.Length], Allocator.Persistent); accumulatedDisplacements = new NativeArray <Vector4>(new Vector4[bodyVerts.Length], Allocator.Persistent); for (int i = 0; i < bodyVerts.Length; i++) { prevBodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } filter.mesh = bodyMesh; renderNormalsArray = new Vector3[renderNormals.Length]; bodyVertsArray = new Vector3[bodyVerts.Length]; kabschVertsArray = new Vector4[kabschVerts.Length]; //Create Distance Constraints from Triangles in Mesh constraintsList = new List <Verlet.DistConstraint>(bodyVerts.Length * 3); Verlet.setUpConstraints(bodyMesh, constraintsList, false); constraintsArray = new NativeArray <Verlet.DistConstraint>(constraintsList.ToArray(), Allocator.Persistent); //Scale gravity by the size of this Mesh Renderer scaledGravity = new Vector3(Physics.gravity.x / transform.lossyScale.x, Physics.gravity.y / transform.lossyScale.y, Physics.gravity.z / transform.lossyScale.z); initialVolume = Verlet.VolumeOfMesh(bodyVerts, bodyTriangles); optimizer.CalculateErrorDerivative = CalculateErrorDerivative; optimizer.Add(1f, "xScale"); optimizer.Add(Vector3.up, "yBasis"); optimizer.Add(Vector3.forward, "zBasis"); }
void Update() { //Physics Verlet.Integrate(clothVerts, prevClothVerts, scaledGravity, Time.deltaTime, previousDeltaTime); previousDeltaTime = Time.deltaTime; //Anchor the Top Corner of the Cloth clothVerts[0] = prevClothVerts[0] = anchor1.position; clothVerts[10] = prevClothVerts[10] = anchor2.position; //Constraint Resolution Verlet.resolveDistanceConstraints(constraints, ref clothVerts, ref accumulatedDisplacements, 1); //Graphics clothMesh.vertices = clothVerts; clothMesh.RecalculateNormals(); clothMesh.RecalculateBounds(); clothMesh.UploadMeshData(false); }
// Start is called before the first frame update void Start() { //instantiate four ghosts prefab = GameObject.Find("ghosty"); GameObject v = Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity); Verlet vv = v.GetComponent <Verlet>(); vv.randomPosition.x = -Random.value * 13 + -5; vv.randomPosition.y = Random.value * 3 + 0.5f; v = Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity); vv = v.GetComponent <Verlet>(); vv.randomPosition.x = -Random.value * 13 + -5; vv.randomPosition.y = Random.value * 3 + 0.5f; v = Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity); vv = v.GetComponent <Verlet>(); vv.randomPosition.x = -Random.value * 13 + -5; vv.randomPosition.y = Random.value * 3 + 0.5f; }
void Start() { //Initialize mesh and state variables MeshFilter filter = GetComponent <MeshFilter>(); bodyMesh = Instantiate(filter.mesh); bodyMesh.MarkDynamic(); bodyVerts = bodyMesh.vertices; originalVerts = bodyMesh.vertices; bodyTriangles = bodyMesh.triangles; bodyNormals = bodyMesh.normals; renderNormals = bodyMesh.normals; accumulatedDisplacements = new Vector4[bodyVerts.Length]; filter.mesh = bodyMesh; //Create Distance Constraints from Triangles in Mesh constraints = new List <Verlet.DistConstraint>(bodyVerts.Length * 3); Verlet.setUpConstraints(bodyMesh, constraints, false); initialVolume = Verlet.VolumeOfMesh(bodyVerts, bodyTriangles); }
public FixedConstraint(Verlet target) { Target = target; }
public BoxConstraint(Verlet target, BoundingBox2 bounds) { Target = target; Bounds = bounds; }
public void SetConstraint(Verlet v) { ConstraintSolver.Set(Index, v.Index, CurrentPosition, v.CurrentPosition); }
void Update() { //Translate the points into world space for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } //Physics float currentDeltaTime = Mathf.Clamp(Time.deltaTime, 0.01f, previousDeltaTime * 1.4f); Verlet.Integrate(bodyVerts, prevBodyVerts, scaledGravity, currentDeltaTime, previousDeltaTime); previousDeltaTime = currentDeltaTime; //Anchor a point on the body if (anchor != null && anchor.gameObject.activeInHierarchy) { bodyVerts[0] = prevBodyVerts[0] = anchor.position; } //Also sneak in a ground plane here: Vector3 groundPlanePos = groundPlane.position; Vector3 groundPlaneNormal = -groundPlane.forward; for (int j = 0; j < bodyVerts.Length; j++) { if (Vector3.Dot(bodyVerts[j] - groundPlanePos, groundPlaneNormal) < 0f) { bodyVerts[j] = Vector3.ProjectOnPlane(bodyVerts[j] - groundPlanePos, groundPlaneNormal) + groundPlanePos; bodyVerts[j] -= Vector3.ProjectOnPlane(bodyVerts[j] - prevBodyVerts[j], groundPlaneNormal) * 0.3f; } } //Calculate the the position and rotation of the body for (int i = 0; i < bodyVerts.Length; i++) { kabschVerts[i] = new Vector4(bodyVerts[i].x, bodyVerts[i].y, bodyVerts[i].z, 1f); } ; kabschVerts.CopyTo(kabschVertsArray); Matrix4x4 toWorldSpace = kabschSolver.SolveKabsch(originalVerts, kabschVertsArray, true); constrainVertsToDeformation(originalVerts, toWorldSpace, ref bodyVerts); Verlet.RecalculateNormalsNonAlloc(bodyVerts, bodyTriangles, ref bodyNormals); //Move the points into local space for rendering transform.position = toWorldSpace.GetVector3(); transform.rotation = toWorldSpace.GetQuaternion(); for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.InverseTransformPoint(bodyVerts[i]); renderNormals[i] = transform.InverseTransformDirection(bodyNormals[i]); } Debug.DrawRay(transform.position, toWorldSpace * (Vector3.Cross(yBasis, zBasis).normalized *xScale), Color.red); Debug.DrawRay(transform.position, toWorldSpace * yBasis, Color.green); Debug.DrawRay(transform.position, toWorldSpace * zBasis, Color.blue); //Graphics bodyVerts.CopyTo(bodyVertsArray); renderNormals.CopyTo(renderNormalsArray); bodyMesh.vertices = bodyVertsArray; bodyMesh.normals = renderNormalsArray; bodyMesh.RecalculateBounds(); bodyMesh.UploadMeshData(false); }
void Update() { //Translate the points into world space for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } //Physics float currentDeltaTime = Mathf.Clamp(Time.deltaTime, 0.01f, previousDeltaTime * 1.4f); Verlet.Integrate(bodyVerts, prevBodyVerts, scaledGravity, currentDeltaTime, previousDeltaTime); previousDeltaTime = currentDeltaTime; //Anchor a point on the body if (anchor != null && anchor.gameObject.activeInHierarchy) { bodyVerts[0] = prevBodyVerts[0] = anchor.position; } for (int i = 0; i < solverIterations; i++) { //First, ensure that the surface area is what we think it is Verlet.resolveDistanceConstraints(constraints, ref bodyVerts, ref accumulatedDisplacements, 1); //Next, set the volume of the soft body Verlet.setVolume(inflationAmount * initialVolume, bodyVerts, bodyNormals, bodyTriangles, initialSurfaceArea, true, fastButGarbage); } //Also sneak in a ground plane here: Vector3 groundPlanePos = groundPlane.position; Vector3 groundPlaneNormal = -groundPlane.forward; for (int j = 0; j < bodyVerts.Length; j++) { if (Vector3.Dot(bodyVerts[j] - groundPlanePos, groundPlaneNormal) < 0f) { bodyVerts[j] = Vector3.ProjectOnPlane(bodyVerts[j] - groundPlanePos, groundPlaneNormal) + groundPlanePos; bodyVerts[j] -= Vector3.ProjectOnPlane(bodyVerts[j] - prevBodyVerts[j], groundPlaneNormal) * 0.3f; } } //Calculate the the position and rotation of the body for (int i = 0; i < bodyVerts.Length; i++) { kabschVerts[i] = new Vector4(bodyVerts[i].x, bodyVerts[i].y, bodyVerts[i].z, 1f); } ; Matrix4x4 toWorldSpace = kabschSolver.SolveKabsch(originalVerts, kabschVerts, transformFollowsRotation); transform.position = toWorldSpace.GetVector3(); transform.rotation = toWorldSpace.GetQuaternion(); //Move the points into local space for rendering for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] = transform.InverseTransformPoint(bodyVerts[i]); renderNormals[i] = transform.InverseTransformDirection(bodyNormals[i]); } //Graphics bodyMesh.vertices = bodyVerts; bodyMesh.normals = renderNormals; bodyMesh.RecalculateBounds(); bodyMesh.UploadMeshData(false); }
public BoxConstraint(Verlet target) { Target = target; }
protected virtual void Start() { GeneratePlant(); _verlet = new Verlet(init_data, this.transform); }
public SoftbodyData(Mesh bodyMesh, Transform transform, List <Verlet.DistConstraint> constraintsList, Vector3 scaledGravity, Transform ground, float radius = 1f, float friction = 0.3f) { bodyVerts = new NativeArray <Vector3>(bodyMesh.vertices, Allocator.Persistent); for (int i = 0; i < bodyVerts.Length; i++) { bodyVerts[i] *= radius; } preCollisionVerts = new NativeArray <Vector3>(bodyVerts, Allocator.Persistent); kabschVerts = new NativeArray <Vector4>(Array.ConvertAll(bodyVerts.ToArray(), (p => new Vector4(p.x, p.y, p.z, 1f))), Allocator.Persistent); int[] triangles = bodyMesh.triangles; Vector3Int[] tris = new Vector3Int[triangles.Length / 3]; for (int i = 0; i < tris.Length; i++) { tris[i] = new Vector3Int(triangles[i * 3], triangles[(i * 3) + 1], triangles[(i * 3) + 2]); } bodyTriangles = new NativeArray <Vector3Int>(tris, Allocator.Persistent); bodyNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); renderNormals = new NativeArray <Vector3>(bodyMesh.normals, Allocator.Persistent); prevBodyVerts = new NativeArray <Vector3>(new Vector3[bodyVerts.Length], Allocator.Persistent); accumulatedDisplacements = new NativeArray <Vector4>(new Vector4[bodyVerts.Length], Allocator.Persistent); for (int i = 0; i < bodyVerts.Length; i++) { prevBodyVerts[i] = transform.TransformPoint(bodyVerts[i]); } raycasts = new NativeArray <RaycastCommand>(new RaycastCommand[bodyVerts.Length], Allocator.Persistent); raycastHits = new NativeArray <RaycastHit>(new RaycastHit[bodyVerts.Length], Allocator.Persistent); constraintsArray = new NativeArray <Verlet.DistConstraint>(constraintsList.ToArray(), Allocator.Persistent); dilationDistance = new NativeArray <float>(new float[1], Allocator.Persistent); triangleVolumes = new NativeArray <float>(new float[tris.Length], Allocator.Persistent); triangleSurfaceAreas = new NativeArray <float>(new float[tris.Length], Allocator.Persistent); volumeAccumulator = new NativeAccumulator <float, Addition>(Allocator.Persistent); areaAccumulator = new NativeAccumulator <float, Addition>(Allocator.Persistent); initialVolume = Verlet.VolumeOfMesh(bodyVerts, bodyTriangles); initialSurfaceArea = Verlet.SurfaceAreaOfMesh(bodyVerts, bodyTriangles); previousDeltaTime = 1f; dilationDistance[0] = 0f; this.scaledGravity = scaledGravity; localToWorld = transform.localToWorldMatrix; worldToLocal = transform.worldToLocalMatrix; groundPlanePos = ground.position; groundPlaneNormal = -ground.forward; this.radius = radius; this.friction = friction; //Set up parallel normal accumulation triangleGraph = new NativeArray <vertexTriangles>(new vertexTriangles[bodyVerts.Length], Allocator.Persistent); for (int i = 0; i < triangleGraph.Length; i++) { triangleGraph[i] = new vertexTriangles(-1); } for (int i = 0; i < tris.Length; i++) { triangleGraph[tris[i].x] = triangleGraph[tris[i].x].Add(tris[i]); triangleGraph[tris[i].y] = triangleGraph[tris[i].y].Add(tris[i]); triangleGraph[tris[i].z] = triangleGraph[tris[i].z].Add(tris[i]); } //Set up parallel constraint satisfaction connectionGraph = new NativeArray <vertexConstraints>(new vertexConstraints[bodyVerts.Length], Allocator.Persistent); for (int i = 0; i < connectionGraph.Length; i++) { connectionGraph[i] = new vertexConstraints(); } for (int i = 0; i < constraintsArray.Length; i++) { Verlet.DistConstraint constraint = constraintsArray[i]; connectionGraph[constraint.index1] = connectionGraph[constraint.index1].Add(constraint); int temp = constraint.index1; constraint.index1 = constraint.index2; constraint.index2 = temp; connectionGraph[constraint.index1] = connectionGraph[constraint.index1].Add(constraint); } }