public override unsafe bool ScheduleVertexColorJob(IGltfBuffers buffers, int colorAccessorIndex, NativeSlice <JobHandle> handles) { Profiler.BeginSample("ScheduleVertexColorJob"); Profiler.BeginSample("AllocateNativeArray"); buffers.GetAccessor(colorAccessorIndex, out var colorAcc, out var data, out var byteStride); if (colorAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "color"); } vData = new NativeArray <float4>(colorAcc.count, VertexBufferConfigBase.defaultAllocator); var vDataPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(vData); Profiler.EndSample(); var h = GetColors32Job( data, colorAcc.componentType, colorAcc.typeEnum, byteStride, vData ); if (h.HasValue) { handles[0] = h.Value; } else { Profiler.EndSample(); return(false); } Profiler.EndSample(); return(true); }
public override unsafe bool ScheduleVertexUVJobs(IGltfBuffers buffers, int[] uvAccessorIndices, int vertexCount, NativeSlice <JobHandle> handles) { Profiler.BeginSample("ScheduleVertexUVJobs"); Profiler.BeginSample("AllocateNativeArray"); vData = new NativeArray <T>(vertexCount, VertexBufferConfigBase.defaultAllocator); var vDataPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(vData); Profiler.EndSample(); uvSetCount = uvAccessorIndices.Length; int outputByteStride = uvAccessorIndices.Length * 8; for (int i = 0; i < uvAccessorIndices.Length; i++) { var accIndex = uvAccessorIndices[i]; buffers.GetAccessor(accIndex, out var uvAcc, out var data, out var byteStride); if (uvAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "UVs"); } var h = GetUvsJob( data, uvAcc.count, uvAcc.componentType, byteStride, (float2 *)(vDataPtr + (i * 8)), outputByteStride, uvAcc.normalized ); if (h.HasValue) { handles[i] = h.Value; } else { Profiler.EndSample(); return(false); } } Profiler.EndSample(); return(true); }
public unsafe JobHandle?ScheduleMorphTargetJobs( IGltfBuffers buffers, int positionAccessorIndex, int normalAccessorIndex, int tangentAccessorIndex, ICodeLogger logger ) { Profiler.BeginSample("ScheduleMorphTargetJobs"); buffers.GetAccessor(positionAccessorIndex, out var posAcc, out var posData, out var posByteStride); positions = new Vector3[posAcc.count]; positionsHandle = GCHandle.Alloc(positions, GCHandleType.Pinned); var jobCount = 1; if (posAcc.isSparse && posAcc.bufferView >= 0) { jobCount++; } Accessor nrmAcc = null; void * nrmInput = null; int nrmInputByteStride = 0; if (normalAccessorIndex >= 0) { normals = new Vector3[posAcc.count]; normalsHandle = GCHandle.Alloc(normals, GCHandleType.Pinned); buffers.GetAccessor(normalAccessorIndex, out nrmAcc, out nrmInput, out nrmInputByteStride); if (nrmAcc.isSparse && nrmAcc.bufferView >= 0) { jobCount += 2; } else { jobCount++; } } Accessor tanAcc = null; void * tanInput = null; int tanInputByteStride = 0; if (tangentAccessorIndex >= 0) { tangents = new Vector3[posAcc.count]; tangentsHandle = GCHandle.Alloc(tangents, GCHandleType.Pinned); buffers.GetAccessor(normalAccessorIndex, out tanAcc, out tanInput, out tanInputByteStride); if (tanAcc.isSparse && tanAcc.bufferView >= 0) { jobCount += 2; } else { jobCount++; } } NativeArray <JobHandle> handles = new NativeArray <JobHandle>(jobCount, VertexBufferConfigBase.defaultAllocator); var handleIndex = 0; fixed(void *dest = &(positions[0])) { JobHandle?h = null; if (posData != null) { #if DEBUG if (posAcc.normalized) { Debug.LogError("Normalized Positions will likely produce incorrect results. Please report this error at https://github.com/atteneder/glTFast/issues/new?assignees=&labels=bug&template=bug_report.md&title=Normalized%20Positions"); } #endif h = VertexBufferConfigBase.GetVector3sJob( posData, posAcc.count, posAcc.componentType, posByteStride, (float3 *)dest, 12, posAcc.normalized, false // positional data never needs to be normalized ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (posAcc.isSparse) { buffers.GetAccessorSparseIndices(posAcc.sparse.indices, out var posIndexData); buffers.GetAccessorSparseValues(posAcc.sparse.values, out var posValueData); var sparseJobHandle = VertexBufferConfigBase.GetVector3sSparseJob( posIndexData, posValueData, posAcc.sparse.count, posAcc.sparse.indices.componentType, posAcc.componentType, (float3 *)dest, 12, dependsOn: ref h, posAcc.normalized ); if (sparseJobHandle.HasValue) { handles[handleIndex] = sparseJobHandle.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } } if (nrmAcc != null) { fixed(void *dest = &(normals[0])) { JobHandle?h = null; if (nrmAcc.bufferView >= 0) { h = VertexBufferConfigBase.GetVector3sJob( nrmInput, nrmAcc.count, nrmAcc.componentType, nrmInputByteStride, (float3 *)dest, 12, nrmAcc.normalized, false // morph target normals are deltas -> don't normalize ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (nrmAcc.isSparse) { buffers.GetAccessorSparseIndices(nrmAcc.sparse.indices, out var indexData); buffers.GetAccessorSparseValues(nrmAcc.sparse.values, out var valueData); var sparseJobHandle = VertexBufferConfigBase.GetVector3sSparseJob( indexData, valueData, nrmAcc.sparse.count, nrmAcc.sparse.indices.componentType, nrmAcc.componentType, (float3 *)dest, 12, dependsOn: ref h, nrmAcc.normalized ); if (sparseJobHandle.HasValue) { handles[handleIndex] = sparseJobHandle.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } } } if (tanAcc != null) { fixed(void *dest = &(tangents[0])) { JobHandle?h = null; if (tanAcc.bufferView >= 0) { h = VertexBufferConfigBase.GetVector3sJob( tanInput, tanAcc.count, tanAcc.componentType, tanInputByteStride, (float3 *)dest, 12, tanAcc.normalized, false // morph target tangents are deltas -> don't normalize ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (tanAcc.isSparse) { buffers.GetAccessorSparseIndices(tanAcc.sparse.indices, out var indexData); buffers.GetAccessorSparseValues(tanAcc.sparse.values, out var valueData); var sparseJobHandle = VertexBufferConfigBase.GetVector3sSparseJob( indexData, valueData, tanAcc.sparse.count, tanAcc.sparse.indices.componentType, tanAcc.componentType, (float3 *)dest, 12, dependsOn: ref h, tanAcc.normalized ); if (sparseJobHandle.HasValue) { handles[handleIndex] = sparseJobHandle.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } } } var handle = (jobCount > 1) ? JobHandle.CombineDependencies(handles) : handles[0]; handles.Dispose(); Profiler.EndSample(); return(handle); }
public override unsafe JobHandle?ScheduleVertexBonesJob( IGltfBuffers buffers, int weightsAccessorIndex, int jointsAccessorIndex ) { Profiler.BeginSample("ScheduleVertexBonesJob"); Profiler.BeginSample("AllocateNativeArray"); buffers.GetAccessor(weightsAccessorIndex, out var weightsAcc, out var weightsData, out var weightsByteStride); if (weightsAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "bone weights"); } vData = new NativeArray <VBones>(weightsAcc.count, VertexBufferConfigBase.defaultAllocator); var vDataPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(vData); Profiler.EndSample(); JobHandle weightsHandle; JobHandle jointsHandle; { var h = GetWeightsJob( weightsData, weightsAcc.count, weightsAcc.componentType, weightsByteStride, (float4 *)vDataPtr, 32, weightsAcc.normalized ); if (h.HasValue) { weightsHandle = h.Value; } else { Profiler.EndSample(); return(null); } } { buffers.GetAccessor(jointsAccessorIndex, out var jointsAcc, out var jointsData, out var jointsByteStride); if (jointsAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "bone joints"); } var h = GetJointsJob( jointsData, jointsAcc.count, jointsAcc.componentType, jointsByteStride, (uint4 *)(vDataPtr + 16), 32, logger ); if (h.HasValue) { jointsHandle = h.Value; } else { Profiler.EndSample(); return(null); } } var jobHandle = JobHandle.CombineDependencies(weightsHandle, jointsHandle); var skinWeights = (int)QualitySettings.skinWeights; if (skinWeights < 4) { var job = new SortJointsByWeightsJob { bones = vData, skinWeights = math.max(1, skinWeights) }; jobHandle = job.Schedule(vData.Length, GltfImport.DefaultBatchCount, jobHandle); } Profiler.EndSample(); return(jobHandle); }
public override unsafe JobHandle?ScheduleVertexJobs( IGltfBuffers buffers, int positionAccessorIndex, int normalAccessorIndex, int tangentAccessorIndex, int[] uvAccessorIndices, int colorAccessorIndex, int weightsAccessorIndex, int jointsAccessorIndex ) { buffers.GetAccessor(positionAccessorIndex, out var posAcc, out var posData, out var posByteStride); Profiler.BeginSample("ScheduleVertexJobs"); Profiler.BeginSample("AllocateNativeArray"); vData = new NativeArray <VType>(posAcc.count, defaultAllocator); var vDataPtr = (byte *)vData.GetUnsafeReadOnlyPtr(); Profiler.EndSample(); bounds = posAcc.TryGetBounds(); int jobCount = 1; int outputByteStride = 12; // sizeof Vector3 if (posAcc.isSparse && posAcc.bufferView >= 0) { jobCount++; } if (normalAccessorIndex >= 0) { jobCount++; hasNormals = true; } hasNormals |= calculateNormals; if (hasNormals) { outputByteStride += 12; } if (tangentAccessorIndex >= 0) { jobCount++; hasTangents = true; } hasTangents |= calculateTangents; if (hasTangents) { outputByteStride += 16; } if (uvAccessorIndices != null && uvAccessorIndices.Length > 0) { // More than two UV sets are not supported yet Assert.IsTrue(uvAccessorIndices.Length < 3); jobCount += uvAccessorIndices.Length; switch (uvAccessorIndices.Length) { case 1: texCoords = new VertexBufferTexCoords <VTexCoord1>(logger); break; default: texCoords = new VertexBufferTexCoords <VTexCoord2>(logger); break; } } hasColors = colorAccessorIndex >= 0; if (hasColors) { jobCount++; colors = new VertexBufferColors(); } hasBones = weightsAccessorIndex >= 0 && jointsAccessorIndex >= 0; if (hasBones) { jobCount++; bones = new VertexBufferBones(logger); } NativeArray <JobHandle> handles = new NativeArray <JobHandle>(jobCount, defaultAllocator); int handleIndex = 0; { JobHandle?h = null; if (posAcc.bufferView >= 0) { h = GetVector3sJob( posData, posAcc.count, posAcc.componentType, posByteStride, (float3 *)vDataPtr, outputByteStride, posAcc.normalized, false // positional data never needs to be normalized ); } if (posAcc.isSparse) { buffers.GetAccessorSparseIndices(posAcc.sparse.indices, out var posIndexData); buffers.GetAccessorSparseValues(posAcc.sparse.values, out var posValueData); var sparseJobHandle = GetVector3sSparseJob( posIndexData, posValueData, posAcc.sparse.count, posAcc.sparse.indices.componentType, posAcc.componentType, (float3 *)vDataPtr, outputByteStride, dependsOn: ref h, posAcc.normalized ); if (sparseJobHandle.HasValue) { handles[handleIndex] = sparseJobHandle.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (normalAccessorIndex >= 0) { buffers.GetAccessor(normalAccessorIndex, out var nrmAcc, out var input, out var inputByteStride); if (nrmAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "normals"); } var h = GetVector3sJob( input, nrmAcc.count, nrmAcc.componentType, inputByteStride, (float3 *)(vDataPtr + 12), outputByteStride, nrmAcc.normalized, true // normals need to be unit length ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (tangentAccessorIndex >= 0) { buffers.GetAccessor(tangentAccessorIndex, out var tanAcc, out var input, out var inputByteStride); if (tanAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "tangents"); } var h = GetTangentsJob( input, tanAcc.count, tanAcc.componentType, inputByteStride, (float4 *)(vDataPtr + 24), outputByteStride, tanAcc.normalized ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } if (texCoords != null) { texCoords.ScheduleVertexUVJobs( buffers, uvAccessorIndices, posAcc.count, new NativeSlice <JobHandle>( handles, handleIndex, uvAccessorIndices.Length ) ); handleIndex += uvAccessorIndices.Length; } if (hasColors) { colors.ScheduleVertexColorJob( buffers, colorAccessorIndex, new NativeSlice <JobHandle>( handles, handleIndex, 1 ) ); handleIndex++; } if (hasBones) { var h = bones.ScheduleVertexBonesJob( buffers, weightsAccessorIndex, jointsAccessorIndex ); if (h.HasValue) { handles[handleIndex] = h.Value; handleIndex++; } else { Profiler.EndSample(); return(null); } } var handle = (jobCount > 1) ? JobHandle.CombineDependencies(handles) : handles[0]; handles.Dispose(); Profiler.EndSample(); return(handle); }
public override unsafe JobHandle?ScheduleVertexBonesJob( IGltfBuffers buffers, int weightsAccessorIndex, int jointsAccessorIndex ) { Profiler.BeginSample("ScheduleVertexBonesJob"); Profiler.BeginSample("AllocateNativeArray"); buffers.GetAccessor(weightsAccessorIndex, out var weightsAcc, out var weightsData, out var weightsByteStride); if (weightsAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "bone weights"); } vData = new NativeArray <VBones>(weightsAcc.count, VertexBufferConfigBase.defaultAllocator); var vDataPtr = (byte *)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(vData); Profiler.EndSample(); JobHandle weightsHandle; JobHandle jointsHandle; { var h = GetWeightsJob( weightsData, weightsAcc.count, weightsAcc.componentType, weightsByteStride, (float4 *)vDataPtr, 32, weightsAcc.normalized ); if (h.HasValue) { weightsHandle = h.Value; } else { Profiler.EndSample(); return(null); } } { buffers.GetAccessor(jointsAccessorIndex, out var jointsAcc, out var jointsData, out var jointsByteStride); if (jointsAcc.isSparse) { logger.Error(LogCode.SparseAccessor, "bone joints"); } var h = GetJointsJob( jointsData, jointsAcc.count, jointsAcc.componentType, jointsByteStride, (uint4 *)(vDataPtr + 16), 32, logger ); if (h.HasValue) { jointsHandle = h.Value; } else { Profiler.EndSample(); return(null); } } var jobHandle = JobHandle.CombineDependencies(weightsHandle, jointsHandle); var skinWeights = (int)QualitySettings.skinWeights; #if UNITY_EDITOR // If this is design-time import, fix and import all weights. if (!UnityEditor.EditorApplication.isPlaying || skinWeights < 4) { if (!UnityEditor.EditorApplication.isPlaying) { skinWeights = 4; } #else if (skinWeights < 4) { #endif var job = new SortAndRenormalizeBoneWeightsJob { bones = vData, skinWeights = math.max(1, skinWeights) }; jobHandle = job.Schedule(vData.Length, GltfImport.DefaultBatchCount, jobHandle); } #if GLTFAST_SAFE else { // Re-normalizing alone is sufficient var job = new RenormalizeBoneWeightsJob { bones = vData, }; jobHandle = job.Schedule(vData.Length, GltfImport.DefaultBatchCount, jobHandle); } #endif Profiler.EndSample(); return(jobHandle); }