MeshVerticesTests.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 <gtest/gtest.h>
  9. #include <AzCore/base.h>
  10. #include <AzCore/std/containers/array.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. #include <Generation/Components/MeshOptimizer/MeshBuilder.h>
  13. namespace AZ::MeshBuilder
  14. {
  15. class CubeMeshVerticesTests
  16. : public UnitTest::LeakDetectionFixture
  17. {
  18. public:
  19. void SetUpMeshBuilder(size_t vertCount)
  20. {
  21. m_meshBuilder = AZStd::make_unique<AZ::MeshBuilder::MeshBuilder>(vertCount);
  22. // Original vertex numbers
  23. m_orgVtxLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerUInt32>(
  24. vertCount,
  25. false,
  26. false
  27. );
  28. // The positions layer
  29. m_posLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3>(
  30. vertCount,
  31. false,
  32. true
  33. );
  34. // The normals layer
  35. m_normalsLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3>(
  36. vertCount,
  37. false,
  38. true
  39. );
  40. }
  41. void BuildCube(const bool useSharedNormals)
  42. {
  43. constexpr AZStd::array m_cubeVertexIndices = {
  44. size_t(0),1,2,
  45. 0,2,3,
  46. 1,5,6,
  47. 1,6,2,
  48. 5,4,7,
  49. 5,7,6,
  50. 4,0,3,
  51. 4,3,7,
  52. 1,0,4,
  53. 1,4,5,
  54. 3,2,6,
  55. 3,6,7
  56. };
  57. const AZStd::array m_cubeOriginalVertices = {
  58. AZ::Vector3(-0.5f, -0.5f, -0.5f),
  59. AZ::Vector3(0.5f, -0.5f, -0.5f),
  60. AZ::Vector3(0.5f, 0.5f, -0.5f),
  61. AZ::Vector3(-0.5f, 0.5f, -0.5f),
  62. AZ::Vector3(-0.5f, -0.5f, 0.5f),
  63. AZ::Vector3(0.5f, -0.5f, 0.5f),
  64. AZ::Vector3(0.5f, 0.5f, 0.5f),
  65. AZ::Vector3(-0.5f, 0.5f, 0.5f)
  66. };
  67. // Create the mesh builder and fill in the layers with cube vertices.
  68. const size_t orgVertCount = m_cubeOriginalVertices.size();
  69. const size_t triangleCount = m_cubeVertexIndices.size() / 3;
  70. SetUpMeshBuilder(orgVertCount);
  71. const size_t materialId = 0;
  72. for (size_t faceNum = 0; faceNum < triangleCount; ++faceNum)
  73. {
  74. const size_t indexA = faceNum * 3;
  75. const size_t indexB = (faceNum * 3) + 1;
  76. const size_t indexC = (faceNum * 3) + 2;
  77. const AZ::Vector3& p1 = m_cubeOriginalVertices[m_cubeVertexIndices[indexA]];
  78. const AZ::Vector3& p2 = m_cubeOriginalVertices[m_cubeVertexIndices[indexB]];
  79. const AZ::Vector3& p3 = m_cubeOriginalVertices[m_cubeVertexIndices[indexC]];
  80. const AZ::Vector3 sharedNormal = (p2 - p1).Cross(p3 - p1).GetNormalized();
  81. m_meshBuilder->BeginPolygon(materialId);
  82. for (size_t vertexOfFace = 0; vertexOfFace < 3; ++vertexOfFace)
  83. {
  84. size_t vertexNum = faceNum * 3 + vertexOfFace;
  85. const AZ::Vector3& smoothShadedNormal = m_cubeOriginalVertices[m_cubeVertexIndices[vertexNum]].GetNormalized();
  86. m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(m_cubeVertexIndices[vertexNum]));
  87. m_posLayer->SetCurrentVertexValue(m_cubeOriginalVertices[m_cubeVertexIndices[vertexNum]]);
  88. m_normalsLayer->SetCurrentVertexValue(useSharedNormals ? sharedNormal : smoothShadedNormal);
  89. m_meshBuilder->AddPolygonVertex(m_cubeVertexIndices[vertexNum]);
  90. }
  91. m_meshBuilder->EndPolygon();
  92. }
  93. }
  94. public:
  95. AZStd::unique_ptr<AZ::MeshBuilder::MeshBuilder> m_meshBuilder;
  96. AZ::MeshBuilder::MeshBuilderVertexAttributeLayerUInt32* m_orgVtxLayer = nullptr;
  97. AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3* m_posLayer = nullptr;
  98. AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3* m_normalsLayer = nullptr;
  99. };
  100. TEST_F(CubeMeshVerticesTests, SmoothShadedCubeMeshVertexDedup)
  101. {
  102. BuildCube(/* useSharedNormals= */false);
  103. const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
  104. EXPECT_EQ(vertexDupeRatio, 1.0f) << "No duplicated vertex should be created.";
  105. }
  106. TEST_F(CubeMeshVerticesTests, FlatShadedCubeMeshVertexDedup)
  107. {
  108. BuildCube(/* useSharedNormals= */true);
  109. const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
  110. EXPECT_EQ(vertexDupeRatio, 3.0f) << "Vertex ratio for flat shaded cube should be 24/8(Unique Normals/originalVertices).";
  111. }
  112. class TriangleFanMeshVerticesTestsFixture
  113. : public ::testing::WithParamInterface<size_t>,
  114. public CubeMeshVerticesTests
  115. {
  116. public:
  117. void SetUp() override
  118. {
  119. CubeMeshVerticesTests::SetUp();
  120. /*
  121. * 1 triangle fan:
  122. * / *
  123. * *__ *
  124. *
  125. * 3 triangles fan:
  126. * * *
  127. * \ | / *
  128. * \|/__ *
  129. *
  130. * 6 triangles fan:
  131. * * *
  132. * * \ | / *
  133. * * __\|/__ *
  134. * * /|
  135. * * / |
  136. * * *
  137. *
  138. * etc.
  139. */
  140. // Individual vertices + shared/center vertex for triangle fan.
  141. m_numOrgVertices = (GetParam() * 2) + 1;
  142. }
  143. void BuildTriangleFan(const bool useSameNormal)
  144. {
  145. SetUpMeshBuilder(m_numOrgVertices);
  146. const size_t faceCount = (m_numOrgVertices - 1) / 2;
  147. const int materialId = 0;
  148. AZ::Vector3 centerVertex(0.0f, 0.0f, 0.0f);
  149. size_t vertexNum = 1;
  150. for (size_t faceNum = 0; faceNum < faceCount; ++faceNum)
  151. {
  152. m_meshBuilder->BeginPolygon(materialId);
  153. for (size_t vertexOfFace = 0; vertexOfFace < 3; ++vertexOfFace)
  154. {
  155. AZ::Vector3 normal(0.0f, 0.0f, 1.0f + (useSameNormal ? 0.0f : vertexNum));
  156. if (vertexOfFace == 0)
  157. {
  158. m_posLayer->SetCurrentVertexValue(centerVertex);
  159. m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(vertexOfFace));
  160. m_normalsLayer->SetCurrentVertexValue(normal);
  161. m_meshBuilder->AddPolygonVertex(vertexOfFace);
  162. }
  163. else
  164. {
  165. const float angle = vertexNum * (360.0f / m_numOrgVertices);
  166. const float x = AZ::Cos(angle);
  167. const float y = AZ::Sin(angle);
  168. AZ::Vector3 point(x, y, 0);
  169. m_posLayer->SetCurrentVertexValue(point);
  170. m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(vertexNum));
  171. m_normalsLayer->SetCurrentVertexValue(normal);
  172. m_meshBuilder->AddPolygonVertex(vertexNum);
  173. vertexNum++;
  174. }
  175. }
  176. m_meshBuilder->EndPolygon();
  177. }
  178. }
  179. public:
  180. size_t m_numOrgVertices = 0;
  181. };
  182. TEST_P(TriangleFanMeshVerticesTestsFixture, SameNormalTriangleFanVertexDedup)
  183. {
  184. BuildTriangleFan(/* useSameNormal= */true);
  185. const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
  186. EXPECT_EQ(vertexDupeRatio, 1.0f) << "No duplicated vertex should be created.";
  187. }
  188. TEST_P(TriangleFanMeshVerticesTestsFixture, DifferentNormalTriangleFanVertexDedup)
  189. {
  190. BuildTriangleFan(/* useSameNormal= */false);
  191. const size_t faceCount = (m_numOrgVertices - 1) / 2;
  192. const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
  193. const float expectedRatio = (faceCount * 3) / aznumeric_cast<float>(m_numOrgVertices);
  194. EXPECT_EQ(vertexDupeRatio, expectedRatio) << "Duplicated vertex ratio does not match expected ratio.";
  195. }
  196. static constexpr AZStd::array meshVerticesTestData = {
  197. size_t(1) /* number of triangles in a triangle fan*/,
  198. 3,
  199. 6,
  200. 9
  201. };
  202. INSTANTIATE_TEST_CASE_P(TriangleFanZVertexDedupTests,
  203. TriangleFanMeshVerticesTestsFixture,
  204. ::testing::ValuesIn(meshVerticesTestData)
  205. );
  206. } // namespace AZ::MeshBuilder