GLTFSkin.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. using Newtonsoft.Json;
  5. using UnityEngine;
  6. using UnityEngine.Scripting;
  7. namespace Siccity.GLTFUtility {
  8. // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#skin
  9. [Preserve] public class GLTFSkin {
  10. /// <summary> Index of accessor containing inverse bind shape matrices </summary>
  11. public int? inverseBindMatrices;
  12. public int[] joints;
  13. public int? skeleton;
  14. public string name;
  15. public class ImportResult {
  16. public Matrix4x4[] inverseBindMatrices;
  17. public int[] joints;
  18. #region Import
  19. public SkinnedMeshRenderer SetupSkinnedRenderer(GameObject go, Mesh mesh, GLTFNode.ImportResult[] nodes) {
  20. SkinnedMeshRenderer smr = go.AddComponent<SkinnedMeshRenderer>();
  21. Transform[] bones = new Transform[joints.Length];
  22. for (int i = 0; i < bones.Length; i++) {
  23. int jointNodeIndex = joints[i];
  24. GLTFNode.ImportResult jointNode = nodes[jointNodeIndex];
  25. bones[i] = jointNode.transform;
  26. if (string.IsNullOrEmpty(jointNode.transform.name)) jointNode.transform.name = "joint" + i;
  27. }
  28. smr.bones = bones;
  29. smr.rootBone = bones[0];
  30. // Bindposes
  31. if (inverseBindMatrices != null) {
  32. if (inverseBindMatrices.Length != joints.Length) Debug.LogWarning("InverseBindMatrices count and joints count not the same");
  33. Matrix4x4 m = nodes[0].transform.localToWorldMatrix;
  34. Matrix4x4[] bindPoses = new Matrix4x4[joints.Length];
  35. for (int i = 0; i < joints.Length; i++) {
  36. bindPoses[i] = inverseBindMatrices[i];
  37. }
  38. mesh.bindposes = bindPoses;
  39. } else {
  40. Matrix4x4 m = nodes[0].transform.localToWorldMatrix;
  41. Matrix4x4[] bindPoses = new Matrix4x4[joints.Length];
  42. for (int i = 0; i < joints.Length; i++) {
  43. bindPoses[i] = nodes[joints[i]].transform.worldToLocalMatrix * m;
  44. }
  45. mesh.bindposes = bindPoses;
  46. }
  47. smr.sharedMesh = mesh;
  48. return smr;
  49. }
  50. }
  51. public ImportResult Import(GLTFAccessor.ImportResult[] accessors) {
  52. ImportResult result = new ImportResult();
  53. result.joints = joints;
  54. // Inverse bind matrices
  55. if (inverseBindMatrices.HasValue) {
  56. result.inverseBindMatrices = accessors[inverseBindMatrices.Value].ReadMatrix4x4();
  57. for (int i = 0; i < result.inverseBindMatrices.Length; i++) {
  58. // Flip the matrix from GLTF (right handed) to Unity (left handed) format.
  59. // This was done through comparing the GLTF matrix to
  60. // the correctly imported matrix from the source model,
  61. // and flipping the values where needed.
  62. // Notice how the rows become collumns
  63. Matrix4x4 m = result.inverseBindMatrices[i];
  64. Vector4 row0 = m.GetRow(0);
  65. row0.y = -row0.y;
  66. row0.z = -row0.z;
  67. Vector4 row1 = m.GetRow(1);
  68. row1.x = -row1.x;
  69. Vector4 row2 = m.GetRow(2);
  70. row2.x = -row2.x;
  71. Vector4 row3 = m.GetRow(3);
  72. row3.x = -row3.x;
  73. m.SetColumn(0, row0);
  74. m.SetColumn(1, row1);
  75. m.SetColumn(2, row2);
  76. m.SetColumn(3, row3);
  77. result.inverseBindMatrices[i] = m;
  78. }
  79. }
  80. return result;
  81. }
  82. public class ImportTask : Importer.ImportTask<ImportResult[]> {
  83. public ImportTask(List<GLTFSkin> skins, GLTFAccessor.ImportTask accessorTask) : base(accessorTask) {
  84. task = new Task(() => {
  85. if (skins == null) return;
  86. Result = new ImportResult[skins.Count];
  87. for (int i = 0; i < Result.Length; i++) {
  88. Result[i] = skins[i].Import(accessorTask.Result);
  89. }
  90. });
  91. }
  92. }
  93. #endregion
  94. }
  95. }