DracoMeshLoader.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Copyright 2017 The Draco Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Runtime.InteropServices;
  19. using Unity.Collections.LowLevel.Unsafe;
  20. using UnityEngine;
  21. public unsafe class DracoMeshLoader
  22. {
  23. // These values must be exactly the same as the values in draco_types.h.
  24. // Attribute data type.
  25. enum DataType {
  26. DT_INVALID = 0,
  27. DT_INT8,
  28. DT_UINT8,
  29. DT_INT16,
  30. DT_UINT16,
  31. DT_INT32,
  32. DT_UINT32,
  33. DT_INT64,
  34. DT_UINT64,
  35. DT_FLOAT32,
  36. DT_FLOAT64,
  37. DT_BOOL
  38. };
  39. // These values must be exactly the same as the values in
  40. // geometry_attribute.h.
  41. // Attribute type.
  42. enum AttributeType {
  43. INVALID = -1,
  44. POSITION = 0,
  45. NORMAL,
  46. COLOR,
  47. TEX_COORD,
  48. // A special id used to mark attributes that are not assigned to any known
  49. // predefined use case. Such attributes are often used for a shader specific
  50. // data.
  51. GENERIC
  52. };
  53. // The order must be consistent with C++ interface.
  54. [StructLayout (LayoutKind.Sequential)] public struct DracoData
  55. {
  56. public int dataType;
  57. public IntPtr data;
  58. }
  59. [StructLayout (LayoutKind.Sequential)] public struct DracoAttribute
  60. {
  61. public int attributeType;
  62. public int dataType;
  63. public int numComponents;
  64. public int uniqueId;
  65. }
  66. [StructLayout (LayoutKind.Sequential)] public struct DracoMesh
  67. {
  68. public int numFaces;
  69. public int numVertices;
  70. public int numAttributes;
  71. }
  72. // Release data associated with DracoMesh.
  73. [DllImport ("dracodec_unity")] private static extern void ReleaseDracoMesh(
  74. DracoMesh**mesh);
  75. // Release data associated with DracoAttribute.
  76. [DllImport ("dracodec_unity")] private static extern void
  77. ReleaseDracoAttribute(DracoAttribute**attr);
  78. // Release attribute data.
  79. [DllImport ("dracodec_unity")] private static extern void ReleaseDracoData(
  80. DracoData**data);
  81. // Decodes compressed Draco::Mesh in buffer to mesh. On input, mesh
  82. // must be null. The returned mesh must released with ReleaseDracoMesh.
  83. [DllImport ("dracodec_unity")] private static extern int DecodeDracoMesh(
  84. byte[] buffer, int length, DracoMesh**mesh);
  85. // Returns the DracoAttribute at index in mesh. On input, attribute must be
  86. // null. The returned attr must be released with ReleaseDracoAttribute.
  87. [DllImport ("dracodec_unity")] private static extern bool GetAttribute(
  88. DracoMesh* mesh, int index, DracoAttribute**attr);
  89. // Returns the DracoAttribute of type at index in mesh. On input, attribute
  90. // must be null. E.g. If the mesh has two texture coordinates then
  91. // GetAttributeByType(mesh, AttributeType.TEX_COORD, 1, &attr); will return
  92. // the second TEX_COORD attribute. The returned attr must be released with
  93. // ReleaseDracoAttribute.
  94. [DllImport ("dracodec_unity")] private static extern bool GetAttributeByType(
  95. DracoMesh* mesh, AttributeType type, int index, DracoAttribute**attr);
  96. // Returns the DracoAttribute with unique_id in mesh. On input, attribute
  97. // must be null.The returned attr must be released with
  98. // ReleaseDracoAttribute.
  99. [DllImport ("dracodec_unity")] private static extern bool
  100. GetAttributeByUniqueId(DracoMesh* mesh, int unique_id,
  101. DracoAttribute**attr);
  102. // Returns an array of indices as well as the type of data in data_type. On
  103. // input, indices must be null. The returned indices must be released with
  104. // ReleaseDracoData.
  105. [DllImport ("dracodec_unity")] private static extern bool GetMeshIndices(
  106. DracoMesh* mesh, DracoData**indices);
  107. // Returns an array of attribute data as well as the type of data in
  108. // data_type. On input, data must be null. The returned data must be
  109. // released with ReleaseDracoData.
  110. [DllImport ("dracodec_unity")] private static extern bool GetAttributeData(
  111. DracoMesh* mesh, DracoAttribute* attr, DracoData**data);
  112. public int LoadMeshFromAsset(string assetName, ref List<Mesh> meshes)
  113. {
  114. TextAsset asset =
  115. Resources.Load(assetName, typeof(TextAsset)) as TextAsset;
  116. if (asset == null) {
  117. Debug.Log ("Didn't load file!");
  118. return -1;
  119. }
  120. byte[] encodedData = asset.bytes;
  121. Debug.Log(encodedData.Length.ToString());
  122. if (encodedData.Length == 0) {
  123. Debug.Log ("Didn't load encoded data!");
  124. return -1;
  125. }
  126. return ConvertDracoMeshToUnity(encodedData, ref meshes);
  127. }
  128. // Decodes a Draco mesh, creates a Unity mesh from the decoded data and
  129. // adds the Unity mesh to meshes. encodedData is the compressed Draco mesh.
  130. public unsafe int ConvertDracoMeshToUnity(byte[] encodedData,
  131. ref List<Mesh> meshes)
  132. {
  133. float startTime = Time.realtimeSinceStartup;
  134. DracoMesh *mesh = null;
  135. if (DecodeDracoMesh(encodedData, encodedData.Length, &mesh) <= 0) {
  136. Debug.Log("Failed: Decoding error.");
  137. return -1;
  138. }
  139. float decodeTimeMilli =
  140. (Time.realtimeSinceStartup - startTime) * 1000.0f;
  141. Debug.Log("decodeTimeMilli: " + decodeTimeMilli.ToString());
  142. Debug.Log("Num indices: " + mesh->numFaces.ToString());
  143. Debug.Log("Num vertices: " + mesh->numVertices.ToString());
  144. Debug.Log("Num attributes: " + mesh->numAttributes.ToString());
  145. Mesh unityMesh = CreateUnityMesh(mesh);
  146. UnityMeshToCamera(ref unityMesh);
  147. meshes.Add(unityMesh);
  148. int numFaces = mesh->numFaces;
  149. ReleaseDracoMesh(&mesh);
  150. return numFaces;
  151. }
  152. // Creates a Unity mesh from the decoded Draco mesh.
  153. public unsafe Mesh CreateUnityMesh(DracoMesh *dracoMesh)
  154. {
  155. float startTime = Time.realtimeSinceStartup;
  156. int numFaces = dracoMesh->numFaces;
  157. int[] newTriangles = new int[dracoMesh->numFaces * 3];
  158. Vector3[] newVertices = new Vector3[dracoMesh->numVertices];
  159. Vector2[] newUVs = null;
  160. Vector3[] newNormals = null;
  161. Color[] newColors = null;
  162. byte[] newGenerics = null;
  163. // Copy face indices.
  164. DracoData *indicesData;
  165. GetMeshIndices(dracoMesh, &indicesData);
  166. int elementSize =
  167. DataTypeSize((DracoMeshLoader.DataType)indicesData->dataType);
  168. int *indices = (int*)(indicesData->data);
  169. var indicesPtr = UnsafeUtility.AddressOf(ref newTriangles[0]);
  170. UnsafeUtility.MemCpy(indicesPtr, indices,
  171. newTriangles.Length * elementSize);
  172. ReleaseDracoData(&indicesData);
  173. // Copy positions.
  174. DracoAttribute *attr = null;
  175. GetAttributeByType(dracoMesh, AttributeType.POSITION, 0, &attr);
  176. DracoData* posData = null;
  177. GetAttributeData(dracoMesh, attr, &posData);
  178. elementSize = DataTypeSize((DracoMeshLoader.DataType)posData->dataType) *
  179. attr->numComponents;
  180. var newVerticesPtr = UnsafeUtility.AddressOf(ref newVertices[0]);
  181. UnsafeUtility.MemCpy(newVerticesPtr, (void*)posData->data,
  182. dracoMesh->numVertices * elementSize);
  183. ReleaseDracoData(&posData);
  184. ReleaseDracoAttribute(&attr);
  185. // Copy normals.
  186. if (GetAttributeByType(dracoMesh, AttributeType.NORMAL, 0, &attr)) {
  187. DracoData* normData = null;
  188. if (GetAttributeData(dracoMesh, attr, &normData)) {
  189. elementSize =
  190. DataTypeSize((DracoMeshLoader.DataType)normData->dataType) *
  191. attr->numComponents;
  192. newNormals = new Vector3[dracoMesh->numVertices];
  193. var newNormalsPtr = UnsafeUtility.AddressOf(ref newNormals[0]);
  194. UnsafeUtility.MemCpy(newNormalsPtr, (void*)normData->data,
  195. dracoMesh->numVertices * elementSize);
  196. Debug.Log("Decoded mesh normals.");
  197. ReleaseDracoData(&normData);
  198. ReleaseDracoAttribute(&attr);
  199. }
  200. }
  201. // Copy texture coordinates.
  202. if (GetAttributeByType(dracoMesh, AttributeType.TEX_COORD, 0, &attr)) {
  203. DracoData* texData = null;
  204. if (GetAttributeData(dracoMesh, attr, &texData)) {
  205. elementSize =
  206. DataTypeSize((DracoMeshLoader.DataType)texData->dataType) *
  207. attr->numComponents;
  208. newUVs = new Vector2[dracoMesh->numVertices];
  209. var newUVsPtr = UnsafeUtility.AddressOf(ref newUVs[0]);
  210. UnsafeUtility.MemCpy(newUVsPtr, (void*)texData->data,
  211. dracoMesh->numVertices * elementSize);
  212. Debug.Log("Decoded mesh texcoords.");
  213. ReleaseDracoData(&texData);
  214. ReleaseDracoAttribute(&attr);
  215. }
  216. }
  217. // Copy colors.
  218. if (GetAttributeByType(dracoMesh, AttributeType.COLOR, 0, &attr)) {
  219. DracoData* colorData = null;
  220. if (GetAttributeData(dracoMesh, attr, &colorData)) {
  221. elementSize =
  222. DataTypeSize((DracoMeshLoader.DataType)colorData->dataType) *
  223. attr->numComponents;
  224. newColors = new Color[dracoMesh->numVertices];
  225. var newColorsPtr = UnsafeUtility.AddressOf(ref newColors[0]);
  226. UnsafeUtility.MemCpy(newColorsPtr, (void*)colorData->data,
  227. dracoMesh->numVertices * elementSize);
  228. Debug.Log("Decoded mesh colors.");
  229. ReleaseDracoData(&colorData);
  230. ReleaseDracoAttribute(&attr);
  231. }
  232. }
  233. // Copy generic data. This script does not do anyhting with the generic
  234. // data.
  235. if (GetAttributeByType(dracoMesh, AttributeType.GENERIC, 0, &attr)) {
  236. DracoData* genericData = null;
  237. if (GetAttributeData(dracoMesh, attr, &genericData)) {
  238. elementSize =
  239. DataTypeSize((DracoMeshLoader.DataType)genericData->dataType) *
  240. attr->numComponents;
  241. newGenerics = new byte[dracoMesh->numVertices * elementSize];
  242. var newGenericPtr = UnsafeUtility.AddressOf(ref newGenerics[0]);
  243. UnsafeUtility.MemCpy(newGenericPtr, (void*)genericData->data,
  244. dracoMesh->numVertices * elementSize);
  245. Debug.Log("Decoded mesh generic data.");
  246. ReleaseDracoData(&genericData);
  247. ReleaseDracoAttribute(&attr);
  248. }
  249. }
  250. float copyDecodedDataTimeMilli =
  251. (Time.realtimeSinceStartup - startTime) * 1000.0f;
  252. Debug.Log("copyDecodedDataTimeMilli: " +
  253. copyDecodedDataTimeMilli.ToString());
  254. startTime = Time.realtimeSinceStartup;
  255. Mesh mesh = new Mesh();
  256. #if UNITY_2017_3_OR_NEWER
  257. mesh.indexFormat = (newVertices.Length > System.UInt16.MaxValue)
  258. ? UnityEngine.Rendering.IndexFormat.UInt32
  259. : UnityEngine.Rendering.IndexFormat.UInt16;
  260. #else
  261. if (newVertices.Length > System.UInt16.MaxValue) {
  262. throw new System.Exception("Draco meshes with more than 65535 vertices are only supported from Unity 2017.3 onwards.");
  263. }
  264. #endif
  265. mesh.vertices = newVertices;
  266. mesh.SetTriangles(newTriangles, 0, true);
  267. if (newUVs != null) {
  268. mesh.uv = newUVs;
  269. }
  270. if (newNormals != null) {
  271. mesh.normals = newNormals;
  272. } else {
  273. mesh.RecalculateNormals();
  274. Debug.Log("Mesh doesn't have normals, recomputed.");
  275. }
  276. if (newColors != null) {
  277. mesh.colors = newColors;
  278. }
  279. float convertTimeMilli =
  280. (Time.realtimeSinceStartup - startTime) * 1000.0f;
  281. Debug.Log("convertTimeMilli: " + convertTimeMilli.ToString());
  282. return mesh;
  283. }
  284. // Scale and translate the decoded mesh so it will be visible to
  285. // a new camera's default settings.
  286. public unsafe void UnityMeshToCamera(ref Mesh mesh)
  287. {
  288. float startTime = Time.realtimeSinceStartup;
  289. mesh.RecalculateBounds();
  290. float scale = 0.5f / mesh.bounds.extents.x;
  291. if (0.5f / mesh.bounds.extents.y < scale) {
  292. scale = 0.5f / mesh.bounds.extents.y;
  293. }
  294. if (0.5f / mesh.bounds.extents.z < scale) {
  295. scale = 0.5f / mesh.bounds.extents.z;
  296. }
  297. Vector3[] vertices = mesh.vertices;
  298. int i = 0;
  299. while (i < vertices.Length) {
  300. vertices[i] *= scale;
  301. i++;
  302. }
  303. mesh.vertices = vertices;
  304. mesh.RecalculateBounds();
  305. Vector3 translate = mesh.bounds.center;
  306. translate.x = 0 - mesh.bounds.center.x;
  307. translate.y = 0 - mesh.bounds.center.y;
  308. translate.z = 2 - mesh.bounds.center.z;
  309. i = 0;
  310. while (i < vertices.Length) {
  311. vertices[i] += translate;
  312. i++;
  313. }
  314. mesh.vertices = vertices;
  315. float transformTimeMilli =
  316. (Time.realtimeSinceStartup - startTime) * 1000.0f;
  317. Debug.Log("transformTimeMilli: " + transformTimeMilli.ToString());
  318. }
  319. private int DataTypeSize(DataType dt) {
  320. switch (dt) {
  321. case DataType.DT_INT8:
  322. case DataType.DT_UINT8:
  323. return 1;
  324. case DataType.DT_INT16:
  325. case DataType.DT_UINT16:
  326. return 2;
  327. case DataType.DT_INT32:
  328. case DataType.DT_UINT32:
  329. return 4;
  330. case DataType.DT_INT64:
  331. case DataType.DT_UINT64:
  332. return 8;
  333. case DataType.DT_FLOAT32:
  334. return 4;
  335. case DataType.DT_FLOAT64:
  336. return 8;
  337. case DataType.DT_BOOL:
  338. return 1;
  339. default:
  340. return -1;
  341. }
  342. }
  343. }