MB3_MeshCombinerSimpleData.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Specialized;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Text;
  7. using DigitalOpus.MB.Core;
  8. namespace DigitalOpus.MB.Core
  9. {
  10. /// <summary>
  11. /// Manages a single combined mesh.This class is the core of the mesh combining API.
  12. ///
  13. /// It is not a component so it can be can be instantiated and used like a normal c sharp class.
  14. /// </summary>
  15. public partial class MB3_MeshCombinerSingle : MB3_MeshCombiner
  16. {
  17. public enum MeshCreationConditions
  18. {
  19. NoMesh,
  20. CreatedInEditor,
  21. CreatedAtRuntime,
  22. AssignedByUser,
  23. }
  24. //2D arrays are not serializable but arrays of arrays are.
  25. [System.Serializable]
  26. public class SerializableIntArray
  27. {
  28. public int[] data;
  29. public SerializableIntArray() { }
  30. public SerializableIntArray(int len)
  31. {
  32. data = new int[len];
  33. }
  34. }
  35. /*
  36. Stores information about one source game object that has been added to
  37. the combined mesh.
  38. */
  39. [System.Serializable]
  40. public class MB_DynamicGameObject : IComparable<MB_DynamicGameObject>
  41. {
  42. public int instanceID;
  43. public GameObject gameObject;
  44. public string name;
  45. public int vertIdx;
  46. public int blendShapeIdx;
  47. public int numVerts;
  48. public int numBlendShapes;
  49. //distinct list of bones in the bones array
  50. public int[] indexesOfBonesUsed = new int[0];
  51. //public Transform[] _originalBones; //used only for integrity checking
  52. //public Matrix4x4[] _originalBindPoses; //used only for integrity checking
  53. public int lightmapIndex = -1;
  54. public Vector4 lightmapTilingOffset = new Vector4(1f, 1f, 0f, 0f);
  55. public Vector3 meshSize = Vector3.one; // in world coordinates
  56. public bool show = true;
  57. public bool invertTriangles = false;
  58. /// <summary>
  59. /// combined mesh will have one submesh per result material
  60. /// source meshes can have any number of submeshes.They are mapped to a result submesh based on their material
  61. /// if two different submeshes have the same material they are merged in the same result submesh
  62. /// </summary>
  63. // These are result mesh submeshCount comine these into a class.
  64. public int[] submeshTriIdxs;
  65. public int[] submeshNumTris;
  66. /// <summary>
  67. /// These are source go mesh submeshCount todo combined these into a class.
  68. /// Maps each submesh in source mesh to a submesh in combined mesh.
  69. /// </summary>
  70. public int[] targetSubmeshIdxs;
  71. /// <summary>
  72. /// The UVRects in the combinedMaterial atlas.
  73. /// </summary>
  74. public Rect[] uvRects;
  75. /// <summary>
  76. /// If AllPropsUseSameMatTiling is the rect that was used for sampling the atlas texture from the source texture including both mesh uvTiling and material tiling.
  77. /// else is the source mesh obUVrect. We don't need to care which.
  78. /// </summary>
  79. public Rect[] encapsulatingRect;
  80. /// <summary>
  81. /// If AllPropsUseSameMatTiling is the source texture material tiling.
  82. /// else is 0,0,1,1. We don't need to care which.
  83. /// </summary>
  84. public Rect[] sourceMaterialTiling;
  85. /// <summary>
  86. /// The obUVRect for each source mesh submesh;
  87. /// </summary>
  88. public Rect[] obUVRects;
  89. /// <summary>
  90. /// The index of the texture array slice.
  91. /// </summary>
  92. public int[] textureArraySliceIdx;
  93. public Material[] sourceSharedMaterials;
  94. public bool _beingDeleted = false;
  95. public int _triangleIdxAdjustment = 0;
  96. //used so we don't have to call GetBones and GetBindposes twice
  97. [NonSerialized]
  98. public SerializableIntArray[] _tmpSubmeshTris;
  99. [NonSerialized]
  100. public Transform[] _tmpCachedBones;
  101. [NonSerialized]
  102. public Matrix4x4[] _tmpCachedBindposes;
  103. [NonSerialized]
  104. public BoneWeight[] _tmpCachedBoneWeights;
  105. [NonSerialized]
  106. public int[] _tmpIndexesOfSourceBonesUsed;
  107. public int CompareTo(MB_DynamicGameObject b)
  108. {
  109. return this.vertIdx - b.vertIdx;
  110. }
  111. }
  112. //if baking many instances of the same sharedMesh, want to cache these results rather than grab them multiple times from the mesh
  113. public class MeshChannels
  114. {
  115. public Vector3[] vertices;
  116. public Vector3[] normals;
  117. public Vector4[] tangents;
  118. public Vector2[] uv0raw;
  119. public Vector2[] uv0modified;
  120. public Vector2[] uv2;
  121. public Vector2[] uv3;
  122. public Vector2[] uv4;
  123. public Vector2[] uv5;
  124. public Vector2[] uv6;
  125. public Vector2[] uv7;
  126. public Vector2[] uv8;
  127. public Color[] colors;
  128. public BoneWeight[] boneWeights;
  129. public Matrix4x4[] bindPoses;
  130. public int[] triangles;
  131. public MBBlendShape[] blendShapes;
  132. }
  133. [Serializable]
  134. public class MBBlendShapeFrame
  135. {
  136. public float frameWeight;
  137. public Vector3[] vertices;
  138. public Vector3[] normals;
  139. public Vector3[] tangents;
  140. }
  141. [Serializable]
  142. public class MBBlendShape
  143. {
  144. public int gameObjectID;
  145. public GameObject gameObject;
  146. public string name;
  147. public int indexInSource;
  148. public MBBlendShapeFrame[] frames;
  149. }
  150. public class MeshChannelsCache
  151. {
  152. MB2_LogLevel LOG_LEVEL;
  153. MB2_LightmapOptions lightmapOption;
  154. protected Dictionary<int, MeshChannels> meshID2MeshChannels = new Dictionary<int, MeshChannels>();
  155. public MeshChannelsCache(MB2_LogLevel ll, MB2_LightmapOptions lo)
  156. {
  157. LOG_LEVEL = ll;
  158. lightmapOption = lo;
  159. }
  160. internal Vector3[] GetVertices(Mesh m)
  161. {
  162. MeshChannels mc;
  163. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  164. {
  165. mc = new MeshChannels();
  166. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  167. }
  168. if (mc.vertices == null)
  169. {
  170. mc.vertices = m.vertices;
  171. }
  172. return mc.vertices;
  173. }
  174. internal Vector3[] GetNormals(Mesh m)
  175. {
  176. MeshChannels mc;
  177. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  178. {
  179. mc = new MeshChannels();
  180. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  181. }
  182. if (mc.normals == null)
  183. {
  184. mc.normals = _getMeshNormals(m);
  185. }
  186. return mc.normals;
  187. }
  188. internal Vector4[] GetTangents(Mesh m)
  189. {
  190. MeshChannels mc;
  191. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  192. {
  193. mc = new MeshChannels();
  194. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  195. }
  196. if (mc.tangents == null)
  197. {
  198. mc.tangents = _getMeshTangents(m);
  199. }
  200. return mc.tangents;
  201. }
  202. internal Vector2[] GetUv0Raw(Mesh m)
  203. {
  204. MeshChannels mc;
  205. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  206. {
  207. mc = new MeshChannels();
  208. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  209. }
  210. if (mc.uv0raw == null)
  211. {
  212. mc.uv0raw = _getMeshUVs(m);
  213. }
  214. return mc.uv0raw;
  215. }
  216. internal Vector2[] GetUv0Modified(Mesh m)
  217. {
  218. MeshChannels mc;
  219. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  220. {
  221. mc = new MeshChannels();
  222. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  223. }
  224. if (mc.uv0modified == null)
  225. {
  226. //todo
  227. mc.uv0modified = null;
  228. }
  229. return mc.uv0modified;
  230. }
  231. internal Vector2[] GetUVChannel(int channel, Mesh m)
  232. {
  233. MeshChannels mc;
  234. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  235. {
  236. mc = new MeshChannels();
  237. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  238. }
  239. switch(channel)
  240. {
  241. case 0:
  242. if (mc.uv0raw == null)
  243. {
  244. mc.uv0raw = GetUv0Raw(m);
  245. }
  246. return mc.uv0raw;
  247. case 2:
  248. if (mc.uv2 == null)
  249. {
  250. mc.uv2 = _getMeshUV2s(m);
  251. }
  252. return mc.uv2;
  253. case 3:
  254. if (mc.uv3 == null)
  255. {
  256. mc.uv3 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  257. }
  258. return mc.uv3;
  259. case 4:
  260. if (mc.uv4 == null)
  261. {
  262. mc.uv4 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  263. }
  264. return mc.uv4;
  265. case 5:
  266. if (mc.uv5 == null)
  267. {
  268. mc.uv5 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  269. }
  270. return mc.uv5;
  271. case 6:
  272. if (mc.uv6 == null)
  273. {
  274. mc.uv6 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  275. }
  276. return mc.uv6;
  277. case 7:
  278. if (mc.uv7 == null)
  279. {
  280. mc.uv7 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  281. }
  282. return mc.uv7;
  283. case 8:
  284. if (mc.uv8 == null)
  285. {
  286. mc.uv8 = MBVersion.GetMeshChannel(channel, m, LOG_LEVEL);
  287. }
  288. return mc.uv8;
  289. default:
  290. Debug.LogError("Error mesh channel " + channel + " not supported");
  291. break;
  292. }
  293. return null;
  294. }
  295. internal Color[] GetColors(Mesh m)
  296. {
  297. MeshChannels mc;
  298. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  299. {
  300. mc = new MeshChannels();
  301. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  302. }
  303. if (mc.colors == null)
  304. {
  305. mc.colors = _getMeshColors(m);
  306. }
  307. return mc.colors;
  308. }
  309. internal Matrix4x4[] GetBindposes(Renderer r)
  310. {
  311. MeshChannels mc;
  312. Mesh m = MB_Utility.GetMesh(r.gameObject);
  313. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  314. {
  315. mc = new MeshChannels();
  316. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  317. }
  318. if (mc.bindPoses == null)
  319. {
  320. mc.bindPoses = _getBindPoses(r);
  321. }
  322. return mc.bindPoses;
  323. }
  324. internal BoneWeight[] GetBoneWeights(Renderer r, int numVertsInMeshBeingAdded)
  325. {
  326. MeshChannels mc;
  327. Mesh m = MB_Utility.GetMesh(r.gameObject);
  328. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  329. {
  330. mc = new MeshChannels();
  331. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  332. }
  333. if (mc.boneWeights == null)
  334. {
  335. mc.boneWeights = _getBoneWeights(r, numVertsInMeshBeingAdded);
  336. }
  337. return mc.boneWeights;
  338. }
  339. internal int[] GetTriangles(Mesh m)
  340. {
  341. MeshChannels mc;
  342. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  343. {
  344. mc = new MeshChannels();
  345. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  346. }
  347. if (mc.triangles == null)
  348. {
  349. mc.triangles = m.triangles;
  350. }
  351. return mc.triangles;
  352. }
  353. internal MBBlendShape[] GetBlendShapes(Mesh m, int gameObjectID, GameObject gameObject)
  354. {
  355. if (MBVersion.GetMajorVersion() > 5 ||
  356. ( MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3))
  357. {
  358. MeshChannels mc;
  359. if (!meshID2MeshChannels.TryGetValue(m.GetInstanceID(), out mc))
  360. {
  361. mc = new MeshChannels();
  362. meshID2MeshChannels.Add(m.GetInstanceID(), mc);
  363. }
  364. if (mc.blendShapes == null)
  365. {
  366. MBBlendShape[] shapes = new MBBlendShape[m.blendShapeCount];
  367. int arrayLen = m.vertexCount;
  368. for (int i = 0; i < shapes.Length; i++)
  369. {
  370. MBBlendShape shape = shapes[i] = new MBBlendShape();
  371. shape.frames = new MBBlendShapeFrame[MBVersion.GetBlendShapeFrameCount(m, i)];
  372. shape.name = m.GetBlendShapeName(i);
  373. shape.indexInSource = i;
  374. shape.gameObjectID = gameObjectID;
  375. shape.gameObject = gameObject;
  376. for (int j = 0; j < shape.frames.Length; j++)
  377. {
  378. MBBlendShapeFrame frame = shape.frames[j] = new MBBlendShapeFrame();
  379. frame.frameWeight = MBVersion.GetBlendShapeFrameWeight(m, i, j);
  380. frame.vertices = new Vector3[arrayLen];
  381. frame.normals = new Vector3[arrayLen];
  382. frame.tangents = new Vector3[arrayLen];
  383. MBVersion.GetBlendShapeFrameVertices(m, i, j, frame.vertices, frame.normals, frame.tangents);
  384. }
  385. }
  386. mc.blendShapes = shapes;
  387. return mc.blendShapes;
  388. }
  389. else
  390. { //copy cached blend shapes assigning a different gameObjectID
  391. MBBlendShape[] shapes = new MBBlendShape[mc.blendShapes.Length];
  392. for (int i = 0; i < shapes.Length; i++)
  393. {
  394. shapes[i] = new MBBlendShape();
  395. shapes[i].name = mc.blendShapes[i].name;
  396. shapes[i].indexInSource = mc.blendShapes[i].indexInSource;
  397. shapes[i].frames = mc.blendShapes[i].frames;
  398. shapes[i].gameObjectID = gameObjectID;
  399. shapes[i].gameObject = gameObject;
  400. }
  401. return shapes;
  402. }
  403. } else {
  404. return new MBBlendShape[0];
  405. }
  406. }
  407. Color[] _getMeshColors(Mesh m)
  408. {
  409. Color[] cs = m.colors;
  410. if (cs.Length == 0)
  411. {
  412. if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug("Mesh " + m + " has no colors. Generating");
  413. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have colors. Generating an array of white colors");
  414. cs = new Color[m.vertexCount];
  415. for (int i = 0; i < cs.Length; i++) { cs[i] = Color.white; }
  416. }
  417. return cs;
  418. }
  419. Vector3[] _getMeshNormals(Mesh m)
  420. {
  421. Vector3[] ns = m.normals;
  422. if (ns.Length == 0)
  423. {
  424. if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug("Mesh " + m + " has no normals. Generating");
  425. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have normals. Generating normals.");
  426. Mesh tempMesh = (Mesh)GameObject.Instantiate(m);
  427. tempMesh.RecalculateNormals();
  428. ns = tempMesh.normals;
  429. MB_Utility.Destroy(tempMesh);
  430. }
  431. return ns;
  432. }
  433. Vector4[] _getMeshTangents(Mesh m)
  434. {
  435. Vector4[] ts = m.tangents;
  436. if (ts.Length == 0)
  437. {
  438. if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug("Mesh " + m + " has no tangents. Generating");
  439. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have tangents. Generating tangents.");
  440. Vector3[] verts = m.vertices;
  441. Vector2[] uvs = GetUv0Raw(m);
  442. Vector3[] norms = _getMeshNormals(m);
  443. ts = new Vector4[m.vertexCount];
  444. for (int i = 0; i < m.subMeshCount; i++)
  445. {
  446. int[] tris = m.GetTriangles(i);
  447. _generateTangents(tris, verts, uvs, norms, ts);
  448. }
  449. }
  450. return ts;
  451. }
  452. Vector2 _HALF_UV = new Vector2(.5f, .5f);
  453. Vector2[] _getMeshUVs(Mesh m)
  454. {
  455. Vector2[] uv = m.uv;
  456. if (uv.Length == 0)
  457. {
  458. #if UNITY_EDITOR
  459. Debug.LogError("Mesh " + m + " has no uvs. Generating garbage uvs. Every UV = .5, .5");
  460. #endif
  461. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have uvs. Generating uvs.");
  462. uv = new Vector2[m.vertexCount];
  463. for (int i = 0; i < uv.Length; i++) { uv[i] = _HALF_UV; }
  464. }
  465. return uv;
  466. }
  467. Vector2[] _getMeshUV2s(Mesh m)
  468. {
  469. Vector2[] uv = m.uv2;
  470. if (uv.Length == 0)
  471. {
  472. #if UNITY_EDITOR
  473. Debug.LogError("Mesh " + m + " has no uv2s. Generating garbage UVs. Every UV = .5, .5");
  474. #endif
  475. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("Mesh " + m + " didn't have uv2s. Generating uv2s.");
  476. if (lightmapOption == MB2_LightmapOptions.copy_UV2_unchanged_to_separate_rects) Debug.LogError("Mesh " + m + " did not have a UV2 channel. Nothing to copy when trying to copy UV2 to separate rects. The combined mesh will not lightmap properly. Try using generate new uv2 layout.");
  477. uv = new Vector2[m.vertexCount];
  478. for (int i = 0; i < uv.Length; i++) { uv[i] = _HALF_UV; }
  479. }
  480. return uv;
  481. }
  482. public static Matrix4x4[] _getBindPoses(Renderer r)
  483. {
  484. if (r is SkinnedMeshRenderer)
  485. {
  486. return ((SkinnedMeshRenderer)r).sharedMesh.bindposes;
  487. }
  488. else if (r is MeshRenderer)
  489. {
  490. Matrix4x4 bindPose = Matrix4x4.identity;
  491. Matrix4x4[] poses = new Matrix4x4[1];
  492. poses[0] = bindPose;
  493. return poses;
  494. }
  495. else {
  496. Debug.LogError("Could not _getBindPoses. Object does not have a renderer");
  497. return null;
  498. }
  499. }
  500. public static BoneWeight[] _getBoneWeights(Renderer r, int numVertsInMeshBeingAdded)
  501. {
  502. if (r is SkinnedMeshRenderer)
  503. {
  504. return ((SkinnedMeshRenderer)r).sharedMesh.boneWeights;
  505. }
  506. else if (r is MeshRenderer)
  507. {
  508. BoneWeight bw = new BoneWeight();
  509. bw.boneIndex0 = bw.boneIndex1 = bw.boneIndex2 = bw.boneIndex3 = 0;
  510. bw.weight0 = 1f;
  511. bw.weight1 = bw.weight2 = bw.weight3 = 0f;
  512. BoneWeight[] bws = new BoneWeight[numVertsInMeshBeingAdded];
  513. for (int i = 0; i < bws.Length; i++) bws[i] = bw;
  514. return bws;
  515. }
  516. else {
  517. Debug.LogError("Could not _getBoneWeights. Object does not have a renderer");
  518. return null;
  519. }
  520. }
  521. void _generateTangents(int[] triangles, Vector3[] verts, Vector2[] uvs, Vector3[] normals, Vector4[] outTangents)
  522. {
  523. int triangleCount = triangles.Length;
  524. int vertexCount = verts.Length;
  525. Vector3[] tan1 = new Vector3[vertexCount];
  526. Vector3[] tan2 = new Vector3[vertexCount];
  527. for (int a = 0; a < triangleCount; a += 3)
  528. {
  529. int i1 = triangles[a + 0];
  530. int i2 = triangles[a + 1];
  531. int i3 = triangles[a + 2];
  532. Vector3 v1 = verts[i1];
  533. Vector3 v2 = verts[i2];
  534. Vector3 v3 = verts[i3];
  535. Vector2 w1 = uvs[i1];
  536. Vector2 w2 = uvs[i2];
  537. Vector2 w3 = uvs[i3];
  538. float x1 = v2.x - v1.x;
  539. float x2 = v3.x - v1.x;
  540. float y1 = v2.y - v1.y;
  541. float y2 = v3.y - v1.y;
  542. float z1 = v2.z - v1.z;
  543. float z2 = v3.z - v1.z;
  544. float s1 = w2.x - w1.x;
  545. float s2 = w3.x - w1.x;
  546. float t1 = w2.y - w1.y;
  547. float t2 = w3.y - w1.y;
  548. float rBot = (s1 * t2 - s2 * t1);
  549. if (rBot == 0f)
  550. {
  551. Debug.LogError("Could not compute tangents. All UVs need to form a valid triangles in UV space. If any UV triangles are collapsed, tangents cannot be generated.");
  552. return;
  553. }
  554. float r = 1.0f / rBot;
  555. Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
  556. Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
  557. tan1[i1] += sdir;
  558. tan1[i2] += sdir;
  559. tan1[i3] += sdir;
  560. tan2[i1] += tdir;
  561. tan2[i2] += tdir;
  562. tan2[i3] += tdir;
  563. }
  564. for (int a = 0; a < vertexCount; ++a)
  565. {
  566. Vector3 n = normals[a];
  567. Vector3 t = tan1[a];
  568. Vector3 tmp = (t - n * Vector3.Dot(n, t)).normalized;
  569. outTangents[a] = new Vector4(tmp.x, tmp.y, tmp.z);
  570. outTangents[a].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
  571. }
  572. }
  573. }
  574. //Used for comparing if skinned meshes use the same bone and bindpose.
  575. //Skinned meshes must be bound with the same TRS to share a bone.
  576. public struct BoneAndBindpose
  577. {
  578. public Transform bone;
  579. public Matrix4x4 bindPose;
  580. public BoneAndBindpose(Transform t, Matrix4x4 bp)
  581. {
  582. bone = t;
  583. bindPose = bp;
  584. }
  585. public override bool Equals(object obj)
  586. {
  587. if (obj is BoneAndBindpose)
  588. {
  589. if (bone == ((BoneAndBindpose)obj).bone && bindPose == ((BoneAndBindpose)obj).bindPose)
  590. {
  591. return true;
  592. }
  593. }
  594. return false;
  595. }
  596. public override int GetHashCode()
  597. {
  598. //OK if don't check bindPose well because bp should be the same
  599. return (bone.GetInstanceID() % 2147483647) ^ (int)bindPose[0, 0];
  600. }
  601. }
  602. }
  603. }