123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <gtest/gtest.h>
- #include <AzCore/base.h>
- #include <AzCore/std/containers/array.h>
- #include <AzCore/UnitTest/TestTypes.h>
- #include <Generation/Components/MeshOptimizer/MeshBuilder.h>
- namespace AZ::MeshBuilder
- {
- class CubeMeshVerticesTests
- : public UnitTest::LeakDetectionFixture
- {
- public:
- void SetUpMeshBuilder(size_t vertCount)
- {
- m_meshBuilder = AZStd::make_unique<AZ::MeshBuilder::MeshBuilder>(vertCount);
- // Original vertex numbers
- m_orgVtxLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerUInt32>(
- vertCount,
- false,
- false
- );
- // The positions layer
- m_posLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3>(
- vertCount,
- false,
- true
- );
- // The normals layer
- m_normalsLayer = m_meshBuilder->AddLayer<AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3>(
- vertCount,
- false,
- true
- );
- }
- void BuildCube(const bool useSharedNormals)
- {
- constexpr AZStd::array m_cubeVertexIndices = {
- size_t(0),1,2,
- 0,2,3,
- 1,5,6,
- 1,6,2,
- 5,4,7,
- 5,7,6,
- 4,0,3,
- 4,3,7,
- 1,0,4,
- 1,4,5,
- 3,2,6,
- 3,6,7
- };
- const AZStd::array m_cubeOriginalVertices = {
- AZ::Vector3(-0.5f, -0.5f, -0.5f),
- AZ::Vector3(0.5f, -0.5f, -0.5f),
- AZ::Vector3(0.5f, 0.5f, -0.5f),
- AZ::Vector3(-0.5f, 0.5f, -0.5f),
- AZ::Vector3(-0.5f, -0.5f, 0.5f),
- AZ::Vector3(0.5f, -0.5f, 0.5f),
- AZ::Vector3(0.5f, 0.5f, 0.5f),
- AZ::Vector3(-0.5f, 0.5f, 0.5f)
- };
- // Create the mesh builder and fill in the layers with cube vertices.
- const size_t orgVertCount = m_cubeOriginalVertices.size();
- const size_t triangleCount = m_cubeVertexIndices.size() / 3;
- SetUpMeshBuilder(orgVertCount);
- const size_t materialId = 0;
- for (size_t faceNum = 0; faceNum < triangleCount; ++faceNum)
- {
- const size_t indexA = faceNum * 3;
- const size_t indexB = (faceNum * 3) + 1;
- const size_t indexC = (faceNum * 3) + 2;
- const AZ::Vector3& p1 = m_cubeOriginalVertices[m_cubeVertexIndices[indexA]];
- const AZ::Vector3& p2 = m_cubeOriginalVertices[m_cubeVertexIndices[indexB]];
- const AZ::Vector3& p3 = m_cubeOriginalVertices[m_cubeVertexIndices[indexC]];
- const AZ::Vector3 sharedNormal = (p2 - p1).Cross(p3 - p1).GetNormalized();
- m_meshBuilder->BeginPolygon(materialId);
- for (size_t vertexOfFace = 0; vertexOfFace < 3; ++vertexOfFace)
- {
- size_t vertexNum = faceNum * 3 + vertexOfFace;
- const AZ::Vector3& smoothShadedNormal = m_cubeOriginalVertices[m_cubeVertexIndices[vertexNum]].GetNormalized();
- m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(m_cubeVertexIndices[vertexNum]));
- m_posLayer->SetCurrentVertexValue(m_cubeOriginalVertices[m_cubeVertexIndices[vertexNum]]);
- m_normalsLayer->SetCurrentVertexValue(useSharedNormals ? sharedNormal : smoothShadedNormal);
- m_meshBuilder->AddPolygonVertex(m_cubeVertexIndices[vertexNum]);
- }
- m_meshBuilder->EndPolygon();
- }
- }
- public:
- AZStd::unique_ptr<AZ::MeshBuilder::MeshBuilder> m_meshBuilder;
- AZ::MeshBuilder::MeshBuilderVertexAttributeLayerUInt32* m_orgVtxLayer = nullptr;
- AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3* m_posLayer = nullptr;
- AZ::MeshBuilder::MeshBuilderVertexAttributeLayerVector3* m_normalsLayer = nullptr;
- };
- TEST_F(CubeMeshVerticesTests, SmoothShadedCubeMeshVertexDedup)
- {
- BuildCube(/* useSharedNormals= */false);
- const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
- EXPECT_EQ(vertexDupeRatio, 1.0f) << "No duplicated vertex should be created.";
- }
- TEST_F(CubeMeshVerticesTests, FlatShadedCubeMeshVertexDedup)
- {
- BuildCube(/* useSharedNormals= */true);
- const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
- EXPECT_EQ(vertexDupeRatio, 3.0f) << "Vertex ratio for flat shaded cube should be 24/8(Unique Normals/originalVertices).";
- }
- class TriangleFanMeshVerticesTestsFixture
- : public ::testing::WithParamInterface<size_t>,
- public CubeMeshVerticesTests
- {
- public:
- void SetUp() override
- {
- CubeMeshVerticesTests::SetUp();
- /*
- * 1 triangle fan:
- * / *
- * *__ *
- *
- * 3 triangles fan:
- * * *
- * \ | / *
- * \|/__ *
- *
- * 6 triangles fan:
- * * *
- * * \ | / *
- * * __\|/__ *
- * * /|
- * * / |
- * * *
- *
- * etc.
- */
- // Individual vertices + shared/center vertex for triangle fan.
- m_numOrgVertices = (GetParam() * 2) + 1;
- }
- void BuildTriangleFan(const bool useSameNormal)
- {
- SetUpMeshBuilder(m_numOrgVertices);
- const size_t faceCount = (m_numOrgVertices - 1) / 2;
- const int materialId = 0;
- AZ::Vector3 centerVertex(0.0f, 0.0f, 0.0f);
- size_t vertexNum = 1;
- for (size_t faceNum = 0; faceNum < faceCount; ++faceNum)
- {
- m_meshBuilder->BeginPolygon(materialId);
- for (size_t vertexOfFace = 0; vertexOfFace < 3; ++vertexOfFace)
- {
- AZ::Vector3 normal(0.0f, 0.0f, 1.0f + (useSameNormal ? 0.0f : vertexNum));
- if (vertexOfFace == 0)
- {
- m_posLayer->SetCurrentVertexValue(centerVertex);
- m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(vertexOfFace));
- m_normalsLayer->SetCurrentVertexValue(normal);
- m_meshBuilder->AddPolygonVertex(vertexOfFace);
- }
- else
- {
- const float angle = vertexNum * (360.0f / m_numOrgVertices);
- const float x = AZ::Cos(angle);
- const float y = AZ::Sin(angle);
- AZ::Vector3 point(x, y, 0);
- m_posLayer->SetCurrentVertexValue(point);
- m_orgVtxLayer->SetCurrentVertexValue(static_cast<AZ::u32>(vertexNum));
- m_normalsLayer->SetCurrentVertexValue(normal);
- m_meshBuilder->AddPolygonVertex(vertexNum);
- vertexNum++;
- }
- }
- m_meshBuilder->EndPolygon();
- }
- }
- public:
- size_t m_numOrgVertices = 0;
- };
- TEST_P(TriangleFanMeshVerticesTestsFixture, SameNormalTriangleFanVertexDedup)
- {
- BuildTriangleFan(/* useSameNormal= */true);
- const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
- EXPECT_EQ(vertexDupeRatio, 1.0f) << "No duplicated vertex should be created.";
- }
- TEST_P(TriangleFanMeshVerticesTestsFixture, DifferentNormalTriangleFanVertexDedup)
- {
- BuildTriangleFan(/* useSameNormal= */false);
- const size_t faceCount = (m_numOrgVertices - 1) / 2;
- const float vertexDupeRatio = m_meshBuilder->CalcNumVertices() / aznumeric_cast<float>(m_meshBuilder->GetNumOrgVerts());
- const float expectedRatio = (faceCount * 3) / aznumeric_cast<float>(m_numOrgVertices);
- EXPECT_EQ(vertexDupeRatio, expectedRatio) << "Duplicated vertex ratio does not match expected ratio.";
- }
- static constexpr AZStd::array meshVerticesTestData = {
- size_t(1) /* number of triangles in a triangle fan*/,
- 3,
- 6,
- 9
- };
- INSTANTIATE_TEST_CASE_P(TriangleFanZVertexDedupTests,
- TriangleFanMeshVerticesTestsFixture,
- ::testing::ValuesIn(meshVerticesTestData)
- );
- } // namespace AZ::MeshBuilder
|