GLTFNode.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Newtonsoft.Json;
  7. using Siccity.GLTFUtility.Converters;
  8. using UnityEngine;
  9. using UnityEngine.Scripting;
  10. namespace Siccity.GLTFUtility {
  11. // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#node
  12. [Preserve] public class GLTFNode {
  13. #region Serialization
  14. public string name;
  15. /// <summary> Indices of child nodes </summary>
  16. public int[] children;
  17. /// <summary> Local TRS </summary>
  18. [JsonConverter(typeof(Matrix4x4Converter))] public Matrix4x4 matrix = Matrix4x4.identity;
  19. /// <summary> Local position </summary>
  20. [JsonConverter(typeof(TranslationConverter))] public Vector3 translation = Vector3.zero;
  21. /// <summary> Local rotation </summary>
  22. [JsonConverter(typeof(QuaternionConverter))] public Quaternion rotation = Quaternion.identity;
  23. /// <summary> Local scale </summary>
  24. [JsonConverter(typeof(Vector3Converter))] public Vector3 scale = Vector3.one;
  25. public int? mesh;
  26. public int? skin;
  27. public int? camera;
  28. public int? weights;
  29. public bool ShouldSerializetranslation() { return translation != Vector3.zero; }
  30. public bool ShouldSerializerotation() { return rotation != Quaternion.identity; }
  31. public bool ShouldSerializescale() { return scale != Vector3.one; }
  32. #endregion
  33. #region Import
  34. public class ImportResult {
  35. public int? parent;
  36. public int[] children;
  37. public Transform transform;
  38. public bool IsRoot { get { return !parent.HasValue; } }
  39. }
  40. /// <summary> Set local position, rotation and scale </summary>
  41. public void ApplyTRS(Transform transform) {
  42. if(matrix!=Matrix4x4.identity)
  43. matrix.UnpackTRS(ref translation, ref rotation, ref scale);
  44. transform.localPosition = translation;
  45. transform.localRotation = rotation;
  46. transform.localScale = scale;
  47. }
  48. public class ImportTask : Importer.ImportTask<ImportResult[]> {
  49. List<GLTFNode> nodes;
  50. GLTFMesh.ImportTask meshTask;
  51. GLTFSkin.ImportTask skinTask;
  52. List<GLTFCamera> cameras;
  53. public ImportTask(List<GLTFNode> nodes, GLTFMesh.ImportTask meshTask, GLTFSkin.ImportTask skinTask, List<GLTFCamera> cameras) : base(meshTask, skinTask) {
  54. this.nodes = nodes;
  55. this.meshTask = meshTask;
  56. this.skinTask = skinTask;
  57. this.cameras = cameras;
  58. //task = new Task(() => { });
  59. }
  60. public override IEnumerator OnCoroutine(Action<float> onProgress = null) {
  61. // No nodes
  62. if (nodes == null) {
  63. if (onProgress != null) onProgress.Invoke(1f);
  64. IsCompleted = true;
  65. yield break;
  66. }
  67. Result = new ImportResult[nodes.Count];
  68. // Initialize transforms
  69. for (int i = 0; i < Result.Length; i++) {
  70. Result[i] = new GLTFNode.ImportResult();
  71. Result[i].transform = new GameObject().transform;
  72. Result[i].transform.name = nodes[i].name;
  73. }
  74. // Set up hierarchy
  75. for (int i = 0; i < Result.Length; i++) {
  76. if (nodes[i].children != null) {
  77. int[] children = nodes[i].children;
  78. Result[i].children = children;
  79. for (int k = 0; k < children.Length; k++) {
  80. int childIndex = children[k];
  81. Result[childIndex].parent = i;
  82. Result[childIndex].transform.parent = Result[i].transform;
  83. }
  84. }
  85. }
  86. // Apply TRS
  87. for (int i = 0; i < Result.Length; i++) {
  88. nodes[i].ApplyTRS(Result[i].transform);
  89. }
  90. // Setup components
  91. for (int i = 0; i < Result.Length; i++) {
  92. // Setup mesh
  93. if (nodes[i].mesh.HasValue) {
  94. GLTFMesh.ImportResult meshResult = meshTask.Result[nodes[i].mesh.Value];
  95. if (meshResult == null) continue;
  96. Mesh mesh = meshResult.mesh;
  97. Renderer renderer;
  98. if (nodes[i].skin.HasValue) {
  99. GLTFSkin.ImportResult skin = skinTask.Result[nodes[i].skin.Value];
  100. renderer = skin.SetupSkinnedRenderer(Result[i].transform.gameObject, mesh, Result);
  101. } else if (mesh.blendShapeCount > 0) {
  102. // Blend shapes require skinned mesh renderer
  103. SkinnedMeshRenderer mr = Result[i].transform.gameObject.AddComponent<SkinnedMeshRenderer>();
  104. mr.sharedMesh = mesh;
  105. renderer = mr;
  106. } else {
  107. MeshRenderer mr = Result[i].transform.gameObject.AddComponent<MeshRenderer>();
  108. MeshFilter mf = Result[i].transform.gameObject.AddComponent<MeshFilter>();
  109. renderer = mr;
  110. mf.sharedMesh = mesh;
  111. }
  112. //Materials
  113. renderer.materials = meshResult.materials;
  114. if (string.IsNullOrEmpty(Result[i].transform.name)) Result[i].transform.name = "node" + i;
  115. } else {
  116. if (string.IsNullOrEmpty(Result[i].transform.name)) Result[i].transform.name = "node" + i;
  117. }
  118. // Setup camera
  119. if (nodes[i].camera.HasValue) {
  120. GLTFCamera cameraData = cameras[nodes[i].camera.Value];
  121. Camera camera = Result[i].transform.gameObject.AddComponent<Camera>();
  122. Result[i].transform.localRotation = Result[i].transform.localRotation * Quaternion.Euler(0, 180, 0);
  123. if (cameraData.type == CameraType.orthographic) {
  124. camera.orthographic = true;
  125. camera.nearClipPlane = cameraData.orthographic.znear;
  126. camera.farClipPlane = cameraData.orthographic.zfar;
  127. camera.orthographicSize = cameraData.orthographic.ymag;
  128. } else {
  129. camera.orthographic = false;
  130. camera.nearClipPlane = cameraData.perspective.znear;
  131. if (cameraData.perspective.zfar.HasValue) camera.farClipPlane = cameraData.perspective.zfar.Value;
  132. if (cameraData.perspective.aspectRatio.HasValue) camera.aspect = cameraData.perspective.aspectRatio.Value;
  133. camera.fieldOfView = Mathf.Rad2Deg * cameraData.perspective.yfov;
  134. }
  135. }
  136. }
  137. IsCompleted = true;
  138. }
  139. }
  140. #endregion
  141. #region Export
  142. public class ExportResult : GLTFNode {
  143. [JsonIgnore] public MeshRenderer renderer;
  144. [JsonIgnore] public MeshFilter filter;
  145. [JsonIgnore] public SkinnedMeshRenderer skinnedRenderer;
  146. }
  147. public static List<ExportResult> Export(Transform root) {
  148. List<ExportResult> nodes = new List<ExportResult>();
  149. CreateNodeListRecursive(root, nodes);
  150. return nodes;
  151. }
  152. private static void CreateNodeListRecursive(Transform transform, List<ExportResult> nodes) {
  153. ExportResult node = new ExportResult();
  154. node.name = transform.name;
  155. node.translation = transform.localPosition;
  156. node.rotation = transform.localRotation;
  157. node.scale = transform.localScale;
  158. node.renderer = transform.gameObject.GetComponent<MeshRenderer>();
  159. node.filter = transform.gameObject.GetComponent<MeshFilter>();
  160. node.skinnedRenderer = transform.gameObject.GetComponent<SkinnedMeshRenderer>();
  161. nodes.Add(node);
  162. if (transform.childCount > 0) {
  163. if (transform.childCount > 0) {
  164. node.children = new int[transform.childCount];
  165. for (int i = 0; i < node.children.Length; i++) {
  166. Transform child = transform.GetChild(i);
  167. node.children[i] = nodes.Count;
  168. CreateNodeListRecursive(child, nodes);
  169. }
  170. }
  171. }
  172. }
  173. #endregion
  174. }
  175. public static class GLTFNodeExtensions {
  176. #region Import
  177. /// <summary> Returns the root if there is one, otherwise creates a new empty root </summary>
  178. public static GameObject GetRoot(this GLTFNode.ImportResult[] nodes) {
  179. GLTFNode.ImportResult[] roots = nodes.Where(x => x.IsRoot).ToArray();
  180. if (roots.Length == 1) return roots[0].transform.gameObject;
  181. else {
  182. GameObject root = new GameObject("Root");
  183. for (int i = 0; i < roots.Length; i++) {
  184. roots[i].transform.parent = root.transform;
  185. }
  186. return root;
  187. }
  188. }
  189. #endregion
  190. }
  191. }