123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- // Copyright 2017 The Draco Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using Unity.Collections.LowLevel.Unsafe;
- using UnityEngine;
- public unsafe class DracoMeshLoader
- {
- // These values must be exactly the same as the values in draco_types.h.
- // Attribute data type.
- enum DataType {
- DT_INVALID = 0,
- DT_INT8,
- DT_UINT8,
- DT_INT16,
- DT_UINT16,
- DT_INT32,
- DT_UINT32,
- DT_INT64,
- DT_UINT64,
- DT_FLOAT32,
- DT_FLOAT64,
- DT_BOOL
- };
- // These values must be exactly the same as the values in
- // geometry_attribute.h.
- // Attribute type.
- enum AttributeType {
- INVALID = -1,
- POSITION = 0,
- NORMAL,
- COLOR,
- TEX_COORD,
- // A special id used to mark attributes that are not assigned to any known
- // predefined use case. Such attributes are often used for a shader specific
- // data.
- GENERIC
- };
- // The order must be consistent with C++ interface.
- [StructLayout (LayoutKind.Sequential)] public struct DracoData
- {
- public int dataType;
- public IntPtr data;
- }
- [StructLayout (LayoutKind.Sequential)] public struct DracoAttribute
- {
- public int attributeType;
- public int dataType;
- public int numComponents;
- public int uniqueId;
- }
- [StructLayout (LayoutKind.Sequential)] public struct DracoMesh
- {
- public int numFaces;
- public int numVertices;
- public int numAttributes;
- }
- // Release data associated with DracoMesh.
- [DllImport ("dracodec_unity")] private static extern void ReleaseDracoMesh(
- DracoMesh**mesh);
- // Release data associated with DracoAttribute.
- [DllImport ("dracodec_unity")] private static extern void
- ReleaseDracoAttribute(DracoAttribute**attr);
- // Release attribute data.
- [DllImport ("dracodec_unity")] private static extern void ReleaseDracoData(
- DracoData**data);
- // Decodes compressed Draco::Mesh in buffer to mesh. On input, mesh
- // must be null. The returned mesh must released with ReleaseDracoMesh.
- [DllImport ("dracodec_unity")] private static extern int DecodeDracoMesh(
- byte[] buffer, int length, DracoMesh**mesh);
- // Returns the DracoAttribute at index in mesh. On input, attribute must be
- // null. The returned attr must be released with ReleaseDracoAttribute.
- [DllImport ("dracodec_unity")] private static extern bool GetAttribute(
- DracoMesh* mesh, int index, DracoAttribute**attr);
- // Returns the DracoAttribute of type at index in mesh. On input, attribute
- // must be null. E.g. If the mesh has two texture coordinates then
- // GetAttributeByType(mesh, AttributeType.TEX_COORD, 1, &attr); will return
- // the second TEX_COORD attribute. The returned attr must be released with
- // ReleaseDracoAttribute.
- [DllImport ("dracodec_unity")] private static extern bool GetAttributeByType(
- DracoMesh* mesh, AttributeType type, int index, DracoAttribute**attr);
- // Returns the DracoAttribute with unique_id in mesh. On input, attribute
- // must be null.The returned attr must be released with
- // ReleaseDracoAttribute.
- [DllImport ("dracodec_unity")] private static extern bool
- GetAttributeByUniqueId(DracoMesh* mesh, int unique_id,
- DracoAttribute**attr);
- // Returns an array of indices as well as the type of data in data_type. On
- // input, indices must be null. The returned indices must be released with
- // ReleaseDracoData.
- [DllImport ("dracodec_unity")] private static extern bool GetMeshIndices(
- DracoMesh* mesh, DracoData**indices);
- // Returns an array of attribute data as well as the type of data in
- // data_type. On input, data must be null. The returned data must be
- // released with ReleaseDracoData.
- [DllImport ("dracodec_unity")] private static extern bool GetAttributeData(
- DracoMesh* mesh, DracoAttribute* attr, DracoData**data);
- public int LoadMeshFromAsset(string assetName, ref List<Mesh> meshes)
- {
- TextAsset asset =
- Resources.Load(assetName, typeof(TextAsset)) as TextAsset;
- if (asset == null) {
- Debug.Log ("Didn't load file!");
- return -1;
- }
- byte[] encodedData = asset.bytes;
- Debug.Log(encodedData.Length.ToString());
- if (encodedData.Length == 0) {
- Debug.Log ("Didn't load encoded data!");
- return -1;
- }
- return ConvertDracoMeshToUnity(encodedData, ref meshes);
- }
- // Decodes a Draco mesh, creates a Unity mesh from the decoded data and
- // adds the Unity mesh to meshes. encodedData is the compressed Draco mesh.
- public unsafe int ConvertDracoMeshToUnity(byte[] encodedData,
- ref List<Mesh> meshes)
- {
- float startTime = Time.realtimeSinceStartup;
- DracoMesh *mesh = null;
- if (DecodeDracoMesh(encodedData, encodedData.Length, &mesh) <= 0) {
- Debug.Log("Failed: Decoding error.");
- return -1;
- }
- float decodeTimeMilli =
- (Time.realtimeSinceStartup - startTime) * 1000.0f;
- Debug.Log("decodeTimeMilli: " + decodeTimeMilli.ToString());
- Debug.Log("Num indices: " + mesh->numFaces.ToString());
- Debug.Log("Num vertices: " + mesh->numVertices.ToString());
- Debug.Log("Num attributes: " + mesh->numAttributes.ToString());
- Mesh unityMesh = CreateUnityMesh(mesh);
- UnityMeshToCamera(ref unityMesh);
- meshes.Add(unityMesh);
- int numFaces = mesh->numFaces;
- ReleaseDracoMesh(&mesh);
- return numFaces;
- }
- // Creates a Unity mesh from the decoded Draco mesh.
- public unsafe Mesh CreateUnityMesh(DracoMesh *dracoMesh)
- {
- float startTime = Time.realtimeSinceStartup;
- int numFaces = dracoMesh->numFaces;
- int[] newTriangles = new int[dracoMesh->numFaces * 3];
- Vector3[] newVertices = new Vector3[dracoMesh->numVertices];
- Vector2[] newUVs = null;
- Vector3[] newNormals = null;
- Color[] newColors = null;
- byte[] newGenerics = null;
- // Copy face indices.
- DracoData *indicesData;
- GetMeshIndices(dracoMesh, &indicesData);
- int elementSize =
- DataTypeSize((DracoMeshLoader.DataType)indicesData->dataType);
- int *indices = (int*)(indicesData->data);
- var indicesPtr = UnsafeUtility.AddressOf(ref newTriangles[0]);
- UnsafeUtility.MemCpy(indicesPtr, indices,
- newTriangles.Length * elementSize);
- ReleaseDracoData(&indicesData);
- // Copy positions.
- DracoAttribute *attr = null;
- GetAttributeByType(dracoMesh, AttributeType.POSITION, 0, &attr);
- DracoData* posData = null;
- GetAttributeData(dracoMesh, attr, &posData);
- elementSize = DataTypeSize((DracoMeshLoader.DataType)posData->dataType) *
- attr->numComponents;
- var newVerticesPtr = UnsafeUtility.AddressOf(ref newVertices[0]);
- UnsafeUtility.MemCpy(newVerticesPtr, (void*)posData->data,
- dracoMesh->numVertices * elementSize);
- ReleaseDracoData(&posData);
- ReleaseDracoAttribute(&attr);
- // Copy normals.
- if (GetAttributeByType(dracoMesh, AttributeType.NORMAL, 0, &attr)) {
- DracoData* normData = null;
- if (GetAttributeData(dracoMesh, attr, &normData)) {
- elementSize =
- DataTypeSize((DracoMeshLoader.DataType)normData->dataType) *
- attr->numComponents;
- newNormals = new Vector3[dracoMesh->numVertices];
- var newNormalsPtr = UnsafeUtility.AddressOf(ref newNormals[0]);
- UnsafeUtility.MemCpy(newNormalsPtr, (void*)normData->data,
- dracoMesh->numVertices * elementSize);
- Debug.Log("Decoded mesh normals.");
- ReleaseDracoData(&normData);
- ReleaseDracoAttribute(&attr);
- }
- }
- // Copy texture coordinates.
- if (GetAttributeByType(dracoMesh, AttributeType.TEX_COORD, 0, &attr)) {
- DracoData* texData = null;
- if (GetAttributeData(dracoMesh, attr, &texData)) {
- elementSize =
- DataTypeSize((DracoMeshLoader.DataType)texData->dataType) *
- attr->numComponents;
- newUVs = new Vector2[dracoMesh->numVertices];
- var newUVsPtr = UnsafeUtility.AddressOf(ref newUVs[0]);
- UnsafeUtility.MemCpy(newUVsPtr, (void*)texData->data,
- dracoMesh->numVertices * elementSize);
- Debug.Log("Decoded mesh texcoords.");
- ReleaseDracoData(&texData);
- ReleaseDracoAttribute(&attr);
- }
- }
- // Copy colors.
- if (GetAttributeByType(dracoMesh, AttributeType.COLOR, 0, &attr)) {
- DracoData* colorData = null;
- if (GetAttributeData(dracoMesh, attr, &colorData)) {
- elementSize =
- DataTypeSize((DracoMeshLoader.DataType)colorData->dataType) *
- attr->numComponents;
- newColors = new Color[dracoMesh->numVertices];
- var newColorsPtr = UnsafeUtility.AddressOf(ref newColors[0]);
- UnsafeUtility.MemCpy(newColorsPtr, (void*)colorData->data,
- dracoMesh->numVertices * elementSize);
- Debug.Log("Decoded mesh colors.");
- ReleaseDracoData(&colorData);
- ReleaseDracoAttribute(&attr);
- }
- }
- // Copy generic data. This script does not do anyhting with the generic
- // data.
- if (GetAttributeByType(dracoMesh, AttributeType.GENERIC, 0, &attr)) {
- DracoData* genericData = null;
- if (GetAttributeData(dracoMesh, attr, &genericData)) {
- elementSize =
- DataTypeSize((DracoMeshLoader.DataType)genericData->dataType) *
- attr->numComponents;
- newGenerics = new byte[dracoMesh->numVertices * elementSize];
- var newGenericPtr = UnsafeUtility.AddressOf(ref newGenerics[0]);
- UnsafeUtility.MemCpy(newGenericPtr, (void*)genericData->data,
- dracoMesh->numVertices * elementSize);
- Debug.Log("Decoded mesh generic data.");
- ReleaseDracoData(&genericData);
- ReleaseDracoAttribute(&attr);
- }
- }
- float copyDecodedDataTimeMilli =
- (Time.realtimeSinceStartup - startTime) * 1000.0f;
- Debug.Log("copyDecodedDataTimeMilli: " +
- copyDecodedDataTimeMilli.ToString());
- startTime = Time.realtimeSinceStartup;
- Mesh mesh = new Mesh();
- #if UNITY_2017_3_OR_NEWER
- mesh.indexFormat = (newVertices.Length > System.UInt16.MaxValue)
- ? UnityEngine.Rendering.IndexFormat.UInt32
- : UnityEngine.Rendering.IndexFormat.UInt16;
- #else
- if (newVertices.Length > System.UInt16.MaxValue) {
- throw new System.Exception("Draco meshes with more than 65535 vertices are only supported from Unity 2017.3 onwards.");
- }
- #endif
- mesh.vertices = newVertices;
- mesh.SetTriangles(newTriangles, 0, true);
- if (newUVs != null) {
- mesh.uv = newUVs;
- }
- if (newNormals != null) {
- mesh.normals = newNormals;
- } else {
- mesh.RecalculateNormals();
- Debug.Log("Mesh doesn't have normals, recomputed.");
- }
- if (newColors != null) {
- mesh.colors = newColors;
- }
- float convertTimeMilli =
- (Time.realtimeSinceStartup - startTime) * 1000.0f;
- Debug.Log("convertTimeMilli: " + convertTimeMilli.ToString());
- return mesh;
- }
- // Scale and translate the decoded mesh so it will be visible to
- // a new camera's default settings.
- public unsafe void UnityMeshToCamera(ref Mesh mesh)
- {
- float startTime = Time.realtimeSinceStartup;
- mesh.RecalculateBounds();
- float scale = 0.5f / mesh.bounds.extents.x;
- if (0.5f / mesh.bounds.extents.y < scale) {
- scale = 0.5f / mesh.bounds.extents.y;
- }
- if (0.5f / mesh.bounds.extents.z < scale) {
- scale = 0.5f / mesh.bounds.extents.z;
- }
- Vector3[] vertices = mesh.vertices;
- int i = 0;
- while (i < vertices.Length) {
- vertices[i] *= scale;
- i++;
- }
- mesh.vertices = vertices;
- mesh.RecalculateBounds();
- Vector3 translate = mesh.bounds.center;
- translate.x = 0 - mesh.bounds.center.x;
- translate.y = 0 - mesh.bounds.center.y;
- translate.z = 2 - mesh.bounds.center.z;
- i = 0;
- while (i < vertices.Length) {
- vertices[i] += translate;
- i++;
- }
- mesh.vertices = vertices;
- float transformTimeMilli =
- (Time.realtimeSinceStartup - startTime) * 1000.0f;
- Debug.Log("transformTimeMilli: " + transformTimeMilli.ToString());
- }
- private int DataTypeSize(DataType dt) {
- switch (dt) {
- case DataType.DT_INT8:
- case DataType.DT_UINT8:
- return 1;
- case DataType.DT_INT16:
- case DataType.DT_UINT16:
- return 2;
- case DataType.DT_INT32:
- case DataType.DT_UINT32:
- return 4;
- case DataType.DT_INT64:
- case DataType.DT_UINT64:
- return 8;
- case DataType.DT_FLOAT32:
- return 4;
- case DataType.DT_FLOAT64:
- return 8;
- case DataType.DT_BOOL:
- return 1;
- default:
- return -1;
- }
- }
- }
|