MeshBuilderSubMesh.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Memory/SystemAllocator.h>
  9. #include <AzCore/Casting/numeric_cast.h>
  10. #include "MeshBuilder.h"
  11. #include "MeshBuilderSkinningInfo.h"
  12. #include "MeshBuilderSubMesh.h"
  13. #include "MeshBuilderVertexAttributeLayers.h"
  14. namespace AZ::MeshBuilder
  15. {
  16. AZ_CLASS_ALLOCATOR_IMPL(MeshBuilderSubMesh, AZ::SystemAllocator)
  17. MeshBuilderSubMesh::MeshBuilderSubMesh(size_t materialIndex, MeshBuilder* mesh)
  18. : m_materialIndex(materialIndex)
  19. , m_mesh(mesh)
  20. {
  21. }
  22. // map the vertices to their original vertex and dupe numbers
  23. void MeshBuilderSubMesh::GenerateVertexOrder()
  24. {
  25. // create our vertex order array and allocate numVertices lookups
  26. m_vertexOrder.resize(m_numVertices);
  27. const size_t numOrgVertices = m_mesh->GetNumOrgVerts();
  28. for (size_t orgVertexNr = 0; orgVertexNr < numOrgVertices; ++orgVertexNr)
  29. {
  30. const size_t numSubMeshVertices = m_mesh->GetNumSubMeshVertices(orgVertexNr);
  31. for (size_t i = 0; i < numSubMeshVertices; ++i)
  32. {
  33. const MeshBuilder::SubMeshVertex& subMeshVertex = m_mesh->GetSubMeshVertex(orgVertexNr, i);
  34. if (subMeshVertex.m_subMesh == this && subMeshVertex.m_realVertexNr != InvalidIndex)
  35. {
  36. const size_t realVertexNr = subMeshVertex.m_realVertexNr;
  37. m_vertexOrder[realVertexNr].mOrgVtx = orgVertexNr;
  38. m_vertexOrder[realVertexNr].mDuplicateNr = subMeshVertex.m_dupeNr;
  39. }
  40. }
  41. }
  42. }
  43. // add a polygon to the submesh
  44. void MeshBuilderSubMesh::AddPolygon(const AZStd::vector<MeshBuilderVertexLookup>& indices, const AZStd::vector<size_t>& jointList)
  45. {
  46. // pre-allocate
  47. if (m_indices.size() % 10000 == 0)
  48. {
  49. m_indices.reserve(m_indices.size() + 10000);
  50. }
  51. // for all vertices in the poly
  52. m_polyVertexCounts.emplace_back(aznumeric_caster(indices.size()));
  53. for (const MeshBuilderVertexLookup& index : indices)
  54. {
  55. // add unused vertices to the list
  56. if (CheckIfHasVertex(index) == false)
  57. {
  58. const size_t numDupes = m_mesh->CalcNumVertexDuplicates(this, index.mOrgVtx);
  59. const ptrdiff_t numToAdd = (aznumeric_cast<ptrdiff_t>(index.mDuplicateNr) - aznumeric_cast<ptrdiff_t>(numDupes)) + 1;
  60. // Create entries in the whole Mesh's vertices array to fill in any missing entries, up to the current
  61. // vertex duplicate number. It is possible that this is duplicate 2 of original vertex 0, and duplicate
  62. // 1 has not been encountered yet. In this case, fill in an invalid index for duplicate 1, since we do
  63. // not yet know which submesh that duplicate belongs to.
  64. for (ptrdiff_t i = 0; i < numToAdd; ++i)
  65. {
  66. const size_t realVertexNr = ((numDupes + i) == index.mDuplicateNr) ? m_numVertices : InvalidIndex;
  67. m_mesh->AddSubMeshVertex(index.mOrgVtx, {
  68. /* .m_realVertexNr = */ realVertexNr,
  69. /* .m_dupeNr = */ numDupes + i,
  70. /* .m_subMesh = */ this
  71. });
  72. }
  73. if (numToAdd <= 0)
  74. {
  75. // If none were added, the submesh vertex was added as a placeholder with an invalid index in a
  76. // previous iteration by a different submesh. We now know which submesh this duplicate belongs to,
  77. // so reset the real vertex index to this mesh's current vertex count.
  78. m_mesh->SetRealVertexNrForSubMeshVertex(this, index.mOrgVtx, index.mDuplicateNr, m_numVertices);
  79. }
  80. m_numVertices++;
  81. }
  82. // an index in the local vertices array
  83. m_indices.emplace_back(index);
  84. }
  85. // add the new joints
  86. for (size_t jointIndex : jointList)
  87. {
  88. if (AZStd::find(m_jointList.begin(), m_jointList.end(), jointIndex) == m_jointList.end())
  89. {
  90. m_jointList.emplace_back(jointIndex);
  91. }
  92. }
  93. }
  94. // check if we can handle a given poly inside the submesh
  95. bool MeshBuilderSubMesh::CanHandlePolygon(const AZStd::vector<size_t>& orgVertexNumbers, size_t materialIndex, AZStd::vector<size_t>& outJointList) const
  96. {
  97. // if the material isn't the same, we can't handle it
  98. if (m_materialIndex != materialIndex)
  99. {
  100. return false;
  101. }
  102. // check if there is still space for the poly vertices (worst case scenario), and if this won't go over the 16 bit index buffer limit
  103. const size_t numPolyVerts = orgVertexNumbers.size();
  104. if (m_numVertices + numPolyVerts > m_mesh->m_maxSubMeshVertices)
  105. {
  106. return false;
  107. }
  108. const MeshBuilderSkinningInfo* skinningInfo = m_mesh->GetSkinningInfo();
  109. if (skinningInfo)
  110. {
  111. // get the maximum number of allowed bones per submesh
  112. const size_t maxNumBones = m_mesh->GetMaxBonesPerSubMesh();
  113. // extract the list of bones used by this poly
  114. m_mesh->ExtractBonesForPolygon(orgVertexNumbers, outJointList);
  115. // check if worst case scenario would be allowed
  116. // this is when we have to add all triangle bones to the bone list
  117. if (m_jointList.size() + outJointList.size() > maxNumBones)
  118. {
  119. return false;
  120. }
  121. // calculate the real number of extra bones needed
  122. size_t numExtraNeeded = 0;
  123. const size_t numPolyBones = outJointList.size();
  124. for (size_t i = 0; i < numPolyBones; ++i)
  125. {
  126. if (AZStd::find(m_jointList.begin(), m_jointList.end(), outJointList.at(i)) == m_jointList.end())
  127. {
  128. numExtraNeeded++;
  129. }
  130. }
  131. // if we can't add the extra required bones to the list, because it would result in more than the
  132. // allowed number of bones, then return that we can't add this triangle to this submesh
  133. if (m_jointList.size() + numExtraNeeded > maxNumBones)
  134. {
  135. return false;
  136. }
  137. }
  138. // yeah, we can add this triangle to the submesh
  139. return true;
  140. }
  141. bool MeshBuilderSubMesh::CheckIfHasVertex(const MeshBuilderVertexLookup& vertex)
  142. {
  143. if (m_mesh->CalcNumVertexDuplicates(this, vertex.mOrgVtx) <= vertex.mDuplicateNr)
  144. {
  145. return false;
  146. }
  147. return (m_mesh->FindRealVertexNr(this, vertex.mOrgVtx, vertex.mDuplicateNr) != InvalidIndex);
  148. }
  149. size_t MeshBuilderSubMesh::GetIndex(size_t index) const
  150. {
  151. return m_mesh->FindRealVertexNr(this, m_indices[index].mOrgVtx, m_indices[index].mDuplicateNr);
  152. }
  153. size_t MeshBuilderSubMesh::CalcNumSimilarJoints(const AZStd::vector<size_t>& jointList) const
  154. {
  155. // reset our similar bones counter and get the number of bones from the input and submesh bone lists
  156. size_t numMatches = 0;
  157. // iterate through all bones from the input bone list and find the matching bones
  158. for (size_t inputJointIndex : jointList)
  159. {
  160. for (size_t jointIndex : jointList)
  161. {
  162. if (jointIndex == inputJointIndex)
  163. {
  164. numMatches++;
  165. break;
  166. }
  167. }
  168. }
  169. return numMatches;
  170. }
  171. } // namespace AZ::MeshBuilder