MegaAttach.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. using UnityEngine;
  2. [ExecuteInEditMode]
  3. public class MegaAttach : MonoBehaviour
  4. {
  5. public MegaModifiers target;
  6. [HideInInspector]
  7. public Vector3 BaryCoord = Vector3.zero;
  8. [HideInInspector]
  9. public int[] BaryVerts = new int[3];
  10. [HideInInspector]
  11. public bool attached = false;
  12. [HideInInspector]
  13. public Vector3 BaryCoord1 = Vector3.zero;
  14. [HideInInspector]
  15. public int[] BaryVerts1 = new int[3];
  16. public Vector3 attachforward = Vector3.forward;
  17. public Vector3 AxisRot = Vector3.zero;
  18. public float radius = 0.1f;
  19. public Vector3 up = Vector3.up;
  20. public bool worldSpace = false;
  21. Vector3 pt = Vector3.zero;
  22. Vector3 norm = Vector3.zero;
  23. public bool skinned;
  24. #if UNITY_5_OR_NEWER
  25. public bool usebakedmesh = true;
  26. #endif
  27. [ContextMenu("Help")]
  28. public void Help()
  29. {
  30. Application.OpenURL("http://www.west-racing.com/mf/?page_id=2645");
  31. }
  32. public void DetachIt()
  33. {
  34. attached = false;
  35. }
  36. public void AttachIt()
  37. {
  38. if ( target )
  39. {
  40. attached = true;
  41. if ( !InitSkin() )
  42. {
  43. Mesh mesh = target.mesh;
  44. Vector3 objSpacePt = target.transform.InverseTransformPoint(pt);
  45. Vector3[] verts = target.sverts;
  46. int[] tris = mesh.triangles;
  47. int index = -1;
  48. MegaNearestPointTest.NearestPointOnMesh1(objSpacePt, verts, tris, ref index, ref BaryCoord);
  49. if ( index >= 0 )
  50. {
  51. BaryVerts[0] = tris[index];
  52. BaryVerts[1] = tris[index + 1];
  53. BaryVerts[2] = tris[index + 2];
  54. }
  55. MegaNearestPointTest.NearestPointOnMesh1(objSpacePt + attachforward, verts, tris, ref index, ref BaryCoord1);
  56. if ( index >= 0 )
  57. {
  58. BaryVerts1[0] = tris[index];
  59. BaryVerts1[1] = tris[index + 1];
  60. BaryVerts1[2] = tris[index + 2];
  61. }
  62. }
  63. }
  64. }
  65. public void AttachIt(Vector3 pos)
  66. {
  67. pt = pos;
  68. AttachIt();
  69. }
  70. void OnDrawGizmosSelected()
  71. {
  72. pt = transform.position;
  73. Gizmos.color = Color.white;
  74. Gizmos.DrawSphere(pt, radius);
  75. if ( target )
  76. {
  77. if ( attached )
  78. {
  79. SkinnedMeshRenderer skin = target.GetComponent<SkinnedMeshRenderer>();
  80. if ( skin )
  81. {
  82. Vector3 pos = transform.position;
  83. Vector3 worldPt = pos;
  84. Gizmos.color = Color.green;
  85. Gizmos.DrawSphere(worldPt, radius);
  86. }
  87. else
  88. {
  89. Vector3 pos = GetCoordMine(target.sverts[BaryVerts[0]], target.sverts[BaryVerts[1]], target.sverts[BaryVerts[2]], BaryCoord);
  90. Vector3 worldPt = target.transform.TransformPoint(pos);
  91. Gizmos.color = Color.green;
  92. Gizmos.DrawSphere(worldPt, radius);
  93. Vector3 nw = target.transform.TransformDirection(norm * 40.0f);
  94. Gizmos.DrawLine(worldPt, worldPt + nw);
  95. }
  96. }
  97. else
  98. {
  99. SkinnedMeshRenderer skin = target.GetComponent<SkinnedMeshRenderer>();
  100. if ( skin )
  101. {
  102. CalcSkinVerts();
  103. Mesh mesh = target.mesh;
  104. Vector3 objSpacePt = pt;
  105. Vector3[] verts = calcskinverts;
  106. int[] tris = mesh.triangles;
  107. int index = -1;
  108. Vector3 tribary = Vector3.zero;
  109. Vector3 meshPt = MegaNearestPointTest.NearestPointOnMesh1(objSpacePt, verts, tris, ref index, ref tribary);
  110. Vector3 worldPt = target.transform.TransformPoint(meshPt);
  111. if ( index >= 0 )
  112. {
  113. Vector3 cp2 = GetCoordMine(verts[tris[index]], verts[tris[index + 1]], verts[tris[index + 2]], tribary);
  114. worldPt = cp2;
  115. }
  116. Gizmos.color = Color.red;
  117. Gizmos.DrawSphere(worldPt, radius);
  118. Gizmos.color = Color.blue;
  119. meshPt = MegaNearestPointTest.NearestPointOnMesh1(objSpacePt + attachforward, verts, tris, ref index, ref tribary);
  120. Vector3 worldPt1 = meshPt;
  121. Gizmos.DrawSphere(worldPt1, radius);
  122. Gizmos.color = Color.yellow;
  123. Gizmos.DrawLine(worldPt, worldPt1);
  124. }
  125. else
  126. {
  127. Mesh mesh = target.mesh;
  128. Vector3 objSpacePt = target.transform.InverseTransformPoint(pt);
  129. Vector3[] verts = target.sverts;
  130. int[] tris = mesh.triangles;
  131. int index = -1;
  132. Vector3 tribary = Vector3.zero;
  133. Vector3 meshPt = MegaNearestPointTest.NearestPointOnMesh1(objSpacePt, verts, tris, ref index, ref tribary);
  134. Vector3 worldPt = target.transform.TransformPoint(meshPt);
  135. if ( index >= 0 )
  136. {
  137. Vector3 cp2 = GetCoordMine(verts[tris[index]], verts[tris[index + 1]], verts[tris[index + 2]], tribary);
  138. worldPt = target.transform.TransformPoint(cp2);
  139. }
  140. Gizmos.color = Color.red;
  141. Gizmos.DrawSphere(worldPt, radius);
  142. Gizmos.color = Color.blue;
  143. meshPt = MegaNearestPointTest.NearestPointOnMesh1(objSpacePt + attachforward, verts, tris, ref index, ref tribary);
  144. Vector3 worldPt1 = target.transform.TransformPoint(meshPt);
  145. Gizmos.DrawSphere(worldPt1, radius);
  146. Gizmos.color = Color.yellow;
  147. Gizmos.DrawLine(worldPt, worldPt1);
  148. }
  149. }
  150. }
  151. }
  152. void LateUpdate()
  153. {
  154. if ( attached )
  155. {
  156. if ( skinned )
  157. {
  158. GetSkinPos1();
  159. return;
  160. }
  161. if ( worldSpace )
  162. {
  163. Vector3 v0 = target.sverts[BaryVerts[0]];
  164. Vector3 v1 = target.sverts[BaryVerts[1]];
  165. Vector3 v2 = target.sverts[BaryVerts[2]];
  166. Vector3 pos = target.transform.localToWorldMatrix.MultiplyPoint(GetCoordMine(v0, v1, v2, BaryCoord));
  167. transform.position = pos;
  168. // Rotation
  169. Vector3 va = v1 - v0;
  170. Vector3 vb = v2 - v1;
  171. norm = Vector3.Cross(va, vb);
  172. v0 = target.sverts[BaryVerts1[0]];
  173. v1 = target.sverts[BaryVerts1[1]];
  174. v2 = target.sverts[BaryVerts1[2]];
  175. Vector3 fwd = target.transform.localToWorldMatrix.MultiplyPoint(GetCoordMine(v0, v1, v2, BaryCoord1)) - pos;
  176. Quaternion erot = Quaternion.Euler(AxisRot);
  177. Quaternion rot = Quaternion.LookRotation(fwd, norm) * erot;
  178. transform.rotation = rot;
  179. }
  180. else
  181. {
  182. Vector3 v0 = target.sverts[BaryVerts[0]];
  183. Vector3 v1 = target.sverts[BaryVerts[1]];
  184. Vector3 v2 = target.sverts[BaryVerts[2]];
  185. Vector3 pos = GetCoordMine(v0, v1, v2, BaryCoord);
  186. transform.localPosition = pos;
  187. // Rotation
  188. Vector3 va = v1 - v0;
  189. Vector3 vb = v2 - v1;
  190. norm = Vector3.Cross(va, vb);
  191. v0 = target.sverts[BaryVerts1[0]];
  192. v1 = target.sverts[BaryVerts1[1]];
  193. v2 = target.sverts[BaryVerts1[2]];
  194. Vector3 fwd = GetCoordMine(v0, v1, v2, BaryCoord1) - pos;
  195. Quaternion erot = Quaternion.Euler(AxisRot);
  196. Quaternion rot = Quaternion.LookRotation(fwd, norm) * erot;
  197. transform.localRotation = rot;
  198. }
  199. }
  200. }
  201. Vector3 GetCoordMine(Vector3 A, Vector3 B, Vector3 C, Vector3 bary)
  202. {
  203. Vector3 p = Vector3.zero;
  204. p.x = (bary.x * A.x) + (bary.y * B.x) + (bary.z * C.x);
  205. p.y = (bary.x * A.y) + (bary.y * B.y) + (bary.z * C.y);
  206. p.z = (bary.x * A.z) + (bary.y * B.z) + (bary.z * C.z);
  207. return p;
  208. }
  209. [System.Serializable]
  210. public class MegaSkinVert
  211. {
  212. public MegaSkinVert()
  213. {
  214. weights = new float[4];
  215. bones = new Transform[4];
  216. bindposes = new Matrix4x4[4];
  217. }
  218. public float[] weights;
  219. public Transform[] bones;
  220. public Matrix4x4[] bindposes;
  221. public int vert;
  222. }
  223. public MegaSkinVert[] skinverts;
  224. bool InitSkin()
  225. {
  226. if ( target )
  227. {
  228. SkinnedMeshRenderer skin = target.GetComponent<SkinnedMeshRenderer>();
  229. if ( skin )
  230. {
  231. Quaternion rot = transform.rotation;
  232. attachrot = Quaternion.identity;
  233. skinned = true;
  234. Mesh ms = skin.sharedMesh;
  235. Vector3 pt = transform.position;
  236. CalcSkinVerts();
  237. Vector3 objSpacePt = pt;
  238. Vector3[] verts = calcskinverts;
  239. int[] tris = ms.triangles;
  240. int index = -1;
  241. MegaNearestPointTest.NearestPointOnMesh1(objSpacePt, verts, tris, ref index, ref BaryCoord); //ref tribary);
  242. if ( index >= 0 )
  243. {
  244. BaryVerts[0] = tris[index];
  245. BaryVerts[1] = tris[index + 1];
  246. BaryVerts[2] = tris[index + 2];
  247. }
  248. MegaNearestPointTest.NearestPointOnMesh1(objSpacePt + attachforward, verts, tris, ref index, ref BaryCoord1);
  249. if ( index >= 0 )
  250. {
  251. BaryVerts1[0] = tris[index];
  252. BaryVerts1[1] = tris[index + 1];
  253. BaryVerts1[2] = tris[index + 2];
  254. }
  255. skinverts = new MegaSkinVert[6];
  256. for ( int i = 0; i < 3; i++ )
  257. {
  258. int vert = BaryVerts[i];
  259. BoneWeight bw = ms.boneWeights[vert];
  260. skinverts[i] = new MegaSkinVert();
  261. skinverts[i].vert = vert;
  262. skinverts[i].weights[0] = bw.weight0;
  263. skinverts[i].weights[1] = bw.weight1;
  264. skinverts[i].weights[2] = bw.weight2;
  265. skinverts[i].weights[3] = bw.weight3;
  266. skinverts[i].bones[0] = skin.bones[bw.boneIndex0];
  267. skinverts[i].bones[1] = skin.bones[bw.boneIndex1];
  268. skinverts[i].bones[2] = skin.bones[bw.boneIndex2];
  269. skinverts[i].bones[3] = skin.bones[bw.boneIndex3];
  270. skinverts[i].bindposes[0] = ms.bindposes[bw.boneIndex0];
  271. skinverts[i].bindposes[1] = ms.bindposes[bw.boneIndex1];
  272. skinverts[i].bindposes[2] = ms.bindposes[bw.boneIndex2];
  273. skinverts[i].bindposes[3] = ms.bindposes[bw.boneIndex3];
  274. }
  275. for ( int i = 3; i < 6; i++ )
  276. {
  277. int vert = BaryVerts1[i - 3];
  278. BoneWeight bw = ms.boneWeights[vert];
  279. skinverts[i] = new MegaSkinVert();
  280. skinverts[i].vert = vert;
  281. skinverts[i].weights[0] = bw.weight0;
  282. skinverts[i].weights[1] = bw.weight1;
  283. skinverts[i].weights[2] = bw.weight2;
  284. skinverts[i].weights[3] = bw.weight3;
  285. skinverts[i].bones[0] = skin.bones[bw.boneIndex0];
  286. skinverts[i].bones[1] = skin.bones[bw.boneIndex1];
  287. skinverts[i].bones[2] = skin.bones[bw.boneIndex2];
  288. skinverts[i].bones[3] = skin.bones[bw.boneIndex3];
  289. skinverts[i].bindposes[0] = ms.bindposes[bw.boneIndex0];
  290. skinverts[i].bindposes[1] = ms.bindposes[bw.boneIndex1];
  291. skinverts[i].bindposes[2] = ms.bindposes[bw.boneIndex2];
  292. skinverts[i].bindposes[3] = ms.bindposes[bw.boneIndex3];
  293. }
  294. GetSkinPos1();
  295. attachrot = Quaternion.Inverse(transform.rotation) * rot;
  296. return true;
  297. }
  298. else
  299. skinned = false;
  300. }
  301. return false;
  302. }
  303. public Quaternion attachrot = Quaternion.identity;
  304. Vector3 GetSkinPos(int i)
  305. {
  306. Vector3 pos = target.sverts[skinverts[i].vert];
  307. Vector3 bpos = skinverts[i].bindposes[0].MultiplyPoint(pos);
  308. Vector3 p = skinverts[i].bones[0].TransformPoint(bpos) * skinverts[i].weights[0];
  309. bpos = skinverts[i].bindposes[1].MultiplyPoint(pos);
  310. p += skinverts[i].bones[1].TransformPoint(bpos) * skinverts[i].weights[1];
  311. bpos = skinverts[i].bindposes[2].MultiplyPoint(pos);
  312. p += skinverts[i].bones[2].TransformPoint(bpos) * skinverts[i].weights[2];
  313. bpos = skinverts[i].bindposes[3].MultiplyPoint(pos);
  314. p += skinverts[i].bones[3].TransformPoint(bpos) * skinverts[i].weights[3];
  315. return p;
  316. }
  317. Vector3[] calcskinverts;
  318. void CalcSkinVerts()
  319. {
  320. if ( calcskinverts == null || calcskinverts.Length != target.sverts.Length )
  321. calcskinverts = new Vector3[target.sverts.Length];
  322. SkinnedMeshRenderer skin = target.GetComponent<SkinnedMeshRenderer>();
  323. Mesh mesh = target.mesh;
  324. Matrix4x4[] bindposes = mesh.bindposes;
  325. BoneWeight[] boneweights = mesh.boneWeights;
  326. for ( int i = 0; i < target.sverts.Length; i++ )
  327. {
  328. Vector3 p = Vector3.zero;
  329. Vector3 pos = target.sverts[i];
  330. Vector3 bpos = bindposes[boneweights[i].boneIndex0].MultiplyPoint(pos);
  331. p += skin.bones[boneweights[i].boneIndex0].TransformPoint(bpos) * boneweights[i].weight0;
  332. bpos = bindposes[boneweights[i].boneIndex1].MultiplyPoint(pos);
  333. p += skin.bones[boneweights[i].boneIndex1].TransformPoint(bpos) * boneweights[i].weight1;
  334. bpos = bindposes[boneweights[i].boneIndex2].MultiplyPoint(pos);
  335. p += skin.bones[boneweights[i].boneIndex2].TransformPoint(bpos) * boneweights[i].weight2;
  336. bpos = bindposes[boneweights[i].boneIndex3].MultiplyPoint(pos);
  337. p += skin.bones[boneweights[i].boneIndex3].TransformPoint(bpos) * boneweights[i].weight3;
  338. calcskinverts[i] = p;
  339. }
  340. }
  341. void GetSkinPos1()
  342. {
  343. Vector3 v0 = GetSkinPos(0);
  344. Vector3 v1 = GetSkinPos(1);
  345. Vector3 v2 = GetSkinPos(2);
  346. Vector3 pos = GetCoordMine(v0, v1, v2, BaryCoord);
  347. transform.position = pos;
  348. Vector3 va = v1 - v0;
  349. Vector3 vb = v2 - v1;
  350. norm = Vector3.Cross(va, vb);
  351. v0 = GetSkinPos(3);
  352. v1 = GetSkinPos(4);
  353. v2 = GetSkinPos(5);
  354. Vector3 fwd = GetCoordMine(v0, v1, v2, BaryCoord1) - pos;
  355. Quaternion erot = Quaternion.Euler(AxisRot);
  356. Quaternion rot = Quaternion.LookRotation(fwd, norm) * erot * attachrot;
  357. transform.rotation = rot;
  358. }
  359. }