From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Filters/Mesh/MeshPartitioner.cpp | 346 +++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 Runtime/Filters/Mesh/MeshPartitioner.cpp (limited to 'Runtime/Filters/Mesh/MeshPartitioner.cpp') diff --git a/Runtime/Filters/Mesh/MeshPartitioner.cpp b/Runtime/Filters/Mesh/MeshPartitioner.cpp new file mode 100644 index 0000000..9ec9f87 --- /dev/null +++ b/Runtime/Filters/Mesh/MeshPartitioner.cpp @@ -0,0 +1,346 @@ + +#include "UnityPrefix.h" +#include "MeshPartitioner.h" +#include "Runtime/Filters/Mesh/LodMesh.h" + +#if UNITY_EDITOR + +static const UInt32 ComponentStride[] = { 12, 12, 4, 8, 8, 16, sizeof(BoneInfluence) }; + +static int CalcDMABatchSize(int totalVerts, int stride, const int sizeRestriction, bool padded) +{ + const int alignmentRestriction = 16; // DMA transfers address must be a multiple of 16 + int a = alignmentRestriction; + + if(a>stride) + { + if(a % stride == 0) + return sizeRestriction; + while(a % stride) { a+=alignmentRestriction; } + } + else + { + if(stride % a == 0) + return sizeRestriction; + while(stride % a) { a+=alignmentRestriction; } + } + + int batchMultiple = a / stride; + totalVerts = (totalVerts < sizeRestriction) ? totalVerts : sizeRestriction; + if(padded) + totalVerts += batchMultiple - 1; + totalVerts /= batchMultiple; + totalVerts *= batchMultiple; + return totalVerts; +}; + +static int CalcBestFitBatchSize(const UInt32 availableChannels, int vertexCount, int maxVerts, bool padded = false) +{ + int bestFit = INT_MAX; + for(int i=0;i<=kShaderChannelCount;i++) + { + if (availableChannels & (1< maxVCount) ? maxVCount : bestFit; + } + } + return bestFit; +} + +template +struct TempPartition +{ + dynamic_array m_Vertices; + dynamic_array m_UV; + dynamic_array m_UV1; + dynamic_array m_Colors; + dynamic_array m_Normals; + dynamic_array m_Tangents; + dynamic_array m_Skin; + dynamic_array indexBuffer; + dynamic_array newToOld; + int vertexCount; + // + void InitRemapping(int numVertices) + { + newToOld.resize_uninitialized(numVertices); + memset(&newToOld[0],(T)-1,numVertices*sizeof(T)); + } + void RemapVertices(Mesh& mesh, int actualVertexCount) + { + m_Vertices.resize_uninitialized(vertexCount); + const UInt32 channels = mesh.GetAvailableChannels(); + if(channels&(1< +struct SegmentedMesh +{ + std::vector > m_Partitions; + void Clear() { m_Partitions.clear(); } +}; + +template +static void CreateFromSubMesh(std::vector< SegmentedMesh >& segments, Mesh& mesh, int submesh) +{ + SubMesh& sm = mesh.GetSubMeshFast(submesh); + + T vertexCount = 0; + const int numIndices = sm.indexCount; + const int numTriangles = numIndices / 3; + + AssertBreak((numTriangles * 3) == numIndices); + + UInt32 maxComponentStride = 0; + const UInt32 availableChannels = mesh.GetAvailableChannels() | (mesh.GetSkin().empty() ? 0 : (1< (&mesh.GetIndexBuffer()[sm.firstByte]); + + int startTriangle = 0; + int startVertex = 0; + std::vector oldToNew; + oldToNew.resize(mesh.GetVertexCount()); + std::vector > & partitions = segments[submesh].m_Partitions; + while(startTriangle != numTriangles) + { + TempPartition p; + p.indexBuffer.clear(); + p.vertexCount = 0; + p.InitRemapping(batchSize+3); + dynamic_array& dstIndices = p.indexBuffer; + memset(&oldToNew[0],(T)-1,oldToNew.size()*sizeof(T)); + for(int i=startTriangle; i= 0); + AssertBreak(vertex < mesh.GetVertexCount()); + AssertBreak(lastVertexCount-startVertex+j < p.newToOld.size()); + AssertBreak(p.newToOld[lastVertexCount-startVertex+j] == (T)-1); + if(oldToNew[vertex]==(T)-1) + { + AssertBreak(vertexCount < numVertices); + oldToNew[vertex]=vertexCount-startVertex; + p.newToOld[vertexCount-startVertex]=vertex; + vertexCount++; + } + dstIndices.push_back(oldToNew[vertex]); + } + if((vertexCount-startVertex) > batchSize) + { + //undo the last one in the partition + for(int j=0;j<3;j++) + { + p.newToOld[lastVertexCount-startVertex+j] = -1;; + dstIndices.pop_back(); + } + startTriangle = i; + vertexCount = lastVertexCount; + break; + } + } + const int actualVertexCount = vertexCount - startVertex; + p.vertexCount = maxVerts;//CalcBestFitBatchSize(availableChannels, actualVertexCount, maxVerts, true); // FIXME!!! This needs to find the next "best fit" that will still keep alignment restrictions.. + p.RemapVertices(mesh, actualVertexCount); + partitions.push_back(p); + startVertex = vertexCount; + } + oldToNew.clear(); +} + +// mircea: todo: this would be awesome!!! +// spuInOut: +// m_Vertices +// m_Normals +// m_Tangents +// spuIn: +// m_Skin + +// rsxDirect +// m_UV +// m_UV1 +// m_Colors +// m_IndexBuffer + +void PartitionSubmeshes(Mesh& m) +{ + typedef UInt16 T; + + const int submeshCount = m.m_SubMeshes.size(); + + m.m_PartitionInfos.clear(); + m.m_Partitions.clear(); + + // skinned meshes cannot be partitioned if the optimization flag is not set because partitioning changes the vertex/index buffers + if (!m.GetMeshOptimized() || m.GetSkin().empty()) + return; + + // destripify if needed + m.DestripifyIndices (); + + // need to fixup the indices first so they are not relative to the partition start anymore. + Mesh::MeshPartitionInfoContainer& partInfos = m.m_PartitionInfos; + for(int pi=0; pi > segments; + segments.resize(submeshCount); + for(int submesh=0;submesh(segments, m, submesh); + + /////////////////////////////////////////////////////////////////////////////// + // combine the segments to get the script accessible buffers + + UInt32 availableChannels = m.GetAvailableChannels(); + + m.Clear(false); + m.SetMeshOptimized(true); //mircea@ m.Clear will set the optimized mesh to false. Being here means we are partitioning an optimized mesh so restore the flag. + m.SetSubMeshCount(submeshCount); + + UInt32 vertexOffset = 0; + UInt32 indexOffset = 0; + + for(int submesh=0;submesh& seg = segments[submesh]; + + MeshPartitionInfo partInfo; + partInfo.submeshStart = m.m_Partitions.size(); + partInfo.partitionCount = seg.m_Partitions.size(); + m.m_PartitionInfos.push_back(partInfo); + + // create partitions & build the mesh buffers + for(int s=0;s& p = seg.m_Partitions[s]; + part.vertexCount = p.vertexCount; + part.vertexOffset = vertexOffset; + part.indexCount = p.indexBuffer.size(); + part.indexByteOffset = indexOffset; + AssertBreak(0 == (part.vertexOffset & 15)); + m.m_Partitions.push_back(part);; + indexCount += part.indexCount; + indexOffset += p.indexBuffer.size() * sizeof(T); + vertexOffset += p.vertexCount; + } + } + + // fill in the partitioned data back into the mesh. + m.ResizeVertices(vertexOffset, availableChannels); + + for(int submesh=0;submesh& seg = segments[submesh]; + const MeshPartitionInfo& partInfo = m.m_PartitionInfos[submesh]; + for(int s=0;s& p = seg.m_Partitions[s]; + const MeshPartition& part = m.m_Partitions[partInfo.submeshStart + s]; + strided_copy (p.m_Vertices.begin (), p.m_Vertices.end(), m.GetVertexBegin () + part.vertexOffset); + if(!p.m_Normals.empty()) + strided_copy (p.m_Normals.begin (), p.m_Normals.end(), m.GetNormalBegin () + part.vertexOffset); + if(!p.m_UV.empty()) + strided_copy (p.m_UV.begin (), p.m_UV.end (), m.GetUvBegin (0) + part.vertexOffset); + if(!p.m_UV1.empty()) + strided_copy (p.m_UV1.begin (), p.m_UV1.end (), m.GetUvBegin (1) + part.vertexOffset); + if(!p.m_Tangents.empty()) + strided_copy (p.m_Tangents.begin (), p.m_Tangents.end (), m.GetTangentBegin () + part.vertexOffset); + if(!p.m_Colors.empty()) + strided_copy (p.m_Colors.begin (), p.m_Colors.end (), m.GetColorBegin() + part.vertexOffset); + if(!p.m_Skin.empty()) + m.GetSkin().insert(m.GetSkin().end(), p.m_Skin.begin(), p.m_Skin.end()); + } + + std::vector indices; + for(int s=0;s& tp = seg.m_Partitions[s]; + for(int i=0;i=0) && (index < (p.vertexCount))); + #if DEBUG_PARTITIONING + index += p.vertexOffset; + #endif + indices.push_back(index); + } + } + m.SetIndices (&indices[0], indices.size(), submesh, kPrimitiveTriangles); + } +} + +void PartitionMesh(Mesh* m) +{ + PartitionSubmeshes(*m); +} + +#endif //UNITY_EDITOR -- cgit v1.1-26-g67d0