MeshBuilderTests.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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/std/smart_ptr/unique_ptr.h>
  9. #include <Generation/Components/MeshOptimizer/MeshBuilder.h>
  10. #include <Generation/Components/MeshOptimizer/MeshBuilderSubMesh.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. namespace AZ::MeshBuilder
  13. {
  14. struct MeshBuilderFixtureParameter
  15. {
  16. size_t m_numRows;
  17. size_t m_numColumns;
  18. size_t m_maxSubMeshVertices;
  19. };
  20. class MeshBuilderFixture
  21. : public UnitTest::LeakDetectionFixture
  22. , public ::testing::WithParamInterface<MeshBuilderFixtureParameter>
  23. {
  24. public:
  25. static void AddVertex(MeshBuilder* meshBuilder, size_t orgVtxNr,
  26. MeshBuilderVertexAttributeLayerVector3* posLayer, const AZ::Vector3& position,
  27. MeshBuilderVertexAttributeLayerVector3* normalsLayer, const AZ::Vector3& normal)
  28. {
  29. posLayer->SetCurrentVertexValue(position);
  30. normalsLayer->SetCurrentVertexValue(normal);
  31. meshBuilder->AddPolygonVertex(orgVtxNr);
  32. }
  33. static AZStd::unique_ptr<MeshBuilder> GenerateMesh(size_t numRows, size_t numColumns, size_t maxSubMeshVertices)
  34. {
  35. const size_t numOrgVertices = numRows * numColumns;
  36. auto meshBuilder = AZStd::make_unique<MeshBuilder>(numOrgVertices, /*maxBonesPerSubMesh=*/64, maxSubMeshVertices);
  37. meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerUInt32>(numOrgVertices, false, false);
  38. auto* posLayer = meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerVector3>(numOrgVertices, false, true);
  39. auto* normalsLayer = meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerVector3>(numOrgVertices, false, true);
  40. size_t materialIndex = 0;
  41. const AZ::Vector3 normal(0.0f, 0.0f, 1.0f);
  42. for (size_t row = 0; row < (numRows-1); ++row)
  43. {
  44. const auto rowFloat = static_cast<float>(row);
  45. for (size_t column = 0; column < (numColumns-1); ++column)
  46. {
  47. const auto columnFloat = static_cast<float>(column);
  48. // 4 +----------+ 3
  49. // | /|
  50. // | T2 / |
  51. // | / |
  52. // | / |
  53. // | / |
  54. // | / |
  55. // | / |
  56. // | / T1 |
  57. // | / |
  58. // 1 +----------+ 2
  59. const size_t orgVtxNr1 = column * numRows + row;
  60. const size_t orgVtxNr2 = (column + 1) * numRows + row;
  61. const size_t orgVtxNr3 = (column + 1) * numRows + (row+1);
  62. const size_t orgVtxNr4 = column * numRows + (row+1);
  63. const AZ::Vector3 pos1(columnFloat, rowFloat, 0.0f);
  64. const AZ::Vector3 pos2(columnFloat+1.0f, rowFloat, 0.0f);
  65. const AZ::Vector3 pos3(columnFloat+1.0f, rowFloat+1.0f, 0.0f);
  66. const AZ::Vector3 pos4(columnFloat, rowFloat+1.0f, 0.0f);
  67. // Triangle 1
  68. meshBuilder->BeginPolygon(materialIndex);
  69. AddVertex(meshBuilder.get(), orgVtxNr1, posLayer, pos1, normalsLayer, normal);
  70. AddVertex(meshBuilder.get(), orgVtxNr2, posLayer, pos2, normalsLayer, normal);
  71. AddVertex(meshBuilder.get(), orgVtxNr3, posLayer, pos3, normalsLayer, normal);
  72. meshBuilder->EndPolygon();
  73. // Triangle 2
  74. meshBuilder->BeginPolygon(materialIndex);
  75. AddVertex(meshBuilder.get(), orgVtxNr1, posLayer, pos1, normalsLayer, normal);
  76. AddVertex(meshBuilder.get(), orgVtxNr3, posLayer, pos3, normalsLayer, normal);
  77. AddVertex(meshBuilder.get(), orgVtxNr4, posLayer, pos4, normalsLayer, normal);
  78. meshBuilder->EndPolygon();
  79. }
  80. }
  81. EXPECT_EQ(meshBuilder->GetNumOrgVerts(), numRows * numColumns);
  82. EXPECT_EQ(meshBuilder->GetNumPolygons(), (numRows - 1) * (numColumns - 1) * 2);
  83. return meshBuilder;
  84. }
  85. static void CheckMaxSubMeshVertices(MeshBuilder* meshBuilder, size_t maxSubMeshVertices)
  86. {
  87. const size_t numSubMeshes = meshBuilder->GetNumSubMeshes();
  88. for (size_t i = 0; i < numSubMeshes; ++i)
  89. {
  90. const MeshBuilderSubMesh* subMesh = meshBuilder->GetSubMesh(i);
  91. EXPECT_TRUE(subMesh->GetNumVertices() <= maxSubMeshVertices)
  92. << "Sub mesh splitting failed. Sub mesh contains more than the max number of allowed vertices.";
  93. }
  94. }
  95. static void CheckSubMeshSplits(MeshBuilder* meshBuilder, size_t maxSubMeshVertices)
  96. {
  97. const size_t numPolygons = meshBuilder->GetNumPolygons();
  98. const size_t numSubMeshes = meshBuilder->GetNumSubMeshes();
  99. size_t numAccumulatedPolys = 0;
  100. size_t numAccumulatedSubMeshVertices = 0;
  101. for (size_t i = 0; i < numSubMeshes; ++i)
  102. {
  103. const MeshBuilderSubMesh* subMesh = meshBuilder->GetSubMesh(i);
  104. numAccumulatedSubMeshVertices += subMesh->GetNumVertices();
  105. const size_t numPolysPerSubMesh = subMesh->GetNumPolygons();
  106. numAccumulatedPolys += numPolysPerSubMesh;
  107. }
  108. EXPECT_EQ(numPolygons, numAccumulatedPolys)
  109. << "Accumulated polygon count for sub meshes does not match total polygon count.";
  110. if (numAccumulatedSubMeshVertices <= maxSubMeshVertices)
  111. {
  112. EXPECT_EQ(numSubMeshes, 1)
  113. << "The vertex count is lower than the maximum allowed vertex count per sub mesh. No split needed and expecting a single sub mesh.";
  114. }
  115. else
  116. {
  117. size_t bestCastNumSubMeshes = numAccumulatedSubMeshVertices / maxSubMeshVertices;
  118. EXPECT_TRUE(numSubMeshes >= bestCastNumSubMeshes)
  119. << "The number of sub meshes is lower than the theoretical best case. One or many splits got missed.";
  120. }
  121. }
  122. };
  123. TEST_P(MeshBuilderFixture, MeshBuilderTest_MaxSubMeshVertices)
  124. {
  125. const MeshBuilderFixtureParameter& param = GetParam();
  126. AZStd::unique_ptr<MeshBuilder> meshBuilder = GenerateMesh(param.m_numRows, param.m_numColumns, param.m_maxSubMeshVertices);
  127. CheckMaxSubMeshVertices(meshBuilder.get(), param.m_maxSubMeshVertices);
  128. CheckSubMeshSplits(meshBuilder.get(), param.m_maxSubMeshVertices);
  129. }
  130. static constexpr AZStd::array meshBuilderMaxSubMeshVerticesTestData
  131. {
  132. MeshBuilderFixtureParameter {
  133. /*m_numRows=*/2,
  134. /*m_numColumns=*/2,
  135. /*m_maxSubMeshVertices=*/100
  136. },
  137. MeshBuilderFixtureParameter {
  138. 4,
  139. 4,
  140. 3
  141. },
  142. MeshBuilderFixtureParameter {
  143. 4,
  144. 4,
  145. 15
  146. },
  147. MeshBuilderFixtureParameter {
  148. 4,
  149. 32,
  150. 9
  151. },
  152. MeshBuilderFixtureParameter {
  153. 64,
  154. 16,
  155. 50
  156. },
  157. MeshBuilderFixtureParameter {
  158. 100,
  159. 100,
  160. 64
  161. },
  162. MeshBuilderFixtureParameter {
  163. 100,
  164. 100,
  165. 512
  166. },
  167. MeshBuilderFixtureParameter {
  168. 100,
  169. 100,
  170. 1000
  171. },
  172. MeshBuilderFixtureParameter {
  173. 1000,
  174. 100,
  175. 10000
  176. }
  177. };
  178. INSTANTIATE_TEST_CASE_P(MeshBuilderTest_MaxSubMeshVertices,
  179. MeshBuilderFixture,
  180. ::testing::ValuesIn(meshBuilderMaxSubMeshVerticesTestData));
  181. } // namespace AZ::MeshBuilder