public void OnDrawGizmosSelected() { if (debugDisplayMappedBoneGizmos) { Gizmos.color = Color.blue; for (int i = 0; i < bone2idxMap.Length; i++) { if (bone2idxMap[i].bone != null) { BoneAndNode bn = bone2idxMap[i]; Gizmos.color = Color.blue; Gizmos.DrawWireSphere(bn.bone.transform.position, .1f); } } } if (debugDisplayMappedAnchors) { Gizmos.color = Color.blue; for (int i = 0; i < anchors.Length; i++) { for (int j = 0; j < anchors[i].anchorNodeIndexes.Count; j++) { Vector3 pos = transform.TransformPoint(anchors[i].anchorPosition[j]); Gizmos.DrawWireSphere(pos, .1f); } } } }
public void LateUpdate() { if (isInWorld) { //Read the positions of the bones from the physics simulation DumpDataFromBullet(); //Update bone positions and orientaion based on bullet data for (int i = 0; i < bone2idxMap.Length; i++) { BoneAndNode bn = bone2idxMap[i]; bn.bone.position = verts[bn.nodeIdx]; //To update the orientation we need to see how the normal and one vertex moved //todo check magnitude and loop over edges if first doesn't work Vector3 edgeXnorm = Vector3.Cross(verts[bn.edges[0].nodeIdx] - verts[bn.nodeIdx], norms[bn.nodeIdx]); edgeXnorm.Normalize(); Quaternion q = WahbasSolution(bn.bindNormal, bn.edges[0].bindEdgeXnorm, norms[bn.nodeIdx], edgeXnorm); bone2idxMap[i].bone.rotation = q * bn.bindBoneRotation; } if (debugDisplaySimulatedMesh) { if (myMesh == null) { myMesh = Instantiate(physicsSimMesh.sharedMesh); MeshFilter mf = physicsSimMesh.GetComponent <MeshFilter>(); mf.sharedMesh = myMesh; } if (localVerts == null || localVerts.Length != verts.Length) { localVerts = new Vector3[verts.Length]; localNorms = new Vector3[norms.Length]; } for (int i = 0; i < verts.Length; i++) { localVerts[i] = physicsSimMesh.transform.InverseTransformPoint(verts[i]) + debugSimMeshOffset; localNorms[i] = physicsSimMesh.transform.InverseTransformDirection(norms[i]); } myMesh.vertices = localVerts; myMesh.normals = localNorms; myMesh.RecalculateBounds(); } } }
public void OnDrawGizmosSelected() { /* * for (int i = 0; i < bone2idxMap.Length; i++) * { * if (i == 1 && verts != null && verts.Length > 0) * { * Gizmos.color = Color.magenta; * for (int j = 0; j < bone2idxMap[i].edges.Length; j++) * { * Gizmos.DrawLine(verts[bone2idxMap[i].nodeIdx], verts[bone2idxMap[i].edges[j].nodeIdx]); * Gizmos.color = Gizmos.color * .75f; * } * } * } */ if (debugDisplayMappedBoneGizmos) { Gizmos.color = Color.blue; for (int i = 0; i < bone2idxMap.Length; i++) { if (bone2idxMap[i].bone != null) { BoneAndNode bn = bone2idxMap[i]; Gizmos.color = Color.blue; Gizmos.DrawWireSphere(bn.bone.transform.position, .1f); /* * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bindNormal); * Gizmos.color = Color.magenta * .6f; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].edges[0].bindEdgeXnorm); * Gizmos.color = Color.green; * Gizmos.DrawRay(bone2idxMap[i].bone.position, norms[bone2idxMap[i].nodeIdx]); * Vector3 edgeXnorm = Vector3.Cross(verts[bn.edges[0].nodeIdx] - verts[bn.nodeIdx], norms[bn.nodeIdx]); * edgeXnorm.Normalize(); * Gizmos.color = Color.green * .6f; * Gizmos.DrawRay(bone2idxMap[i].bone.position, edgeXnorm); */ /* * Gizmos.color = Color.red; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bone.right); * Gizmos.color = Color.green; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bone.up); * Gizmos.color = Color.blue; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bone.forward); * * Gizmos.color = Color.red * .6f; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bindBoneRotation * Vector3.forward); * Gizmos.color = Color.green * .6f; ; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bindBoneRotation * Vector3.up); * Gizmos.color = Color.blue * .6f; * Gizmos.DrawRay(bone2idxMap[i].bone.position, bone2idxMap[i].bindBoneRotation * Vector3.right); */ } } } if (debugDisplayMappedAnchors) { Gizmos.color = Color.blue; for (int i = 0; i < anchors.Length; i++) { for (int j = 0; j < anchors[i].anchorNodeIndexes.Count; j++) { Vector3 pos = transform.TransformPoint(anchors[i].anchorPosition[j]); Gizmos.DrawWireSphere(pos, .1f); } } } }
// Use this for initialization public void BindBonesToSoftBodyAndNodesToAnchors() { if (transform.localScale != Vector3.one) { Debug.LogError("The scale must be 1,1,1"); return; } if (skinnedMesh == null) { Debug.LogError("The Skinned Mesh field has not been assigned."); return; } physicsSimMesh = GetComponent <MeshFilter>(); if (physicsSimMesh == null) { Debug.LogError("Must be attached to an object with a MeshRenderer"); return; } if (physicsSimMesh == null) { Debug.LogError("must add the physics sim mesh bone"); return; } for (int i = 0; i < anchors.Length; i++) { BAnchor a = anchors[i]; if (a.colRangeTo <= a.colRangeFrom) { Debug.LogError("Error with Anchor row " + i + " ColRangeTo must be greater than colRangeFrom."); } for (int j = i + 1; j < anchors.Length; j++) { BAnchor b = anchors[j]; if (b.colRangeFrom >= a.colRangeTo && b.colRangeTo >= a.colRangeTo) { //good } else if (b.colRangeFrom <= a.colRangeFrom && b.colRangeTo <= a.colRangeFrom) { //good } else { Debug.LogErrorFormat("The color ranges of Anchors {0} and {1} overlap", i, j); } } } //get bones and mesh verts //compare these in world space to see which ones line up //TODO why does other mesh shape work better than this one. Transform[] bones = skinnedMesh.bones; Mesh m = physicsSimMesh.sharedMesh; Vector3[] verts = m.vertices; Vector3[] norms = m.normals; Color[] cols = m.colors; int[] triangles = m.triangles; if (cols.Length != verts.Length) { Debug.LogError("The physics sim mesh had no colors. Colors are needed to identify the anchor bones."); } //check for duplicate verts int numDuplicated = 0; for (int i = 0; i < verts.Length; i++) { for (int j = i + 1; j < verts.Length; j++) { if (verts[i] == verts[j]) { numDuplicated++; } } } if (numDuplicated > 0) { Debug.LogError("The physics sim mesh has " + numDuplicated + " duplicated vertices. Check that the mesh does not have hard edges and that there are no UVs."); } List <BoneAndNode> foundMatches = new List <BoneAndNode>(); for (int i = 0; i < verts.Length; i++) { for (int j = 0; j < bones.Length; j++) { Vector3 worldSpaceVert = physicsSimMesh.transform.TransformPoint(verts[i]); Vector3 worldSpaceBone = bones[j].position; if (Vector3.Distance(worldSpaceBone, worldSpaceVert) < radius) { //Debug.Log("found a bone that is aligned with a vertex " + bones[j]); BoneAndNode ban = new BoneAndNode(); ban.bone = bones[j]; ban.nodeIdx = i; foundMatches.Add(ban); } } } bone2idxMap = foundMatches.ToArray(); for (int i = 0; i < bone2idxMap.Length; i++) { int idx = bone2idxMap[i].nodeIdx; List <Edge> edges = new List <Edge>(); for (int j = 0; j < triangles.Length; j += 3) { if (triangles[j] == idx) { _addEdges(idx, triangles[j + 1], triangles[j + 2], edges, norms, verts); } else if (triangles[j + 1] == idx) { _addEdges(idx, triangles[j], triangles[j + 2], edges, norms, verts); } else if (triangles[j + 2] == idx) { _addEdges(idx, triangles[j], triangles[j + 1], edges, norms, verts); } } edges.Sort(); bone2idxMap[i].edges = edges.ToArray(); } // clear old values for (int j = 0; j < anchors.Length; j++) { anchors[j].anchorNodeIndexes.Clear(); anchors[j].anchorNodeStrength.Clear(); anchors[j].anchorPosition.Clear(); } int numAnchorNodes = 0; for (int i = 0; i < cols.Length; i++) { for (int j = 0; j < anchors.Length; j++) { if (cols[i].g > anchors[j].colRangeFrom && cols[i].g < anchors[j].colRangeTo) { anchors[j].anchorNodeIndexes.Add(i); anchors[j].anchorNodeStrength.Add(cols[i].r); anchors[j].anchorPosition.Add(verts[i]); numAnchorNodes++; } } } SoftBody sb = (SoftBody)m_collisionObject; Debug.LogFormat("Done binding bones to nodes and nodes to anchors. Found: {0} bones and {1} anchor nodes.", bone2idxMap.Length, numAnchorNodes); }