diff --git a/Runtime/Scripts/BoneWeightData.cs b/Runtime/Scripts/BoneWeightData.cs index 8bd2edd..847f4d3 100644 --- a/Runtime/Scripts/BoneWeightData.cs +++ b/Runtime/Scripts/BoneWeightData.cs @@ -37,6 +37,16 @@ public void ApplyOnMesh(Mesh mesh) mesh.SetBoneWeights(m_BonesPerVertex, m_BoneWeights); } + /// + /// Assigns the weight and index buffers as outputs to the GetDracoBonesJob job + /// + /// + internal void AssignToJob(ref DracoNative.GetDracoBonesJob job) + { + job.bonesPerVertex = m_BonesPerVertex; + job.boneWeights = m_BoneWeights; + } + /// /// Releases allocated resources. /// diff --git a/Runtime/Scripts/DracoDecoder.cs b/Runtime/Scripts/DracoDecoder.cs index e8764e4..10f4c3b 100644 --- a/Runtime/Scripts/DracoDecoder.cs +++ b/Runtime/Scripts/DracoDecoder.cs @@ -157,6 +157,86 @@ DecodeSettings decodeSettings return await DecodeMesh(encodedData, decodeSettings, null); } + public static async Task DecodeMesh( + NativeSlice[] encodedDataArray, + DecodeSettings decodeSettings, + Dictionary[] attributeIdMaps, + int[] vertexIntervals, + int[] indicesIntervals, + Bounds?[] bounds + ) + { + CertifySupportedPlatform( +#if UNITY_EDITOR + false +#endif + ); + + var meshDataArray = Mesh.AllocateWritableMeshData(1); + var mesh = meshDataArray[0]; + Bounds combinedBounds = default; + bool calculateNormals = false; + BoneWeightData boneWeightData = null; + + for (var i = 0; i < encodedDataArray.Length; i++) + { + var encodedData = encodedDataArray[i]; + var attributeIdMap = attributeIdMaps[i]; + var encodedDataPtr = GetUnsafeReadOnlyIntPtr(encodedData); + + var result = await DecodeMesh( + mesh, + encodedDataPtr, + encodedData.Length, + decodeSettings, + attributeIdMap, + i, + vertexIntervals, + indicesIntervals, + bounds, + boneWeightData + ); + if (!result.success) + { + meshDataArray.Dispose(); + return null; + } + + boneWeightData = result.boneWeightData; + + if (i == 0) + combinedBounds = result.bounds; + else + combinedBounds.Encapsulate(result.bounds); + + calculateNormals |= result.calculateNormals; + } + + var unityMesh = new Mesh(); + Mesh.ApplyAndDisposeWritableMeshData(meshDataArray, unityMesh); + unityMesh.bounds = combinedBounds; + if (boneWeightData != null) + { + boneWeightData.ApplyOnMesh(unityMesh); + boneWeightData.Dispose(); + } + + if (unityMesh.GetTopology(0) == MeshTopology.Triangles) + { + if (calculateNormals) + { + unityMesh.RecalculateNormals(); + } + + if ((decodeSettings & DecodeSettings.RequireTangents) != 0) + { + unityMesh.RecalculateTangents(); + } + } + + return unityMesh; + } + /// /// Attribute type to index map public static async Task DecodeMesh( @@ -291,7 +371,7 @@ Dictionary attributeIdMap decodeSettings, attributeIdMap #if UNITY_EDITOR - ,sync + , sync: sync #endif ); UnsafeUtility.ReleaseGCObject(gcHandle); @@ -320,13 +400,18 @@ static async Task DecodeMesh( IntPtr encodedData, int size, DecodeSettings decodeSettings, - Dictionary attributeIdMap + Dictionary attributeIdMap, + int submeshIndex = 0, + int[] vertexIntervals = null, + int[] indicesIntervals = null, + Bounds?[] bounds = null, + BoneWeightData boneWeightData = null #if UNITY_EDITOR ,bool sync = false #endif ) { - var dracoNative = new DracoNative(meshData, decodeSettings); + var dracoNative = new DracoNative(meshData, decodeSettings, submeshIndex, vertexIntervals, indicesIntervals, bounds?[submeshIndex], boneWeightData); #if UNITY_EDITOR if (sync) { @@ -363,19 +448,12 @@ Dictionary attributeIdMap return new DecodeResult(); } - var bounds = dracoNative.CreateBounds(); - var success = dracoNative.PopulateMeshData(bounds); - BoneWeightData boneWeightData = null; - if (success && dracoNative.hasBoneWeightData) - { - boneWeightData = new BoneWeightData(dracoNative.bonesPerVertex, dracoNative.boneWeights); - dracoNative.DisposeBoneWeightData(); - } + var success = dracoNative.PopulateMeshData(out var subMeshBounds); return new DecodeResult( success, - bounds, + subMeshBounds, calculateNormals, - boneWeightData + dracoNative.boneWeightData ); } diff --git a/Runtime/Scripts/DracoMeshLoader.cs b/Runtime/Scripts/DracoMeshLoader.cs deleted file mode 100644 index a8e4f0e..0000000 --- a/Runtime/Scripts/DracoMeshLoader.cs +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Unity Technologies and the Draco for Unity authors -// SPDX-License-Identifier: Apache-2.0 - -using System; -using System.Threading.Tasks; -using Unity.Collections; -using UnityEngine; - -namespace Draco -{ - /// - /// Obsolete! Please use instead. Provides Draco mesh decoding. - /// - /// - [Obsolete("Use DracoDecoder.DecodeMesh methods instead.")] - public class DracoMeshLoader - { - /// - /// If true, coordinate space is converted from right-hand (like in glTF) to left-hand (Unity). - /// - readonly bool m_ConvertSpace; - - /// - /// Create a DracoMeshLoader instance which let's you decode Draco data. - /// - /// If true, coordinate space is converted from right-hand (like in glTF) to left-hand (Unity). - public DracoMeshLoader(bool convertSpace = true) - { - m_ConvertSpace = convertSpace; - } - - /// - /// Decodes a Draco mesh - /// - /// Compressed Draco data - /// If draco does not contain normals and this is set to true, normals are calculated. - /// If draco does not contain tangents and this is set to true, tangents and normals are calculated. - /// Draco attribute ID that contains bone weights (for skinning) - /// Draco attribute ID that contains bone joint indices (for skinning) - /// Enforces vertex buffer layout with highest compatibility. Enable this if you want to use blend shapes on the resulting mesh - /// Unity Mesh or null in case of errors - /// - [Obsolete("Use DracoDecoder.DecodeMesh instead.")] - public async Task ConvertDracoMeshToUnity( - NativeSlice encodedData, - bool requireNormals = false, - bool requireTangents = false, - int weightsAttributeId = -1, - int jointsAttributeId = -1, - bool forceUnityLayout = false - ) - { - return await DracoDecoder.DecodeMesh( - encodedData, - CreateDecodeSettings(requireNormals, requireTangents, forceUnityLayout), - DracoDecoder.CreateAttributeIdMap(weightsAttributeId, jointsAttributeId) - ); - } - - /// - /// Decodes a Draco mesh - /// - /// Compressed Draco data - /// If draco does not contain normals and this is set to true, normals are calculated. - /// If draco does not contain tangents and this is set to true, tangents and normals are calculated. - /// Draco attribute ID that contains bone weights (for skinning) - /// Draco attribute ID that contains bone joint indices (for skinning) - /// Enforces vertex buffer layout with highest compatibility. Enable this if you want to use blend shapes on the resulting mesh - /// Unity Mesh or null in case of errors - /// - [Obsolete("Use DracoDecoder.DecodeMesh instead.")] - public async Task ConvertDracoMeshToUnity( - byte[] encodedData, - bool requireNormals = false, - bool requireTangents = false, - int weightsAttributeId = -1, - int jointsAttributeId = -1, - bool forceUnityLayout = false - ) - { - return await DracoDecoder.DecodeMesh( - encodedData, - CreateDecodeSettings(requireNormals, requireTangents, forceUnityLayout), - DracoDecoder.CreateAttributeIdMap(weightsAttributeId, jointsAttributeId) - ); - } - - /// - /// Decodes a Draco mesh - /// - /// MeshData used to create the mesh - /// Compressed Draco data - /// If draco does not contain normals and this is set to true, normals are calculated. - /// If draco does not contain tangents and this is set to true, tangents and normals are calculated. - /// Draco attribute ID that contains bone weights (for skinning) - /// Draco attribute ID that contains bone joint indices (for skinning) - /// Enforces vertex buffer layout with highest compatibility. Enable this if you want to use blend shapes on the resulting mesh - /// A DecodeResult - /// - [Obsolete("Use DracoDecoder.DecodeMesh instead.")] - public async Task ConvertDracoMeshToUnity( - Mesh.MeshData mesh, - byte[] encodedData, - bool requireNormals = false, - bool requireTangents = false, - int weightsAttributeId = -1, - int jointsAttributeId = -1, - bool forceUnityLayout = false - ) - { - return await DracoDecoder.DecodeMesh( - mesh, - encodedData, - CreateDecodeSettings(requireNormals, requireTangents, forceUnityLayout), - DracoDecoder.CreateAttributeIdMap(weightsAttributeId, jointsAttributeId) - ); - } - - /// - /// Decodes a Draco mesh - /// - /// MeshData used to create the mesh - /// Compressed Draco data - /// If draco does not contain normals and this is set to true, normals are calculated. - /// If draco does not contain tangents and this is set to true, tangents and normals are calculated. - /// Draco attribute ID that contains bone weights (for skinning) - /// Draco attribute ID that contains bone joint indices (for skinning) - /// Enforces vertex buffer layout with highest compatibility. Enable this if you want to use blend shapes on the resulting mesh - /// A DecodeResult - /// - [Obsolete("Use DracoDecoder.DecodeMesh instead.")] - public async Task ConvertDracoMeshToUnity( - Mesh.MeshData mesh, - NativeArray encodedData, - bool requireNormals = false, - bool requireTangents = false, - int weightsAttributeId = -1, - int jointsAttributeId = -1, - bool forceUnityLayout = false - ) - { - return await DracoDecoder.DecodeMesh( - mesh, - encodedData, - CreateDecodeSettings(requireNormals, requireTangents, forceUnityLayout), - DracoDecoder.CreateAttributeIdMap(weightsAttributeId, jointsAttributeId) - ); - } - - DecodeSettings CreateDecodeSettings(bool requireNormals, bool requireTangents, bool forceUnityLayout) - { - var flags = DecodeSettings.None; - if (requireNormals) flags |= DecodeSettings.RequireNormals; - if (requireTangents) flags |= DecodeSettings.RequireTangents; - if (forceUnityLayout) flags |= DecodeSettings.ForceUnityVertexLayout; - if (m_ConvertSpace) flags |= DecodeSettings.ConvertSpace; - return flags; - } - } -} diff --git a/Runtime/Scripts/DracoMeshLoader.cs.meta b/Runtime/Scripts/DracoMeshLoader.cs.meta deleted file mode 100644 index dfb7fe8..0000000 --- a/Runtime/Scripts/DracoMeshLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0c6cd7d1ea670421cb7d7e71240d682d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Scripts/DracoNative.cs b/Runtime/Scripts/DracoNative.cs index e9ed386..368e56e 100644 --- a/Runtime/Scripts/DracoNative.cs +++ b/Runtime/Scripts/DracoNative.cs @@ -68,6 +68,11 @@ unsafe class DracoNative Mesh.MeshData m_Mesh; int m_IndicesCount; + private readonly int m_SubMeshIndex; + private int[] m_VertexIntervals; + private int[] m_IndicesIntervals; + private readonly bool m_SetupBuffers = true; + private Bounds? m_Bounds; // START BLEND-HACK // TODO: Unity does not support setting bone weights and indices via new Mesh API @@ -77,8 +82,7 @@ unsafe class DracoNative AttributeMap m_BoneIndexMap; AttributeMap m_BoneWeightMap; public bool hasBoneWeightData => m_BoneIndexMap != null && m_BoneWeightMap != null; - public NativeArray bonesPerVertex; - public NativeArray boneWeights; + public BoneWeightData boneWeightData; // END BLEND-HACK public DracoNative( @@ -90,6 +94,19 @@ DecodeSettings decodeSettings m_Mesh = mesh; } + public DracoNative(Mesh.MeshData mesh, DecodeSettings decodeSettings, int subMeshIndex, int[] vertexIntervals, + int[] indicesIntervals, Bounds? bounds, BoneWeightData boneWeightData) + { + m_DecodeSettings = decodeSettings; + m_Mesh = mesh; + m_SubMeshIndex = subMeshIndex; + m_VertexIntervals = vertexIntervals; + m_IndicesIntervals = indicesIntervals; + m_SetupBuffers = subMeshIndex == 0; + m_Bounds = bounds; + this.boneWeightData = boneWeightData; + } + public JobHandle Init(IntPtr encodedData, int size) { var decodeJob = CreateDecodeJob(encodedData, size); @@ -122,11 +139,10 @@ public bool ErrorOccured() return m_DracoDecodeResult[0] < 0; } - void CalculateVertexParams( - DracoMesh* dracoMesh, + void CalculateVertexParams(DracoMesh* dracoMesh, Dictionary attributeIdMap, - out bool calculateNormals - ) + bool canFitIn16BitBuffer, + out bool calculateNormals) { Profiler.BeginSample("CalculateVertexParams"); @@ -154,7 +170,7 @@ out m_BoneIndexMap // on performance. Therefore we stick to Unity's layout (which // combines pos+normal+tangent in one stream) for smaller meshes. // See: https://github.com/atteneder/glTFast/issues/197 - forceUnityVertexLayout |= dracoMesh->numVertices <= ushort.MaxValue; + forceUnityVertexLayout |= canFitIn16BitBuffer; foreach (var attributeMap in m_Attributes) { @@ -231,6 +247,11 @@ public JobHandle DecodeVertexData( decodeVerticesJobHandle.Complete(); } #endif + + var indicesOffset = m_IndicesIntervals[m_SubMeshIndex]; + var indicesLength = m_IndicesIntervals[m_SubMeshIndex + 1] - indicesOffset; + var vertOffset = m_VertexIntervals[m_SubMeshIndex]; + var vertLength = m_VertexIntervals[m_SubMeshIndex + 1] - vertOffset; JobHandle indicesJob; var dracoMeshJobCount = m_Attributes.Count; @@ -239,7 +260,9 @@ public JobHandle DecodeVertexData( { indicesJob = new GeneratePointCloudIndicesJob { - mesh = m_Mesh + mesh = m_Mesh, + indicesOffset = indicesOffset, + indicesLength = indicesLength }.Schedule(); } else @@ -250,7 +273,9 @@ public JobHandle DecodeVertexData( dracoTempResources = m_DracoTempResources, flip = (m_DecodeSettings & DecodeSettings.ConvertSpace) != 0, dataType = m_Mesh.indexFormat == IndexFormat.UInt16 ? DataType.UInt16 : DataType.UInt32, - mesh = m_Mesh + mesh = m_Mesh, + indicesOffset = indicesOffset, + indicesLength = indicesLength }.Schedule(decodeVerticesJobHandle); dracoMeshJobCount++; } @@ -281,7 +306,8 @@ public JobHandle DecodeVertexData( // weights were removed from attributes before if (map.attribute == VertexAttribute.BlendIndices) continue; // Blend - var calculateBound = map.attribute == VertexAttribute.Position; + + var calculateBound = map.attribute == VertexAttribute.Position && !m_Bounds.HasValue; if (calculateBound) { Assert.IsFalse(m_PositionMinMax.IsCreated, "Multiple position attributes are not supported"); @@ -305,6 +331,8 @@ public JobHandle DecodeVertexData( streamIndex = map.stream, offset = map.offset, bounds = m_PositionMinMax, + vertOffset = vertOffset, + vertLength = vertLength }; jobHandles[jobIndex] = job.Schedule(decodeVerticesJobHandle); } @@ -321,6 +349,8 @@ public JobHandle DecodeVertexData( mesh = m_Mesh, streamIndex = map.stream, offset = map.offset, + vertOffset = vertOffset, + vertLength = vertLength }; jobHandles[jobIndex] = job.Schedule(decodeVerticesJobHandle); } @@ -339,6 +369,8 @@ public JobHandle DecodeVertexData( mesh = m_Mesh, streamIndex = map.stream, bounds = m_PositionMinMax, + vertOffset = vertOffset, + vertLength = vertLength, }; jobHandles[jobIndex] = job.Schedule(decodeVerticesJobHandle); } @@ -353,6 +385,8 @@ public JobHandle DecodeVertexData( componentStride = map.numComponents, mesh = m_Mesh, streamIndex = map.stream, + vertOffset = vertOffset, + vertLength = vertLength }; jobHandles[jobIndex] = job.Schedule(decodeVerticesJobHandle); } @@ -374,10 +408,12 @@ public JobHandle DecodeVertexData( dracoTempResources = m_DracoTempResources, indicesAttribute = m_BoneIndexMap.dracoAttribute, weightsAttribute = m_BoneWeightMap.dracoAttribute, - bonesPerVertex = bonesPerVertex, - boneWeights = boneWeights, + boneOffset = vertOffset, indexValueConverter = GetIndexValueConverter(m_BoneIndexMap.format) }; + + boneWeightData.AssignToJob(ref job); + jobHandles[jobIndex] = job.Schedule(decodeVerticesJobHandle); } @@ -418,37 +454,52 @@ Dictionary attributeIdMap var dracoMesh = (DracoMesh*)m_DracoTempResources[k_MeshPtrIndex]; m_Allocator = dracoMesh->numVertices > k_PersistentDataThreshold ? Allocator.Persistent : Allocator.TempJob; + m_IsPointCloud = dracoMesh->isPointCloud; + m_IndicesCount = m_IsPointCloud ? dracoMesh->numVertices : dracoMesh->numFaces * 3; + + m_VertexIntervals ??= new[] { 0, dracoMesh->numVertices }; + m_IndicesIntervals ??= new[] { 0, m_IndicesCount }; + + var totalVertCount = m_VertexIntervals[m_VertexIntervals.Length - 1]; + var canFitIn16BitBuffer = totalVertCount < ushort.MaxValue; // Max value is excluded because it is reserved in some Graphics APIs for triggering primitive restart (https://github.com/KhronosGroup/glTF/issues/1142#issuecomment-433717774) + CalculateVertexParams( dracoMesh, attributeIdMap, + canFitIn16BitBuffer, out calculateNormals ); Profiler.BeginSample("SetParameters"); - m_IsPointCloud = dracoMesh->isPointCloud; - if (m_IsPointCloud) - { - m_IndicesCount = dracoMesh->numVertices; - m_Mesh.SetIndexBufferParams(dracoMesh->numVertices, dracoMesh->indexFormat); - } - else - { - m_IndicesCount = dracoMesh->numFaces * 3; - m_Mesh.SetIndexBufferParams(dracoMesh->numFaces * 3, dracoMesh->indexFormat); - } - var vertexParams = new List(m_Attributes.Count); - foreach (var map in m_Attributes) + // The first submesh will setup the entire mesh buffer. + if (m_SetupBuffers) { - vertexParams.Add(map.GetVertexAttributeDescriptor()); - } - m_Mesh.SetVertexBufferParams(dracoMesh->numVertices, vertexParams.ToArray()); - if (hasBoneWeightData) - { - var boneCount = m_BoneIndexMap.numComponents; - bonesPerVertex = new NativeArray(dracoMesh->numVertices, m_Allocator); - boneWeights = new NativeArray(dracoMesh->numVertices * boneCount, m_Allocator); + var totalIndicesCount = m_IsPointCloud ? totalVertCount : m_IndicesIntervals[m_IndicesIntervals.Length - 1]; + var indexFormat = canFitIn16BitBuffer ? IndexFormat.UInt16 : IndexFormat.UInt32; + + m_Mesh.SetIndexBufferParams(totalIndicesCount, indexFormat); + + var vertexParams = new List(m_Attributes.Count); + foreach (var map in m_Attributes) + { + vertexParams.Add(map.GetVertexAttributeDescriptor()); + } + + m_Mesh.SetVertexBufferParams(totalVertCount, vertexParams.ToArray()); + + m_Mesh.subMeshCount = m_VertexIntervals.Length - 1; + + if (hasBoneWeightData) + { + var boneCount = m_BoneIndexMap.numComponents; + var boneAllocator = totalVertCount > k_PersistentDataThreshold ? Allocator.Persistent : Allocator.TempJob; + var bonesPerVertex = new NativeArray(totalVertCount, boneAllocator); + var boneWeights = new NativeArray(totalVertCount * boneCount, boneAllocator); + boneWeightData = new BoneWeightData(bonesPerVertex, boneWeights); + } } + Profiler.EndSample(); // SetParameters Profiler.EndSample(); // CreateMesh } @@ -471,10 +522,8 @@ public Bounds CreateBounds() return bounds; } - public bool - PopulateMeshData(Bounds bounds) + public bool PopulateMeshData(out Bounds bounds) { - Profiler.BeginSample("PopulateMeshData"); foreach (var map in m_Attributes) @@ -485,19 +534,21 @@ public bool Profiler.BeginSample("MeshAssign"); + bounds = m_Bounds ?? CreateBounds(); const MeshUpdateFlags flags = DracoDecoder.defaultMeshUpdateFlags; - - m_Mesh.subMeshCount = 1; var subMeshDescriptor = new SubMeshDescriptor( - 0, + m_IndicesIntervals[m_SubMeshIndex], m_IndicesCount, m_IsPointCloud ? MeshTopology.Points : MeshTopology.Triangles ) { - vertexCount = m_Mesh.vertexCount, + baseVertex = m_VertexIntervals[m_SubMeshIndex], + vertexCount = m_VertexIntervals[m_SubMeshIndex + 1] - m_VertexIntervals[m_SubMeshIndex], + firstVertex = m_VertexIntervals[m_SubMeshIndex], bounds = bounds }; - m_Mesh.SetSubMesh(0, subMeshDescriptor, flags); + m_Mesh.SetSubMesh(m_SubMeshIndex, subMeshDescriptor, flags); + Profiler.EndSample(); // CreateUnityMesh.CreateMesh Profiler.EndSample(); @@ -571,7 +622,7 @@ struct DracoData } [StructLayout(LayoutKind.Sequential)] - struct DracoAttribute + internal struct DracoAttribute { // ReSharper disable MemberCanBePrivate.Local public int attributeType; @@ -589,8 +640,6 @@ struct DracoMesh // ReSharper disable once MemberCanBePrivate.Local public int numAttributes; public bool isPointCloud; - - public IndexFormat indexFormat => numVertices >= ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16; } /// @@ -1042,7 +1091,6 @@ public void Execute() [BurstCompile] struct DecodeVerticesJob : IJob { - public NativeArray result; public NativeArray dracoTempResources; @@ -1064,7 +1112,6 @@ public void Execute() [BurstCompile] struct GetDracoIndicesJob : IJob { - [ReadOnly] public NativeArray result; [ReadOnly] @@ -1073,6 +1120,10 @@ struct GetDracoIndicesJob : IJob public bool flip; [ReadOnly] public DataType dataType; + [ReadOnly] + public int indicesOffset; + [ReadOnly] + public int indicesLength; public Mesh.MeshData mesh; public void Execute() @@ -1084,28 +1135,24 @@ public void Execute() var dracoMesh = (DracoMesh*)dracoTempResources[k_MeshPtrIndex]; Assert.IsFalse(dracoMesh->isPointCloud); void* indicesPtr; - int indicesLength; switch (dataType) { case DataType.UInt16: { - var indices = mesh.GetIndexData(); - indicesPtr = indices.GetUnsafePtr(); - indicesLength = indices.Length; + indicesPtr = (ushort*)mesh.GetIndexData().GetUnsafePtr() + indicesOffset; break; } case DataType.UInt32: { - var indices = mesh.GetIndexData(); - indicesPtr = indices.GetUnsafePtr(); - indicesLength = indices.Length; + indicesPtr = (uint*)mesh.GetIndexData().GetUnsafePtr() + indicesOffset; break; } default: result[0] = -1; return; } + GetMeshIndices(dracoMesh, dataType, indicesPtr, indicesLength, flip); } } @@ -1114,6 +1161,11 @@ public void Execute() struct GeneratePointCloudIndicesJob : IJob { public Mesh.MeshData mesh; + + [ReadOnly] + public int indicesOffset; + [ReadOnly] + public int indicesLength; public void Execute() { @@ -1122,18 +1174,18 @@ public void Execute() case IndexFormat.UInt16: { var indices = mesh.GetIndexData(); - for (var i = 0; i < indices.Length; i++) + for (var i = 0; i < indicesLength; i++) { - indices[i] = (ushort)i; + indices[i + indicesOffset] = (ushort)i; } break; } case IndexFormat.UInt32: { var indices = mesh.GetIndexData(); - for (var i = 0; i < indices.Length; i++) + for (var i = 0; i < indicesLength; i++) { - indices[i] = (uint)i; + indices[i + indicesOffset] = (uint)i; } break; } @@ -1163,6 +1215,11 @@ struct GetDracoDataJob : IJob public Mesh.MeshData mesh; [ReadOnly] public int streamIndex; + + [ReadOnly] + public int vertOffset; + [ReadOnly] + public int vertLength; public void Execute() { @@ -1175,8 +1232,8 @@ public void Execute() GetAttributeData(dracoMesh, attribute, &data, flip, componentStride); var elementSize = DataTypeSize((DataType)data->dataType) * componentStride; var dst = mesh.GetVertexData(streamIndex); - var dstPtr = dst.GetUnsafePtr(); - UnsafeUtility.MemCpy(dstPtr, (void*)data->data, elementSize * dracoMesh->numVertices); + var dstPtr = (byte*)dst.GetUnsafePtr() + vertOffset * elementSize; + UnsafeUtility.MemCpy(dstPtr, (void*)data->data, elementSize * vertLength); ReleaseDracoData(&data); } } @@ -1206,6 +1263,11 @@ struct GetDracoDataBoundsJob : IJob public NativeArray bounds; + [ReadOnly] + public int vertOffset; + [ReadOnly] + public int vertLength; + public void Execute() { if (result[0] < 0) @@ -1217,8 +1279,8 @@ public void Execute() GetAttributeData(dracoMesh, attribute, &data, flip, componentStride); var elementSize = DataTypeSize((DataType)data->dataType) * componentStride; var dst = mesh.GetVertexData(streamIndex); - var dstPtr = dst.GetUnsafePtr(); - for (var v = 0; v < dracoMesh->numVertices; v++) + var dstPtr = (byte*)dst.GetUnsafePtr() + vertOffset * elementSize; + for (var v = 0; v < vertLength; v++) { var value = *(float3*)((byte*)data->data + elementSize * v); bounds[0] = math.min(bounds[0], value); @@ -1258,6 +1320,11 @@ struct GetDracoDataInterleavedJob : IJob [ReadOnly] public int offset; + + [ReadOnly] + public int vertOffset; + [ReadOnly] + public int vertLength; public void Execute() { @@ -1270,8 +1337,8 @@ public void Execute() GetAttributeData(dracoMesh, attribute, &data, flip, componentStride); var elementSize = DataTypeSize((DataType)data->dataType) * componentStride; var dst = mesh.GetVertexData(streamIndex); - var dstPtr = ((byte*)dst.GetUnsafePtr()) + offset; - for (var v = 0; v < dracoMesh->numVertices; v++) + var dstPtr = ((byte*)dst.GetUnsafePtr()) + offset + vertOffset * stride; + for (var v = 0; v < vertLength; v++) { UnsafeUtility.MemCpy(dstPtr + (stride * v), ((byte*)data->data) + (elementSize * v), elementSize); } @@ -1311,6 +1378,11 @@ struct GetDracoDataInterleavedBoundsJob : IJob public int offset; public NativeArray bounds; + + [ReadOnly] + public int vertOffset; + [ReadOnly] + public int vertLength; public void Execute() { @@ -1323,8 +1395,8 @@ public void Execute() GetAttributeData(dracoMesh, attribute, &data, flip, componentStride); var elementSize = DataTypeSize((DataType)data->dataType) * componentStride; var dst = mesh.GetVertexData(streamIndex); - var dstPtr = ((byte*)dst.GetUnsafePtr()) + offset; - for (var v = 0; v < dracoMesh->numVertices; v++) + var dstPtr = ((byte*)dst.GetUnsafePtr()) + offset + vertOffset * stride; + for (var v = 0; v < vertLength; v++) { var value = *(float3*)((byte*)data->data + elementSize * v); bounds[0] = math.min(bounds[0], value); @@ -1336,7 +1408,7 @@ public void Execute() } [BurstCompile] - struct GetDracoBonesJob : IJob + internal struct GetDracoBonesJob : IJob { public delegate int GetIndexValueDelegate(IntPtr baseAddress, int index); @@ -1355,6 +1427,9 @@ struct GetDracoBonesJob : IJob [ReadOnly] [NativeDisableUnsafePtrRestriction] public DracoAttribute* weightsAttribute; + + [ReadOnly] + public int boneOffset; [WriteOnly] public NativeArray bonesPerVertex; @@ -1380,12 +1455,12 @@ public void Execute() for (var v = 0; v < dracoMesh->numVertices; v++) { - bonesPerVertex[v] = (byte)indicesAttribute->numComponents; + bonesPerVertex[v + boneOffset] = (byte)indicesAttribute->numComponents; var indicesPtr = (IntPtr)(((byte*)indicesData->data) + (indexSize * v)); var weightsPtr = (float*)(((byte*)weightsData->data) + (weightSize * v)); for (var b = 0; b < indicesAttribute->numComponents; b++) { - boneWeights[v * indicesAttribute->numComponents + b] = new BoneWeight1 + boneWeights[(v + boneOffset) * indicesAttribute->numComponents + b] = new BoneWeight1 { boneIndex = indexValueConverter.Invoke(indicesPtr, b), weight = *(weightsPtr + b)