FbxExporter.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using UnityEngine;
  5. namespace UTJ.FbxExporter
  6. {
  7. public class FbxExporter
  8. {
  9. public FbxExporter(FbxExporter.ExportOptions opt)
  10. {
  11. this.m_opt = opt;
  12. }
  13. ~FbxExporter()
  14. {
  15. this.Release();
  16. }
  17. public void Release()
  18. {
  19. FbxExporter.fbxeReleaseContext(this.m_ctx);
  20. this.m_ctx = FbxExporter.Context.Null;
  21. }
  22. public bool CreateScene(string name)
  23. {
  24. this.Release();
  25. if (!this.m_ctx)
  26. {
  27. this.m_ctx = FbxExporter.fbxeCreateContext(ref this.m_opt);
  28. }
  29. this.m_nodes = new Dictionary<Transform, FbxExporter.Node>();
  30. return FbxExporter.fbxeCreateScene(this.m_ctx, name);
  31. }
  32. public void AddNode(GameObject go)
  33. {
  34. if (go)
  35. {
  36. this.FindOrCreateNodeTree(go.GetComponent<Transform>(), new Action<Transform, FbxExporter.Node>(this.ProcessNode));
  37. }
  38. }
  39. public bool WriteAsync(string path, FbxExporter.Format format)
  40. {
  41. return FbxExporter.fbxeWriteAsync(this.m_ctx, path, format);
  42. }
  43. public bool IsFinished()
  44. {
  45. return FbxExporter.fbxeIsFinished(this.m_ctx);
  46. }
  47. private void ProcessNode(Transform trans, FbxExporter.Node node)
  48. {
  49. MeshRenderer component = trans.GetComponent<MeshRenderer>();
  50. SkinnedMeshRenderer component2 = trans.GetComponent<SkinnedMeshRenderer>();
  51. Terrain component3 = trans.GetComponent<Terrain>();
  52. if (component3)
  53. {
  54. this.AddTerrain(node, component3);
  55. }
  56. else if (component2)
  57. {
  58. this.AddSkinnedMesh(node, component2);
  59. }
  60. else if (component)
  61. {
  62. this.AddMesh(node, component);
  63. }
  64. }
  65. private FbxExporter.Node FindOrCreateNodeTree(Transform trans, Action<Transform, FbxExporter.Node> act)
  66. {
  67. if (!trans)
  68. {
  69. return FbxExporter.Node.Null;
  70. }
  71. if (this.m_nodes.ContainsKey(trans))
  72. {
  73. return this.m_nodes[trans];
  74. }
  75. FbxExporter.Node parent = trans.parent ? this.FindOrCreateNodeTree(trans.parent, act) : FbxExporter.fbxeGetRootNode(this.m_ctx);
  76. FbxExporter.Node node = FbxExporter.fbxeCreateNode(this.m_ctx, parent, trans.name);
  77. if (this.m_opt.transform)
  78. {
  79. FbxExporter.fbxeSetTRS(this.m_ctx, node, trans.localPosition, trans.localRotation, trans.localScale);
  80. }
  81. this.m_nodes.Add(trans, node);
  82. if (act != null)
  83. {
  84. act(trans, node);
  85. }
  86. return node;
  87. }
  88. private bool AddMesh(FbxExporter.Node node, Mesh mesh)
  89. {
  90. if (!mesh || mesh.vertexCount == 0)
  91. {
  92. return false;
  93. }
  94. if (!mesh.isReadable)
  95. {
  96. Debug.LogWarning("Mesh " + mesh.name + " is not readable and be ignored.");
  97. return false;
  98. }
  99. FbxExporter.Topology topology = FbxExporter.Topology.Triangles;
  100. PinnedArray<int> pinnedArray = new PinnedArray<int>(mesh.triangles, false);
  101. PinnedArray<Vector3> pinnedArray2 = new PinnedArray<Vector3>(mesh.vertices, false);
  102. PinnedArray<Vector3> pinnedArray3 = new PinnedArray<Vector3>(mesh.normals, false);
  103. if (pinnedArray3.Length == 0)
  104. {
  105. pinnedArray3 = null;
  106. }
  107. PinnedArray<Vector4> pinnedArray4 = new PinnedArray<Vector4>(mesh.tangents, false);
  108. if (pinnedArray4.Length == 0)
  109. {
  110. pinnedArray4 = null;
  111. }
  112. PinnedArray<Vector2> pinnedArray5 = new PinnedArray<Vector2>(mesh.uv, false);
  113. if (pinnedArray5.Length == 0)
  114. {
  115. pinnedArray5 = null;
  116. }
  117. PinnedArray<Color> pinnedArray6 = new PinnedArray<Color>(mesh.colors, false);
  118. if (pinnedArray6.Length == 0)
  119. {
  120. pinnedArray6 = null;
  121. }
  122. FbxExporter.fbxeAddMesh(this.m_ctx, node, pinnedArray2.Length, pinnedArray2, pinnedArray3, pinnedArray4, pinnedArray5, pinnedArray6);
  123. FbxExporter.fbxeAddMeshSubmesh(this.m_ctx, node, topology, pinnedArray.Length, pinnedArray, -1);
  124. int blendShapeCount = mesh.blendShapeCount;
  125. if (blendShapeCount > 0)
  126. {
  127. PinnedArray<Vector3> v = new PinnedArray<Vector3>(mesh.vertexCount);
  128. PinnedArray<Vector3> v2 = new PinnedArray<Vector3>(mesh.vertexCount);
  129. PinnedArray<Vector3> v3 = new PinnedArray<Vector3>(mesh.vertexCount);
  130. for (int i = 0; i < blendShapeCount; i++)
  131. {
  132. string blendShapeName = mesh.GetBlendShapeName(i);
  133. int blendShapeFrameCount = mesh.GetBlendShapeFrameCount(i);
  134. for (int j = 0; j < blendShapeFrameCount; j++)
  135. {
  136. float blendShapeFrameWeight = mesh.GetBlendShapeFrameWeight(i, j);
  137. mesh.GetBlendShapeFrameVertices(i, j, v, v2, v3);
  138. FbxExporter.fbxeAddMeshBlendShape(this.m_ctx, node, blendShapeName, blendShapeFrameWeight, v, v2, v3);
  139. }
  140. }
  141. }
  142. return true;
  143. }
  144. private bool AddMesh(FbxExporter.Node node, MeshRenderer mr)
  145. {
  146. MeshFilter component = mr.gameObject.GetComponent<MeshFilter>();
  147. return component && this.AddMesh(node, component.sharedMesh);
  148. }
  149. private bool AddSkinnedMesh(FbxExporter.Node node, SkinnedMeshRenderer smr)
  150. {
  151. Mesh sharedMesh = smr.sharedMesh;
  152. if (!this.AddMesh(node, sharedMesh))
  153. {
  154. return false;
  155. }
  156. Transform[] bones = smr.bones;
  157. PinnedArray<FbxExporter.Node> pinnedArray = new PinnedArray<FbxExporter.Node>(bones.Length);
  158. for (int i = 0; i < bones.Length; i++)
  159. {
  160. pinnedArray[i] = this.FindOrCreateNodeTree(bones[i], new Action<Transform, FbxExporter.Node>(this.ProcessNode));
  161. }
  162. PinnedArray<BoneWeight> v = new PinnedArray<BoneWeight>(sharedMesh.boneWeights, false);
  163. PinnedArray<Matrix4x4> v2 = new PinnedArray<Matrix4x4>(sharedMesh.bindposes, false);
  164. FbxExporter.fbxeAddMeshSkin(this.m_ctx, node, v, pinnedArray.Length, pinnedArray, v2);
  165. return true;
  166. }
  167. private bool AddTerrain(FbxExporter.Node node, Terrain terrain)
  168. {
  169. TerrainData terrainData = terrain.terrainData;
  170. int heightmapWidth = terrainData.heightmapWidth;
  171. int heightmapHeight = terrainData.heightmapHeight;
  172. float[,] heights = terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight);
  173. int size = heightmapWidth * heightmapHeight;
  174. int size2 = (heightmapWidth - 1) * (heightmapHeight - 1) * 2 * 3;
  175. PinnedArray<Vector3> pinnedArray = new PinnedArray<Vector3>(size);
  176. PinnedArray<Vector3> v = new PinnedArray<Vector3>(size);
  177. PinnedArray<Vector2> v2 = new PinnedArray<Vector2>(size);
  178. PinnedArray<int> pinnedArray2 = new PinnedArray<int>(size2);
  179. FbxExporter.fbxeGenerateTerrainMesh(heights, heightmapWidth, heightmapHeight, terrainData.size, pinnedArray, v, v2, pinnedArray2);
  180. FbxExporter.Topology topology = FbxExporter.Topology.Triangles;
  181. FbxExporter.fbxeAddMesh(this.m_ctx, node, pinnedArray.Length, pinnedArray, v, IntPtr.Zero, v2, IntPtr.Zero);
  182. FbxExporter.fbxeAddMeshSubmesh(this.m_ctx, node, topology, pinnedArray2.Length, pinnedArray2, -1);
  183. return true;
  184. }
  185. [DllImport("FbxExporterCore")]
  186. private static extern FbxExporter.Context fbxeCreateContext(ref FbxExporter.ExportOptions opt);
  187. [DllImport("FbxExporterCore")]
  188. private static extern void fbxeReleaseContext(FbxExporter.Context ctx);
  189. [DllImport("FbxExporterCore")]
  190. private static extern bool fbxeCreateScene(FbxExporter.Context ctx, string name);
  191. [DllImport("FbxExporterCore")]
  192. private static extern bool fbxeWriteAsync(FbxExporter.Context ctx, string path, FbxExporter.Format format);
  193. [DllImport("FbxExporterCore")]
  194. private static extern bool fbxeIsFinished(FbxExporter.Context ctx);
  195. [DllImport("FbxExporterCore")]
  196. private static extern FbxExporter.Node fbxeGetRootNode(FbxExporter.Context ctx);
  197. [DllImport("FbxExporterCore")]
  198. private static extern FbxExporter.Node fbxeFindNodeByName(FbxExporter.Context ctx, string name);
  199. [DllImport("FbxExporterCore")]
  200. private static extern FbxExporter.Node fbxeCreateNode(FbxExporter.Context ctx, FbxExporter.Node parent, string name);
  201. [DllImport("FbxExporterCore")]
  202. private static extern void fbxeSetTRS(FbxExporter.Context ctx, FbxExporter.Node node, Vector3 t, Quaternion r, Vector3 s);
  203. [DllImport("FbxExporterCore")]
  204. private static extern void fbxeAddMesh(FbxExporter.Context ctx, FbxExporter.Node node, int num_vertices, IntPtr points, IntPtr normals, IntPtr tangents, IntPtr uv, IntPtr colors);
  205. [DllImport("FbxExporterCore")]
  206. private static extern void fbxeAddMeshSubmesh(FbxExporter.Context ctx, FbxExporter.Node node, FbxExporter.Topology topology, int num_indices, IntPtr indices, int material);
  207. [DllImport("FbxExporterCore")]
  208. private static extern void fbxeAddMeshSkin(FbxExporter.Context ctx, FbxExporter.Node node, IntPtr weights, int num_bones, IntPtr bones, IntPtr bindposes);
  209. [DllImport("FbxExporterCore")]
  210. private static extern void fbxeAddMeshBlendShape(FbxExporter.Context ctx, FbxExporter.Node node, string name, float weight, IntPtr deltaPoints, IntPtr deltaNormals, IntPtr deltaTangents);
  211. [DllImport("FbxExporterCore")]
  212. private static extern void fbxeGenerateTerrainMesh(float[,] heightmap, int width, int height, Vector3 size, IntPtr dst_vertices, IntPtr dst_normals, IntPtr dst_uv, IntPtr dst_indices);
  213. private FbxExporter.ExportOptions m_opt = FbxExporter.ExportOptions.defaultValue;
  214. private FbxExporter.Context m_ctx;
  215. private Dictionary<Transform, FbxExporter.Node> m_nodes;
  216. public struct Context
  217. {
  218. public static FbxExporter.Context Null
  219. {
  220. get
  221. {
  222. FbxExporter.Context result;
  223. result.ptr = IntPtr.Zero;
  224. return result;
  225. }
  226. }
  227. public static implicit operator bool(FbxExporter.Context v)
  228. {
  229. return v.ptr != IntPtr.Zero;
  230. }
  231. public IntPtr ptr;
  232. }
  233. public struct Node
  234. {
  235. public static FbxExporter.Node Null
  236. {
  237. get
  238. {
  239. FbxExporter.Node result;
  240. result.ptr = IntPtr.Zero;
  241. return result;
  242. }
  243. }
  244. public static implicit operator bool(FbxExporter.Node v)
  245. {
  246. return v.ptr != IntPtr.Zero;
  247. }
  248. public IntPtr ptr;
  249. }
  250. public enum Format
  251. {
  252. FbxBinary,
  253. FbxAscii,
  254. FbxEncrypted,
  255. Obj
  256. }
  257. public enum SystemUnit
  258. {
  259. Millimeter,
  260. Centimeter,
  261. Decimeter,
  262. Meter,
  263. Kilometer
  264. }
  265. public enum Topology
  266. {
  267. Points,
  268. Lines,
  269. Triangles,
  270. Quads
  271. }
  272. public struct ExportOptions
  273. {
  274. public static FbxExporter.ExportOptions defaultValue
  275. {
  276. get
  277. {
  278. return new FbxExporter.ExportOptions
  279. {
  280. flip_handedness = true,
  281. flip_faces = true,
  282. quadify = true,
  283. quadify_full_search = false,
  284. quadify_threshold_angle = 20f,
  285. scale_factor = 1f,
  286. system_unit = FbxExporter.SystemUnit.Meter,
  287. transform = true
  288. };
  289. }
  290. }
  291. public bool flip_handedness;
  292. public bool flip_faces;
  293. public bool quadify;
  294. public bool quadify_full_search;
  295. public float quadify_threshold_angle;
  296. public float scale_factor;
  297. public FbxExporter.SystemUnit system_unit;
  298. public bool transform;
  299. }
  300. }
  301. }