You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
8.0 KiB
C++
206 lines
8.0 KiB
C++
/*
|
|
* 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 <AzCore/std/smart_ptr/unique_ptr.h>
|
|
#include <Generation/Components/MeshOptimizer/MeshBuilder.h>
|
|
#include <Generation/Components/MeshOptimizer/MeshBuilderSubMesh.h>
|
|
#include <AzCore/UnitTest/TestTypes.h>
|
|
|
|
namespace AZ::MeshBuilder
|
|
{
|
|
struct MeshBuilderFixtureParameter
|
|
{
|
|
size_t m_numRows;
|
|
size_t m_numColumns;
|
|
size_t m_maxSubMeshVertices;
|
|
};
|
|
|
|
class MeshBuilderFixture
|
|
: public UnitTest::ScopedAllocatorSetupFixture
|
|
, public ::testing::WithParamInterface<MeshBuilderFixtureParameter>
|
|
{
|
|
public:
|
|
static void AddVertex(MeshBuilder* meshBuilder, size_t orgVtxNr,
|
|
MeshBuilderVertexAttributeLayerVector3* posLayer, const AZ::Vector3& position,
|
|
MeshBuilderVertexAttributeLayerVector3* normalsLayer, const AZ::Vector3& normal)
|
|
{
|
|
posLayer->SetCurrentVertexValue(position);
|
|
normalsLayer->SetCurrentVertexValue(normal);
|
|
meshBuilder->AddPolygonVertex(orgVtxNr);
|
|
}
|
|
|
|
static AZStd::unique_ptr<MeshBuilder> GenerateMesh(size_t numRows, size_t numColumns, size_t maxSubMeshVertices)
|
|
{
|
|
const size_t numOrgVertices = numRows * numColumns;
|
|
auto meshBuilder = AZStd::make_unique<MeshBuilder>(numOrgVertices, /*maxBonesPerSubMesh=*/64, maxSubMeshVertices);
|
|
|
|
meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerUInt32>(numOrgVertices, false, false);
|
|
auto* posLayer = meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerVector3>(numOrgVertices, false, true);
|
|
auto* normalsLayer = meshBuilder->AddLayer<MeshBuilderVertexAttributeLayerVector3>(numOrgVertices, false, true);
|
|
|
|
|
|
size_t materialIndex = 0;
|
|
|
|
const AZ::Vector3 normal(0.0f, 0.0f, 1.0f);
|
|
for (size_t row = 0; row < (numRows-1); ++row)
|
|
{
|
|
const auto rowFloat = static_cast<float>(row);
|
|
for (size_t column = 0; column < (numColumns-1); ++column)
|
|
{
|
|
const auto columnFloat = static_cast<float>(column);
|
|
|
|
// 4 +----------+ 3
|
|
// | /|
|
|
// | T2 / |
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// | / T1 |
|
|
// | / |
|
|
// 1 +----------+ 2
|
|
|
|
const size_t orgVtxNr1 = column * numRows + row;
|
|
const size_t orgVtxNr2 = (column + 1) * numRows + row;
|
|
const size_t orgVtxNr3 = (column + 1) * numRows + (row+1);
|
|
const size_t orgVtxNr4 = column * numRows + (row+1);
|
|
|
|
const AZ::Vector3 pos1(columnFloat, rowFloat, 0.0f);
|
|
const AZ::Vector3 pos2(columnFloat+1.0f, rowFloat, 0.0f);
|
|
const AZ::Vector3 pos3(columnFloat+1.0f, rowFloat+1.0f, 0.0f);
|
|
const AZ::Vector3 pos4(columnFloat, rowFloat+1.0f, 0.0f);
|
|
|
|
// Triangle 1
|
|
meshBuilder->BeginPolygon(materialIndex);
|
|
AddVertex(meshBuilder.get(), orgVtxNr1, posLayer, pos1, normalsLayer, normal);
|
|
AddVertex(meshBuilder.get(), orgVtxNr2, posLayer, pos2, normalsLayer, normal);
|
|
AddVertex(meshBuilder.get(), orgVtxNr3, posLayer, pos3, normalsLayer, normal);
|
|
meshBuilder->EndPolygon();
|
|
|
|
// Triangle 2
|
|
meshBuilder->BeginPolygon(materialIndex);
|
|
AddVertex(meshBuilder.get(), orgVtxNr1, posLayer, pos1, normalsLayer, normal);
|
|
AddVertex(meshBuilder.get(), orgVtxNr3, posLayer, pos3, normalsLayer, normal);
|
|
AddVertex(meshBuilder.get(), orgVtxNr4, posLayer, pos4, normalsLayer, normal);
|
|
meshBuilder->EndPolygon();
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(meshBuilder->GetNumOrgVerts(), numRows * numColumns);
|
|
EXPECT_EQ(meshBuilder->GetNumPolygons(), (numRows - 1) * (numColumns - 1) * 2);
|
|
|
|
return meshBuilder;
|
|
}
|
|
|
|
static void CheckMaxSubMeshVertices(MeshBuilder* meshBuilder, size_t maxSubMeshVertices)
|
|
{
|
|
const size_t numSubMeshes = meshBuilder->GetNumSubMeshes();
|
|
for (size_t i = 0; i < numSubMeshes; ++i)
|
|
{
|
|
const MeshBuilderSubMesh* subMesh = meshBuilder->GetSubMesh(i);
|
|
EXPECT_TRUE(subMesh->GetNumVertices() <= maxSubMeshVertices)
|
|
<< "Sub mesh splitting failed. Sub mesh contains more than the max number of allowed vertices.";
|
|
}
|
|
}
|
|
|
|
static void CheckSubMeshSplits(MeshBuilder* meshBuilder, size_t maxSubMeshVertices)
|
|
{
|
|
const size_t numPolygons = meshBuilder->GetNumPolygons();
|
|
const size_t numSubMeshes = meshBuilder->GetNumSubMeshes();
|
|
|
|
size_t numAccumulatedPolys = 0;
|
|
size_t numAccumulatedSubMeshVertices = 0;
|
|
for (size_t i = 0; i < numSubMeshes; ++i)
|
|
{
|
|
const MeshBuilderSubMesh* subMesh = meshBuilder->GetSubMesh(i);
|
|
numAccumulatedSubMeshVertices += subMesh->GetNumVertices();
|
|
|
|
const size_t numPolysPerSubMesh = subMesh->GetNumPolygons();
|
|
numAccumulatedPolys += numPolysPerSubMesh;
|
|
}
|
|
|
|
EXPECT_EQ(numPolygons, numAccumulatedPolys)
|
|
<< "Accumulated polygon count for sub meshes does not match total polygon count.";
|
|
|
|
if (numAccumulatedSubMeshVertices <= maxSubMeshVertices)
|
|
{
|
|
EXPECT_EQ(numSubMeshes, 1)
|
|
<< "The vertex count is lower than the maximum allowed vertex count per sub mesh. No split needed and expecting a single sub mesh.";
|
|
}
|
|
else
|
|
{
|
|
size_t bestCastNumSubMeshes = numAccumulatedSubMeshVertices / maxSubMeshVertices;
|
|
EXPECT_TRUE(numSubMeshes >= bestCastNumSubMeshes)
|
|
<< "The number of sub meshes is lower than the theoretical best case. One or many splits got missed.";
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST_P(MeshBuilderFixture, MeshBuilderTest_MaxSubMeshVertices)
|
|
{
|
|
const MeshBuilderFixtureParameter& param = GetParam();
|
|
AZStd::unique_ptr<MeshBuilder> meshBuilder = GenerateMesh(param.m_numRows, param.m_numColumns, param.m_maxSubMeshVertices);
|
|
CheckMaxSubMeshVertices(meshBuilder.get(), param.m_maxSubMeshVertices);
|
|
CheckSubMeshSplits(meshBuilder.get(), param.m_maxSubMeshVertices);
|
|
}
|
|
|
|
static constexpr AZStd::array meshBuilderMaxSubMeshVerticesTestData
|
|
{
|
|
MeshBuilderFixtureParameter {
|
|
/*m_numRows=*/2,
|
|
/*m_numColumns=*/2,
|
|
/*m_maxSubMeshVertices=*/100
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
4,
|
|
4,
|
|
3
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
4,
|
|
4,
|
|
15
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
4,
|
|
32,
|
|
9
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
64,
|
|
16,
|
|
50
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
100,
|
|
100,
|
|
64
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
100,
|
|
100,
|
|
512
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
100,
|
|
100,
|
|
1000
|
|
},
|
|
MeshBuilderFixtureParameter {
|
|
1000,
|
|
100,
|
|
10000
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_CASE_P(MeshBuilderTest_MaxSubMeshVertices,
|
|
MeshBuilderFixture,
|
|
::testing::ValuesIn(meshBuilderMaxSubMeshVerticesTestData));
|
|
} // namespace AZ::MeshBuilder
|