123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // 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.Linq;
- using System.Runtime.InteropServices;
- using Unity.Collections.LowLevel.Unsafe;
- using UnityEngine;
- public unsafe class GLTFUtilityDracoLoader {
- // 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 = 1,
- COLOR = 2,
- TEX_COORD = 3,
- GENERIC = 4
- }
- // 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;
- }
- public struct MeshAttributes {
- public int pos, norms, uv, joints, weights, col;
- public MeshAttributes(int pos, int norms, int uv, int joints, int weights, int col) {
- this.pos = pos;
- this.norms = norms;
- this.uv = uv;
- this.joints = joints;
- this.weights = weights;
- this.col = col;
- }
- }
- [StructLayout(LayoutKind.Sequential)] public struct Vector4<T> where T : struct {
- public T x;
- public T y;
- public T z;
- public T w;
- }
- public class AsyncMesh {
- public int[] tris;
- public Vector3[] verts;
- public Vector2[] uv;
- public Vector3[] norms;
- public BoneWeight[] boneWeights;
- public Color[] colors;
- }
- #if !UNITY_EDITOR && (UNITY_WEBGL || UNITY_IOS)
- const string DRACODEC_UNITY_LIB = "__Internal";
- #elif UNITY_ANDROID || UNITY_STANDALONE || UNITY_WSA || UNITY_EDITOR || PLATFORM_LUMIN
- const string DRACODEC_UNITY_LIB = "dracodec_unity";
- #endif
- // Release data associated with DracoMesh.
- [DllImport(DRACODEC_UNITY_LIB)] private static extern void ReleaseDracoMesh(
- DracoMesh * * mesh);
- // Release data associated with DracoAttribute.
- [DllImport(DRACODEC_UNITY_LIB)] private static extern void
- ReleaseDracoAttribute(DracoAttribute * * attr);
- // Release attribute data.
- [DllImport(DRACODEC_UNITY_LIB)] 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_LIB)] 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_LIB)] 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_LIB)] 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_LIB)] 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_LIB)] 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_LIB)] private static extern bool GetAttributeData(
- DracoMesh * mesh, DracoAttribute * attr, DracoData * * data);
- // 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 AsyncMesh LoadMesh(byte[] encodedData, MeshAttributes attributes) {
- DracoMesh * mesh = null;
- if (DecodeDracoMesh(encodedData, encodedData.Length, & mesh) <= 0) {
- Debug.Log("Failed: Decoding error.");
- return null;
- }
- AsyncMesh unityMesh = CreateAsyncMesh(mesh, attributes);
- int numFaces = mesh -> numFaces;
- ReleaseDracoMesh( & mesh);
- if (numFaces > 0) return unityMesh;
- else return null;
- }
- // Creates a Unity mesh from the decoded Draco mesh.
- public unsafe AsyncMesh CreateAsyncMesh(DracoMesh * dracoMesh, MeshAttributes attributes) {
- int numFaces = dracoMesh -> numFaces;
- AsyncMesh mesh = new AsyncMesh();
- mesh.tris = new int[dracoMesh -> numFaces * 3];
- mesh.verts = new Vector3[dracoMesh -> numVertices];
- // Copy face indices.
- DracoData * indicesData;
- GetMeshIndices(dracoMesh, & indicesData);
- int elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) indicesData -> dataType);
- int * indices = (int * ) (indicesData -> data);
- var indicesPtr = UnsafeUtility.AddressOf(ref mesh.tris[0]);
- UnsafeUtility.MemCpy(indicesPtr, indices,
- mesh.tris.Length * elementSize);
- ReleaseDracoData( & indicesData);
- DracoAttribute * attr = null;
- // Copy positions.
- if (GetAttributeByUniqueId(dracoMesh, attributes.pos, & attr)) {
- DracoData * posData = null;
- GetAttributeData(dracoMesh, attr, & posData);
- elementSize = DataTypeSize((GLTFUtilityDracoLoader.DataType) posData -> dataType) *
- attr -> numComponents;
- var newVerticesPtr = UnsafeUtility.AddressOf(ref mesh.verts[0]);
- UnsafeUtility.MemCpy(newVerticesPtr, (void * ) posData -> data,
- dracoMesh -> numVertices * elementSize);
- ReleaseDracoData( & posData);
- ReleaseDracoAttribute( & attr);
- }
- // Copy normals.
- if (GetAttributeByUniqueId(dracoMesh, attributes.norms, & attr)) {
- DracoData * normData = null;
- if (GetAttributeData(dracoMesh, attr, & normData)) {
- elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) normData -> dataType) *
- attr -> numComponents;
- mesh.norms = new Vector3[dracoMesh -> numVertices];
- var newNormalsPtr = UnsafeUtility.AddressOf(ref mesh.norms[0]);
- UnsafeUtility.MemCpy(newNormalsPtr, (void * ) normData -> data,
- dracoMesh -> numVertices * elementSize);
- ReleaseDracoData( & normData);
- ReleaseDracoAttribute( & attr);
- }
- }
- // Copy texture coordinates.
- if (GetAttributeByUniqueId(dracoMesh, attributes.uv, & attr)) {
- DracoData * texData = null;
- if (GetAttributeData(dracoMesh, attr, & texData)) {
- elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) texData -> dataType) *
- attr -> numComponents;
- mesh.uv = new Vector2[dracoMesh -> numVertices];
- var newUVsPtr = UnsafeUtility.AddressOf(ref mesh.uv[0]);
- UnsafeUtility.MemCpy(newUVsPtr, (void * ) texData -> data,
- dracoMesh -> numVertices * elementSize);
- ReleaseDracoData( & texData);
- ReleaseDracoAttribute( & attr);
- }
- }
- // Copy colors.
- if (GetAttributeByUniqueId(dracoMesh, attributes.col, & attr)) {
- DracoData * colorData = null;
- if (GetAttributeData(dracoMesh, attr, & colorData)) {
- elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) colorData -> dataType) *
- attr -> numComponents;
- mesh.colors = new Color[dracoMesh -> numVertices];
- var newColorsPtr = UnsafeUtility.AddressOf(ref mesh.colors[0]);
- UnsafeUtility.MemCpy(newColorsPtr, (void * ) colorData -> data,
- dracoMesh -> numVertices * elementSize);
- ReleaseDracoData( & colorData);
- ReleaseDracoAttribute( & attr);
- }
- }
- // Copy weights.
- Vector4[] weights = null;
- if (GetAttributeByUniqueId(dracoMesh, attributes.weights, & attr)) {
- DracoData * weightData = null;
- if (GetAttributeData(dracoMesh, attr, & weightData)) {
- elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) weightData -> dataType) *
- attr -> numComponents;
- if (attr -> dataType == 9) {
- weights = new Vector4[dracoMesh -> numVertices];
- var newWeightsPtr = UnsafeUtility.AddressOf(ref weights[0]);
- UnsafeUtility.MemCpy(newWeightsPtr, (void * ) weightData -> data,
- dracoMesh -> numVertices * elementSize);
- } else if (attr -> dataType == 4) {
- var newWeightsInt = new Vector4<UInt16>[dracoMesh -> numVertices];
- var newWeightsPtr = UnsafeUtility.AddressOf(ref newWeightsInt[0]);
- UnsafeUtility.MemCpy(newWeightsPtr, (void * ) weightData -> data,
- dracoMesh -> numVertices * elementSize);
- weights = newWeightsInt.Select(x => new Vector4(x.x, x.y, x.z, x.w)).ToArray();
- }
- ReleaseDracoData( & weightData);
- ReleaseDracoAttribute( & attr);
- }
- }
- // Copy joints.
- Vector4[] joints = null;
- if (GetAttributeByUniqueId(dracoMesh, attributes.joints, & attr)) {
- DracoData * jointData = null;
- if (GetAttributeData(dracoMesh, attr, & jointData)) {
- elementSize =
- DataTypeSize((GLTFUtilityDracoLoader.DataType) jointData -> dataType) *
- attr -> numComponents;
- if (attr -> dataType == 9) {
- joints = new Vector4[dracoMesh -> numVertices];
- var newJointsPtr = UnsafeUtility.AddressOf(ref joints[0]);
- UnsafeUtility.MemCpy(newJointsPtr, (void * ) jointData -> data,
- dracoMesh -> numVertices * elementSize);
- } else if (attr -> dataType == 4) {
- var newJointsInt = new Vector4<UInt16>[dracoMesh -> numVertices];
- var newJointsPtr = UnsafeUtility.AddressOf(ref newJointsInt[0]);
- UnsafeUtility.MemCpy(newJointsPtr, (void * ) jointData -> data,
- dracoMesh -> numVertices * elementSize);
- joints = newJointsInt.Select(x => new Vector4(x.x, x.y, x.z, x.w)).ToArray();
- }
- ReleaseDracoData( & jointData);
- ReleaseDracoAttribute( & attr);
- }
- }
- /* #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 */
- if (joints != null && weights != null) {
- if (joints.Length == weights.Length) {
- BoneWeight[] boneWeights = new BoneWeight[weights.Length];
- for (int k = 0; k < boneWeights.Length; k++) {
- NormalizeWeights(ref weights[k]);
- boneWeights[k].weight0 = weights[k].x;
- boneWeights[k].weight1 = weights[k].y;
- boneWeights[k].weight2 = weights[k].z;
- boneWeights[k].weight3 = weights[k].w;
- boneWeights[k].boneIndex0 = Mathf.RoundToInt(joints[k].x);
- boneWeights[k].boneIndex1 = Mathf.RoundToInt(joints[k].y);
- boneWeights[k].boneIndex2 = Mathf.RoundToInt(joints[k].z);
- boneWeights[k].boneIndex3 = Mathf.RoundToInt(joints[k].w);
- }
- mesh.boneWeights = boneWeights;
- } else Debug.LogWarning("Draco: joints and weights not same length. Skipped");
- }
- return mesh;
- }
- public void NormalizeWeights(ref Vector4 weights) {
- float total = weights.x + weights.y + weights.z + weights.w;
- if (total == 0) return;
- float mult = 1f / total;
- weights.x *= mult;
- weights.y *= mult;
- weights.z *= mult;
- weights.w *= mult;
- }
- 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;
- }
- }
- }
|