can anyone help me to find the issue with my Parallel Mesh Combining Job ?
the steps im following are:
Frustum Culling on all chunks to collect per chunk Matrices and MeshData of all visible Entities.
- note: in the InitializationSystemGroup i disable all chunks that are too far away to be taken in consideration by frustum culling. (TOP-DOWN Optimization)
a Job will collect all included Batches from the Frustum Culling job and set them to NativeArrays for easy access from the MeshCombinerJob:
EG:
The job will get an input of [A,A,A,B,B,C,C,A,B] ( chunks Batchs with Combining Compatibility Sorting Index )
- Compatibility depends on Layers, Receive/Cast Shadows and Material
Resulting Arrays:
[4,3,2] : Meshes counts that can be Merged Together.
[0,1,2,7,3,4,8,5,6] : Ordred Indices by Mergeable Groups
let’s pretend that every chunk batch contains a 10 vertices and 15 Tris.
Verts: [0, 10, 20, 0, 10, 0, 10, 30, 20 ] :
Tris: [0, 15, 30, 0, 15, 0, 15, 45, 30 ] :
the arrays above are the key to parallelize the combining process, so the IJobParallelFor Index can start writing the Resulting Mesh without calculating all previous Indices.
the Issue:
when setting the SetIndexBufferData i get an error:
ArgumentException: Index buffer element #94176 (value 38976) is out of bounds; mesh only has 38976 vertices
At first I thought the job might be linked to bad indexes when combining meshes, but after debugging each index and its start / end offset. I have found that the parallel job correctly accesses MeshDatas and the resulting mesh indices.
later I found out that the combining process was miscalculating the triangles and creating values greater than the maximum length of the vertices.
The Combining Job:
[BurstCompile]
struct CombineMeshesJob : IJobParallelFor
{
[ReadOnly] public NativeArray<int> SortedIndices;// [A,A,A,B,B,C,C,A,B] Sorted indices: [0,1,2,7,3,4,8,5,6]
[ReadOnly] public NativeArray<MeshDataPrevousIndex> PreviousMeshDataIndicesCount; //contains all previous Vertices/Triangles Count by Index
[ReadOnly] public NativeArray<MeshData> MeshDatas;
[ReadOnly] public NativeArray<ChunkMatrices> ChunkMatrices; // Contains the Count and World Prositions of all visible entities within a chunk
// this StartIndex is used to identify the initial index that this Job will start in SortedIndices Array
[ReadOnly] public int StartIndex;
[ReadOnly] public int ResultMeshIndex; // this index is related to SharedIndexCount
[NativeDisableParallelForRestriction]
[NativeDisableContainerSafetyRestriction]
public NativeArray<MergedMeshData> CombinedMeshes;
public void Execute(int index)
{
// Relative to MergeableChunksIndex
var meshBatchIndex = SortedIndices[index + StartIndex];
var mergedMeshDataVertices = CombinedMeshes[ResultMeshIndex];
NativeArray<VertexMeshData> finalMeshVertices;
NativeArray<int> finalMeshTris;
unsafe
{
finalMeshVertices = NativeUtility.PtrToNativeArray(mergedMeshDataVertices.VertexMeshDataPtr, mergedMeshDataVertices.VertexCount);
finalMeshTris = NativeUtility.PtrToNativeArray(mergedMeshDataVertices.TrianglesMeshDataPtr, mergedMeshDataVertices.TrianglesCount);
}
ref var meshDataBlob = ref MeshDatas[meshBatchIndex].BlobMeshData.Value;
var meshVerticesCount = meshDataBlob.Vertices.Length;
var meshTrisCount = meshDataBlob.Triangles.Length;
//this represents the Vertex Index that this job should start from in the final Combined Mesh
var previousMeshDataIndicesCount = PreviousMeshDataIndicesCount[meshBatchIndex];
var vertOffset = previousMeshDataIndicesCount.VertexIndex;
var trisOffset = previousMeshDataIndicesCount.TrianglesIndex;
Debug.Log($"FinalMeshIndex: {ResultMeshIndex} _ index: {meshBatchIndex}, vertOffset: {vertOffset}, trisOffset: {trisOffset} , Before");
var chunkMatrices = ChunkMatrices[meshBatchIndex];
NativeArray<Matrix4x4> chunkMatricesArray;
unsafe
{
chunkMatricesArray = NativeUtility.PtrToNativeArray((Matrix4x4*)chunkMatrices.MatricesPtr, chunkMatrices.BatchCount);
}
for (var i = 0; i < chunkMatrices.BatchCount; i++)
{
var matrix = chunkMatricesArray[i];
//Triangles
for (var j = 0; j < meshTrisCount; j++)
{
finalMeshTris[trisOffset++] = j + vertOffset;
}
//Vertices
for (var j = 0; j < meshVerticesCount; j++)
{
var vertexMeshData = new VertexMeshData
{
Position = matrix.MultiplyPoint3x4(meshDataBlob.Vertices[j]),
Normal = matrix.MultiplyVector(meshDataBlob.Normals[j]).normalized,
Uv = meshDataBlob.Uvs[j]
};
finalMeshVertices[vertOffset++] = vertexMeshData;
}
}
Debug.Log($"FinalMeshIndex: {ResultMeshIndex} _ index: {meshBatchIndex}, vertOffset: {vertOffset}, trisOffset: {trisOffset}, After");
}
}