BindingHelper.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. namespace VertexAnimationTools_30 {
  5. public class BindingHelper {
  6. struct Edge {
  7. public int A;
  8. public int B;
  9. Vector3 pA;
  10. Vector3 pB;
  11. Vector3 ab;
  12. float length;
  13. float length2;
  14. public Edge(int idxa, int idxb ) {
  15. A = idxa;
  16. B = idxb;
  17. pA = Vector3.zero;
  18. pB = Vector3.zero;
  19. ab = Vector3.zero;
  20. length = 0;
  21. length2 = 0;
  22. }
  23. public void SetVertices(Vector3[] verts) {
  24. pA = verts[A];
  25. pB = verts[B];
  26. ab = pB - pA;
  27. length = ab.magnitude;
  28. length2 = length * length;
  29. }
  30. public override int GetHashCode() {
  31. unchecked {
  32. int min = A;
  33. int max = B;
  34. if (A > B) {
  35. min = B;
  36. max = A;
  37. }
  38. return (min.ToString() + max.ToString()).GetHashCode();
  39. }
  40. }
  41. public override bool Equals(object obj) {
  42. Edge other = (Edge)obj;
  43. return other.GetHashCode() == this.GetHashCode();
  44. }
  45. public float GetDistance(Vector3 point, ref float lv) {
  46. Vector3 ap = point - pA;
  47. float u = Vector3.Dot(ap, ab) / length2;
  48. Vector3 nearestPoint = Vector3.zero;
  49. if (u < 0) {
  50. lv = 0;
  51. nearestPoint = pA;
  52. } else if (u > 1) {
  53. lv = 1f;
  54. nearestPoint = pB;
  55. } else {
  56. lv = u;
  57. nearestPoint = pA + ab * u;
  58. }
  59. return Vector3.Distance(nearestPoint, point);
  60. }
  61. }
  62. public MeshCollider mc;
  63. public MeshCollider imc;
  64. public int[] tris;
  65. public Matrix4x4 ltw;
  66. public Vector3[] dirs;
  67. Vector3[] vertices;
  68. Vector3[] normals;
  69. Vector3[] tangents;
  70. HashSet<Edge> edges;
  71. Edge[] edgesArr ;
  72. public BindingHelper(Mesh snapshot, Transform tr) {
  73. System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
  74. ltw = tr.transform.localToWorldMatrix;
  75. Mesh colliderMesh = snapshot;
  76. GameObject go = new GameObject();
  77. go.hideFlags = HideFlags.HideAndDontSave;
  78. go.transform.position = tr.position;
  79. go.transform.rotation = tr.rotation;
  80. go.transform.localScale = tr.localScale;
  81. mc = go.AddComponent<MeshCollider>();
  82. mc.sharedMesh = colliderMesh;
  83. go.AddComponent<MeshFilter>().sharedMesh = colliderMesh;
  84. go.AddComponent<MeshRenderer>();
  85. tris = colliderMesh.triangles;
  86. Mesh icolliderMesh = Object.Instantiate(colliderMesh);
  87. GameObject igo = new GameObject();
  88. igo.hideFlags = HideFlags.HideAndDontSave;
  89. igo.transform.position = tr.position;
  90. igo.transform.rotation = tr.rotation;
  91. igo.transform.localScale = tr.localScale;
  92. imc = igo.AddComponent<MeshCollider>();
  93. int[] itris = icolliderMesh.triangles;
  94. edges = new HashSet<Edge>();
  95. for (int r = 0; r < tris.Length; r += 3) {
  96. int t0 = itris[r + 2];
  97. int t1 = itris[r + 1];
  98. int t2 = itris[r];
  99. itris[r] = t0;
  100. itris[r + 1] = t1;
  101. itris[r + 2] = t2;
  102. Edge e0 = new Edge(t0, t1);
  103. Edge e1 = new Edge(t1, t2);
  104. Edge e2 = new Edge(t2, t0);
  105. if (!edges.Contains(e0)) {
  106. edges.Add(e0);
  107. }
  108. if (!edges.Contains(e1)) {
  109. edges.Add(e1);
  110. }
  111. if (!edges.Contains(e2)) {
  112. edges.Add(e2);
  113. }
  114. }
  115. icolliderMesh.triangles = itris;
  116. imc.sharedMesh = icolliderMesh;
  117. edgesArr = new Edge[edges.Count];
  118. edges.CopyTo(edgesArr);
  119. ProjectionSamples ps = ProjectionSamples.Get;
  120. dirs = ps.SphereSamples[4].Dirs;
  121. sw.Stop();
  122. }
  123. public void SetVertices(Vector3[] _vertices, Vector3[] _normals, Vector3[] _tangents) {
  124. vertices = Extension.Copy(_vertices);
  125. normals = Extension.Copy(_normals);
  126. tangents = Extension.Copy(_tangents);
  127. }
  128. public Matrix4x4 GetTrisTM(int idxa, int idxb, int idxc, Vector3 bary) {
  129. Vector3 a = vertices[idxa];
  130. Vector3 b = vertices[idxb];
  131. Vector3 c = vertices[idxc];
  132. Vector3 na = normals[idxa];
  133. Vector3 nb = normals[idxb];
  134. Vector3 nc = normals[idxc];
  135. Vector3 ta = tangents[idxa];
  136. Vector3 tb = tangents[idxb];
  137. Vector3 tc = tangents[idxc];
  138. Vector3 trisCenter = a * bary.x + b * bary.y + c * bary.z;
  139. Vector3 averageUp = na * bary.x + nb * bary.y + nc * bary.z;
  140. Vector3 xDir = ta * bary.x + tb * bary.y + tc * bary.z;
  141. Vector3 zDir = Vector3.Cross(xDir, averageUp);
  142. Matrix4x4 res = Matrix4x4.identity;
  143. res.SetColumn(0, (Vector4)xDir);
  144. res.SetColumn(1, (Vector4)averageUp);
  145. res.SetColumn(2, (Vector4)zDir);
  146. res.SetColumn(3, trisCenter);
  147. res[15] = 1;
  148. return res;
  149. }
  150. public void Bind(PFU objSpacePFU, ref BindInfo bi) {
  151. float minDist = float.MaxValue;
  152. RaycastHit rh = new RaycastHit();
  153. Vector3 constraintPos = ltw.MultiplyPoint3x4(objSpacePFU.P);
  154. float lv = -1;
  155. for (int e = 0; e < edgesArr.Length; e++) {
  156. edgesArr[e].SetVertices(vertices);
  157. float d = edgesArr[e].GetDistance(objSpacePFU.P, ref lv);
  158. if (d < minDist) {
  159. bi.VidxA = edgesArr[e].A;
  160. bi.VidxB = edgesArr[e].B;
  161. bi.VidxC = edgesArr[e].B;
  162. minDist = d;
  163. bi.Bary = new Vector3(1f - lv, lv, 0);
  164. }
  165. }
  166. for (int i = 0; i < dirs.Length; i++) {
  167. Ray r = new Ray(constraintPos, dirs[i]);
  168. if (imc.Raycast(r, out rh, float.MaxValue)) {
  169. //Debug.LogFormat("to edge {0} dist:{1}", e, d);
  170. if (rh.distance < minDist) {
  171. bi.VidxA = tris[rh.triangleIndex * 3 + 2];
  172. bi.VidxB = tris[rh.triangleIndex * 3 + 1];
  173. bi.VidxC = tris[rh.triangleIndex * 3];
  174. minDist = rh.distance;
  175. bi.Bary = rh.barycentricCoordinate;
  176. }
  177. }
  178. if (mc.Raycast(r, out rh, float.MaxValue)) {
  179. if (rh.distance < minDist) {
  180. bi.VidxA = tris[rh.triangleIndex * 3];
  181. bi.VidxB = tris[rh.triangleIndex * 3 + 1];
  182. bi.VidxC = tris[rh.triangleIndex * 3 + 2];
  183. minDist = rh.distance;
  184. bi.Bary = rh.barycentricCoordinate;
  185. }
  186. }
  187. }
  188. bi.TrisSpace = objSpacePFU * GetTrisTM(bi.VidxA, bi.VidxB, bi.VidxC, bi.Bary).inverse;
  189. }
  190. public void Delete() {
  191. Object.DestroyImmediate(mc.gameObject);
  192. Object.DestroyImmediate(imc.gameObject);
  193. }
  194. }
  195. }