Integrating github/staging through commit ab87ed9

This commit is contained in:
alexpete
2021-04-09 11:27:37 -07:00
parent ae62a97894
commit 1044dc3da1
1582 changed files with 29374 additions and 519051 deletions
@@ -11,6 +11,7 @@
*/
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/numeric.h>
#include <AzCore/Jobs/JobFunction.h>
@@ -46,20 +47,15 @@ namespace AZ::MeshBuilder
for (size_t d = 0; d < numDuplicates; ++d)
{
// check if the submitted vertex data is equal in all layers for the current duplicate
bool allDataEqual = true;
const size_t numLayers = m_layers.size();
for (size_t layer = 0; layer < numLayers && allDataEqual; ++layer)
const bool allDataEqual = AZStd::all_of(begin(m_layers), end(m_layers), [orgVertexNr, d](const AZStd::unique_ptr<MeshBuilderVertexAttributeLayer>& layer)
{
if (m_layers[layer]->CheckIfIsVertexEqual(orgVertexNr, d) == false)
{
allDataEqual = false;
}
}
return layer->CheckIfIsVertexEqual(orgVertexNr, d);
});
// if so, we have found a matching vertex!
if (allDataEqual)
{
return MeshBuilderVertexLookup(orgVertexNr, d);
return {orgVertexNr, d};
}
}
@@ -131,67 +127,47 @@ namespace AZ::MeshBuilder
AZStd::vector<size_t> polyJointList;
ExtractBonesForPolygon(orgVertexNumbers, polyJointList);
// create our list of possible submeshes, start value are all submeshes available
AZStd::vector<MeshBuilderSubMesh*> possibleSubMeshes;
possibleSubMeshes.reserve(m_subMeshes.size());
for (const AZStd::unique_ptr<MeshBuilderSubMesh>& subMesh : m_subMeshes)
// find the submesh with the most similar bones
size_t maxMatchings = 0;
const auto* bestMatchingSubMesh = m_subMeshes.cend();
for (const auto* subMesh = m_subMeshes.cbegin(); subMesh != m_subMeshes.cend(); ++subMesh)
{
possibleSubMeshes.emplace_back(subMesh.get());
// get the number of matching bones from the current submesh and the given polygon
const size_t currentNumMatches = (*subMesh)->CalcNumSimilarJoints(polyJointList);
// if the current submesh has more similar bones than the current maximum we found a better one
if (currentNumMatches > maxMatchings)
{
maxMatchings = currentNumMatches;
bestMatchingSubMesh = subMesh;
// check if this submesh already our perfect match
if (currentNumMatches == polyJointList.size())
{
break;
}
}
}
while (!possibleSubMeshes.empty())
// if we cannot find a submesh with enough similar joints, find any one that can handle the polygon
if (bestMatchingSubMesh == m_subMeshes.cend())
{
size_t maxMatchings = 0;
size_t foundSubMeshNr = InvalidIndex;
const size_t numPossibleSubMeshes = possibleSubMeshes.size();
// iterate over all submeshes and find the one with the most similar bones
for (size_t i = 0; i < numPossibleSubMeshes; ++i)
bestMatchingSubMesh = AZStd::find_if(m_subMeshes.cbegin(), m_subMeshes.cend(), [&orgVertexNumbers, &materialIndex, &polyJointList](const auto& subMesh)
{
// get the number of matching bones from the current submesh and the given polygon
const size_t currentNumMatches = possibleSubMeshes[i]->CalcNumSimilarJoints(polyJointList);
return subMesh->CanHandlePolygon(orgVertexNumbers, materialIndex, polyJointList);
});
// if the current submesh has more similar bones than the current maximum we found a better one
if (currentNumMatches > maxMatchings)
{
// check if this submesh already our perfect match
if (currentNumMatches == polyJointList.size())
{
// check if the submesh which has the most common bones with the given polygon can handle it
if (possibleSubMeshes[i]->CanHandlePolygon(orgVertexNumbers, materialIndex, polyJointList))
{
return possibleSubMeshes[i];
}
}
maxMatchings = currentNumMatches;
foundSubMeshNr = i;
}
}
// if we cannot find a submesh return nullptr and create a new one
if (foundSubMeshNr == InvalidIndex)
if (bestMatchingSubMesh != m_subMeshes.cend())
{
for (MeshBuilderSubMesh* possibleSubMesh : possibleSubMeshes)
{
// check if the submesh which has the most common bones with the given polygon can handle it
if (possibleSubMesh->CanHandlePolygon(orgVertexNumbers, materialIndex, polyJointList))
{
return possibleSubMesh;
}
}
return nullptr;
return (*bestMatchingSubMesh).get();
}
return nullptr;
}
// check if the submesh which has the most common bones with the given polygon can handle it
if (possibleSubMeshes[foundSubMeshNr]->CanHandlePolygon(orgVertexNumbers, materialIndex, polyJointList))
{
return possibleSubMeshes[foundSubMeshNr];
}
// remove the found submesh from the possible submeshes directly so that we can don't find the same one in the next iteration again
possibleSubMeshes.erase(possibleSubMeshes.begin() + foundSubMeshNr);
// check if the submesh which has the most common bones with the given polygon can handle it
if ((*bestMatchingSubMesh)->CanHandlePolygon(orgVertexNumbers, materialIndex, polyJointList))
{
return (*bestMatchingSubMesh).get();
}
return nullptr;
@@ -219,19 +195,6 @@ namespace AZ::MeshBuilder
subMesh->AddPolygon(indices, m_polyJointList);
}
void MeshBuilder::OptimizeTriangleList()
{
if (!CheckIfIsTriangleMesh())
{
return;
}
for (const AZStd::unique_ptr<MeshBuilderSubMesh>& subMesh : m_subMeshes)
{
subMesh->Optimize();
}
}
void MeshBuilder::ExtractBonesForPolygon(const AZStd::vector<size_t>& orgVertexNumbers, AZStd::vector<size_t>& outPolyJointList) const
{
// get rid of existing data
@@ -302,16 +265,6 @@ namespace AZ::MeshBuilder
jobCompletion.StartAndWaitForCompletion();
}
bool MeshBuilder::CheckIfIsTriangleMesh() const
{
return AZStd::all_of(begin(m_polyVertexCounts), end(m_polyVertexCounts), [](AZ::u8 count) { return count == 3; });
}
bool MeshBuilder::CheckIfIsQuadMesh() const
{
return AZStd::all_of(begin(m_polyVertexCounts), end(m_polyVertexCounts), [](AZ::u8 count) { return count == 4; });
}
void MeshBuilder::SetSkinningInfo(AZStd::unique_ptr<MeshBuilderSkinningInfo> skinningInfo)
{
m_skinningInfo = AZStd::move(skinningInfo);
@@ -330,20 +283,27 @@ namespace AZ::MeshBuilder
return InvalidIndex;
}
const MeshBuilder::SubMeshVertex* MeshBuilder::FindSubMeshVertex(MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const
void MeshBuilder::SetRealVertexNrForSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr, size_t realVertexNr)
{
for (const SubMeshVertex& subMeshVertex : m_vertices[orgVtx])
SubMeshVertex* subMeshVertex = FindSubMeshVertex(subMesh, orgVtx, dupeNr);
if (!subMeshVertex)
{
if (subMeshVertex.m_subMesh == subMesh && subMeshVertex.m_dupeNr == dupeNr)
{
return &subMeshVertex;
}
return;
}
return nullptr;
subMeshVertex->m_realVertexNr = realVertexNr;
}
size_t MeshBuilder::CalcNumVertexDuplicates(MeshBuilderSubMesh* subMesh, size_t orgVtx) const
const MeshBuilder::SubMeshVertex* MeshBuilder::FindSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const
{
auto subMeshVertex = AZStd::find_if(m_vertices[orgVtx].begin(), m_vertices[orgVtx].end(), [subMesh, dupeNr](const SubMeshVertex& vertex)
{
return vertex.m_subMesh == subMesh && vertex.m_dupeNr == dupeNr;
});
return (subMeshVertex == m_vertices[orgVtx].end()) ? nullptr : subMeshVertex;
}
size_t MeshBuilder::CalcNumVertexDuplicates(const MeshBuilderSubMesh* subMesh, size_t orgVtx) const
{
size_t numDupes = 0;
for (const SubMeshVertex& subMeshVertex : m_vertices[orgVtx])
@@ -71,11 +71,6 @@ namespace AZ::MeshBuilder
size_t CalcNumIndices() const; // calculate the number of indices in the mesh
size_t CalcNumVertices() const; // calculate the number of vertices in the mesh
void OptimizeTriangleList(); // call this in order to optimize the index buffers on cache efficiency
bool CheckIfIsTriangleMesh() const;
bool CheckIfIsQuadMesh() const;
size_t GetNumOrgVerts() const { return m_numOrgVerts; }
void SetSkinningInfo(AZStd::unique_ptr<MeshBuilderSkinningInfo> skinningInfo);
const MeshBuilderSkinningInfo* GetSkinningInfo() const { return m_skinningInfo.get(); }
@@ -97,8 +92,9 @@ namespace AZ::MeshBuilder
};
size_t FindRealVertexNr(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const;
const SubMeshVertex* FindSubMeshVertex(MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const;
size_t CalcNumVertexDuplicates(MeshBuilderSubMesh* subMesh, size_t orgVtx) const;
void SetRealVertexNrForSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr, size_t realVertexNr);
const SubMeshVertex* FindSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr) const;
size_t CalcNumVertexDuplicates(const MeshBuilderSubMesh* subMesh, size_t orgVtx) const;
void GenerateSubMeshVertexOrders();
@@ -134,6 +130,10 @@ namespace AZ::MeshBuilder
{
return const_cast<MeshBuilderSubMesh*>(static_cast<const MeshBuilder*>(this)->FindSubMeshForPolygon(orgVertexNumbers, materialIndex));
}
SubMeshVertex* FindSubMeshVertex(const MeshBuilderSubMesh* subMesh, size_t orgVtx, size_t dupeNr)
{
return const_cast<SubMeshVertex*>(static_cast<const MeshBuilder*>(this)->FindSubMeshVertex(subMesh, orgVtx, dupeNr));
}
void ExtractBonesForPolygon(const AZStd::vector<size_t>& orgVertexNumbers, AZStd::vector<size_t>& outPolyJointList) const;
void AddPolygon(const AZStd::vector<MeshBuilderVertexLookup>& indices, const AZStd::vector<size_t>& orgVertexNumbers, size_t materialIndex);
};
@@ -14,6 +14,8 @@
#include <AzCore/std/sort.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/numeric.h>
#include "MeshBuilderSkinningInfo.h"
#include "MeshBuilderSubMesh.h"
#include "MeshBuilder.h"
@@ -35,58 +37,30 @@ namespace AZ::MeshBuilder
// optimize weights
void MeshBuilderSkinningInfo::OptimizeSkinningInfluences(AZStd::vector<Influence>& influences, float tolerance, size_t maxWeights)
{
if (influences.empty())
const auto influenceLess = [](const Influence& left, const Influence& right) { return left.mWeight < right.mWeight; };
// Move all the items greater than the tolerance to the end of the array
auto removePoint = AZStd::remove_if(begin(influences), end(influences), [tolerance](const Influence& influence) { return influence.mWeight < tolerance; });
if (removePoint == begin(influences))
{
return; // vertex has no weights, so nothing to optimize
// If this would remove all influences, keep the biggest one
auto [_, maxElement] = AZStd::minmax_element(begin(influences), end(influences), influenceLess);
AZStd::swap(removePoint, maxElement);
++removePoint;
}
// remove all weights below the tolerance
// at least keep one weight left after this optimization
for (auto it = begin(influences); it != end(influences);)
{
if (influences.size() == 1)
{
break;
}
float weight = it->mWeight;
if (weight < tolerance)
{
influences.erase(it);
}
else
{
++it;
}
}
influences.erase(removePoint, end(influences));
// reduce number of weights when needed
while (influences.size() > maxWeights)
{
float minWeight = FLT_MAX;
AZStd::vector<Influence>::iterator minInfluence = end(influences);
// find the smallest weight
for (auto it = begin(influences); it != end(influences); ++it)
{
if (it->mWeight < minWeight)
{
minWeight = it->mWeight;
minInfluence = it;
}
}
// remove this smallest weight
const auto [minInfluence, _] = AZStd::minmax_element(begin(influences), end(influences), influenceLess);
influences.erase(minInfluence);
}
// calculate the total weight
float totalWeight = 0;
for (const Influence& influence : influences)
{
totalWeight += influence.mWeight;
}
const float totalWeight = AZStd::accumulate(begin(influences), end(influences), 0.0f, [](float total, const Influence& influence) { return total + influence.mWeight; });
// normalize
for (Influence& influence : influences)
@@ -26,14 +26,6 @@ namespace AZ::MeshBuilder
{
}
void MeshBuilderSubMesh::Optimize()
{
if (m_vertexOrder.size() != m_numVertices)
{
GenerateVertexOrder();
}
}
// map the vertices to their original vertex and dupe numbers
void MeshBuilderSubMesh::GenerateVertexOrder()
{
@@ -76,16 +68,28 @@ namespace AZ::MeshBuilder
if (CheckIfHasVertex(index) == false)
{
const size_t numDupes = m_mesh->CalcNumVertexDuplicates(this, index.mOrgVtx);
const ptrdiff_t numToAdd = (index.mDuplicateNr - numDupes) + 1;
for (ptrdiff_t j = 0; j < numToAdd; ++j)
const ptrdiff_t numToAdd = (aznumeric_cast<ptrdiff_t>(index.mDuplicateNr) - aznumeric_cast<ptrdiff_t>(numDupes)) + 1;
// Create entries in the whole Mesh's vertices array to fill in any missing entries, up to the current
// vertex duplicate number. It is possible that this is duplicate 2 of original vertex 0, and duplicate
// 1 has not been encountered yet. In this case, fill in an invalid index for duplicate 1, since we do
// not yet know which submesh that duplicate belongs to.
for (ptrdiff_t i = 0; i < numToAdd; ++i)
{
const size_t realVertexNr = ((numDupes + i) == index.mDuplicateNr) ? m_numVertices : InvalidIndex;
m_mesh->AddSubMeshVertex(index.mOrgVtx, {
/* .m_realVertexNr = */ m_numVertices,
/* .m_dupeNr = */ numDupes + j,
/* .m_subMesh = */ this,
/* .m_realVertexNr = */ realVertexNr,
/* .m_dupeNr = */ numDupes + i,
/* .m_subMesh = */ this
});
++m_numVertices;
}
if (numToAdd <= 0)
{
// If none were added, the submesh vertex was added as a placeholder with an invalid index in a
// previous iteration by a different submesh. We now know which submesh this duplicate belongs to,
// so reset the real vertex index to this mesh's current vertex count.
m_mesh->SetRealVertexNrForSubMeshVertex(this, index.mOrgVtx, index.mDuplicateNr, m_numVertices);
}
m_numVertices++;
}
// an index in the local vertices array
@@ -45,7 +45,6 @@ namespace AZ::MeshBuilder
void SetJoints(const AZStd::vector<size_t>& jointList) { m_jointList = jointList; }
const AZStd::vector<size_t>& GetJoints() const { return m_jointList; }
void Optimize();
void AddPolygon(const AZStd::vector<MeshBuilderVertexLookup>& indices, const AZStd::vector<size_t>& jointList);
bool CanHandlePolygon(const AZStd::vector<size_t>& orgVertexNumbers, size_t materialIndex, AZStd::vector<size_t>& outJointList) const;
@@ -111,11 +111,11 @@ namespace AZ::MeshBuilder
}
else if constexpr (AZStd::is_floating_point_v<AttribType>)
{
return AZ::IsClose(mVertices[orgVtx][duplicate].mValue, mVertexValue);
return AZ::IsClose(mVertices[orgVtx][duplicate].mValue, mVertexValue, 0.00001f);
}
else
{
return mVertices[orgVtx][duplicate].mValue.IsClose(mVertexValue);
return mVertices[orgVtx][duplicate].mValue.IsClose(mVertexValue, 0.00001f);
}
}
@@ -50,9 +50,11 @@
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
#include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ILodRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ISkinRule.h>
#include <SceneAPI/SceneCore/Events/GenerateEventContext.h>
#include <SceneAPI/SceneCore/Events/ProcessingResult.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
@@ -87,6 +89,7 @@ namespace AZ::SceneGenerationComponents
using AZ::SceneAPI::Events::ProcessingResult;
using AZ::SceneAPI::Events::GenerateSimplificationEventContext;
using AZ::SceneAPI::SceneCore::GenerationComponent;
using AZ::SceneData::GraphData::BlendShapeData;
using AZ::SceneData::GraphData::MeshData;
using AZ::SceneData::GraphData::MeshVertexBitangentData;
using AZ::SceneData::GraphData::MeshVertexColorData;
@@ -110,9 +113,9 @@ namespace AZ::SceneGenerationComponents
}
}
template<class SkinWeightDataView>
template<class MeshDataType, class SkinWeightDataView>
static AZStd::unique_ptr<AZ::MeshBuilder::MeshBuilderSkinningInfo> ExtractSkinningInfo(
const IMeshData* meshData,
const MeshDataType* meshData,
const SkinWeightDataView& skinWeights,
AZ::u32 maxWeightsPerVertex,
float weightThreshold)
@@ -298,7 +301,10 @@ namespace AZ::SceneGenerationComponents
{
const AZStd::string optimizedName {graph.GetNodeName(originalNodeIndex).GetName(), graph.GetNodeName(originalNodeIndex).GetNameLength()};
const NodeIndex optimizedNodeIndex = graph.AddChild(optimizedMeshNodeIndex, optimizedName.c_str(), AZStd::move(optimizedNode));
graph.MakeEndPoint(optimizedNodeIndex);
if (graph.IsNodeEndPoint(originalNodeIndex))
{
graph.MakeEndPoint(optimizedNodeIndex);
}
}
};
addOptimizedNodes(nodeIndexes(Containers::MakeDerivedFilterView<IMeshVertexUVData>(childNodes(nodeIndex))), optimizedUVs);
@@ -312,12 +318,27 @@ namespace AZ::SceneGenerationComponents
graph.MakeEndPoint(optimizedSkinNodeIndex);
}
for (const NodeIndex& blendShapeNodeIndex : nodeIndexes(Containers::MakeDerivedFilterView<IBlendShapeData>(childNodes(nodeIndex))))
{
const IBlendShapeData* blendShapeNode = static_cast<IBlendShapeData*>(graph.GetNodeContent(blendShapeNodeIndex).get());
auto [optimizedBlendShape, _1, _2, _3 , _4, _5] = OptimizeMesh(blendShapeNode, {}, {}, {}, {}, {}, meshGroup, hasBlendShapes);
const AZStd::string optimizedName {graph.GetNodeName(blendShapeNodeIndex).GetName(), graph.GetNodeName(blendShapeNodeIndex).GetNameLength()};
const NodeIndex optimizedNodeIndex = graph.AddChild(optimizedMeshNodeIndex, optimizedName.c_str(), AZStd::move(optimizedBlendShape));
if (graph.IsNodeEndPoint(blendShapeNodeIndex))
{
graph.MakeEndPoint(optimizedNodeIndex);
}
}
const AZStd::array optimizedChildTypes {
azrtti_typeid<IMeshData>(),
azrtti_typeid<IMeshVertexUVData>(),
azrtti_typeid<IMeshVertexTangentData>(),
azrtti_typeid<IMeshVertexBitangentData>(),
azrtti_typeid<IMeshVertexColorData>(),
azrtti_typeid<ISkinWeightData>(),
azrtti_typeid<IBlendShapeData>(),
};
for (const NodeIndex& childNodeIndex : nodeIndexes(childNodes(nodeIndex)))
{
@@ -327,7 +348,7 @@ namespace AZ::SceneGenerationComponents
{
const AZStd::string optimizedName {graph.GetNodeName(childNodeIndex).GetName(), graph.GetNodeName(childNodeIndex).GetNameLength()};
const NodeIndex optimizedNodeIndex = graph.AddChild(optimizedMeshNodeIndex, optimizedName.c_str(), childNode);
if (graph.IsNodeEndPoint(nodeIndex))
if (graph.IsNodeEndPoint(childNodeIndex))
{
graph.MakeEndPoint(optimizedNodeIndex);
}
@@ -351,26 +372,27 @@ namespace AZ::SceneGenerationComponents
};
template<class MeshDataType>
AZStd::tuple<
AZStd::unique_ptr<AZ::SceneAPI::DataTypes::IMeshData>,
AZStd::unique_ptr<MeshDataType>,
AZStd::vector<AZStd::unique_ptr<MeshVertexUVData>>,
AZStd::vector<AZStd::unique_ptr<MeshVertexTangentData>>,
AZStd::vector<AZStd::unique_ptr<MeshVertexBitangentData>>,
AZStd::vector<AZStd::unique_ptr<MeshVertexColorData>>,
AZStd::unique_ptr<AZ::SceneAPI::DataTypes::ISkinWeightData>
> MeshOptimizerComponent::OptimizeMesh(
const IMeshData* meshData,
const MeshDataType* meshData,
const AZStd::vector<AZStd::reference_wrapper<const IMeshVertexUVData>>& uvs,
const AZStd::vector<AZStd::reference_wrapper<const IMeshVertexTangentData>>& tangents,
const AZStd::vector<AZStd::reference_wrapper<const IMeshVertexBitangentData>>& bitangents,
const AZStd::vector<AZStd::reference_wrapper<const IMeshVertexColorData>>& vertexColors,
const AZStd::vector<AZStd::reference_wrapper<const ISkinWeightData>>& skinWeights,
const AZ::SceneAPI::DataTypes::IMeshGroup& /*meshGroup*/,
const bool hasBlendShapes)
const AZ::SceneAPI::DataTypes::IMeshGroup& meshGroup,
bool hasBlendShapes)
{
const size_t vertexCount = meshData->GetUsedControlPointCount();
AZ::MeshBuilder::MeshBuilder meshBuilder(vertexCount, AZStd::numeric_limits<size_t>::max(), AZStd::numeric_limits<size_t>::max(), /*optimizeDuplicates=*/ hasBlendShapes);
AZ::MeshBuilder::MeshBuilder meshBuilder(vertexCount, AZStd::numeric_limits<size_t>::max(), AZStd::numeric_limits<size_t>::max(), /*optimizeDuplicates=*/ !hasBlendShapes);
// Make the layers to hold the vertex data
auto* orgVtxLayer = meshBuilder.AddLayer<MeshBuilder::MeshBuilderVertexAttributeLayerUInt32>(vertexCount);
@@ -409,15 +431,16 @@ namespace AZ::SceneGenerationComponents
const AZStd::vector<MeshBuilder::MeshBuilderVertexAttributeLayerVector3*> bitangentLayers = makeLayersForData(bitangents);
const AZStd::vector<MeshBuilder::MeshBuilderVertexAttributeLayerColor*> vertexColorLayers = makeLayersForData(vertexColors);
const AZ::u32 maxWeightsPerVertex = 4;
const float weightThreshold = 0.001f;
const auto* skinRule = meshGroup.GetRuleContainerConst().FindFirstByType<SceneAPI::DataTypes::ISkinRule>().get();
const AZ::u32 maxWeightsPerVertex = skinRule ? skinRule->GetMaxWeightsPerVertex() : 4;
const float weightThreshold = skinRule ? skinRule->GetWeightThreshold() : 0.001f;
meshBuilder.SetSkinningInfo(ExtractSkinningInfo(meshData, skinWeights, maxWeightsPerVertex, weightThreshold));
// Add the vertex data to all the layers
const AZ::u32 faceCount = meshData->GetFaceCount();
for (AZ::u32 faceIndex = 0; faceIndex < faceCount; ++faceIndex)
{
meshBuilder.BeginPolygon(meshData->GetFaceMaterialId(faceIndex));
meshBuilder.BeginPolygon(GetFaceMaterialId(meshData, faceIndex));
for (const AZ::u32 vertexIndex : meshData->GetFaceInfo(faceIndex).vertexIndex)
{
const int orgVertexNumber = meshData->GetUsedPointIndexForControlPoint(meshData->GetControlPointIndex(vertexIndex));
@@ -451,20 +474,39 @@ namespace AZ::SceneGenerationComponents
meshBuilder.EndPolygon();
}
meshBuilder.OptimizeTriangleList();
meshBuilder.GenerateSubMeshVertexOrders();
// Create the resulting nodes
auto optimizedMesh = AZStd::make_unique<MeshData>();
optimizedMesh->SetUnitSizeInMeters(meshData->GetUnitSizeInMeters());
optimizedMesh->SetOriginalUnitSizeInMeters(meshData->GetOriginalUnitSizeInMeters());
struct ResultingType
{
// When this method is called with an IMeshData node, it is generating a MeshData node. When called on an
// IBlendShapeData node, it is generating a BlendShapeData node.
static constexpr auto type(const IMeshData*) -> MeshData;
static constexpr auto type(const IBlendShapeData*) -> BlendShapeData;
};
auto optimizedMesh = AZStd::make_unique<decltype(ResultingType::type(meshData))>();
optimizedMesh->CloneAttributesFrom(meshData);
AZStd::vector<AZStd::unique_ptr<MeshVertexUVData>> optimizedUVs = makeSceneGraphNodesForMeshBuilderLayers<MeshVertexUVData>(uvLayers);
AZStd::vector<AZStd::unique_ptr<MeshVertexTangentData>> optimizedTangents = makeSceneGraphNodesForMeshBuilderLayers<MeshVertexTangentData>(tangentLayers);
AZStd::vector<AZStd::unique_ptr<MeshVertexBitangentData>> optimizedBitangents = makeSceneGraphNodesForMeshBuilderLayers<MeshVertexBitangentData>(bitangentLayers);
AZStd::vector<AZStd::unique_ptr<MeshVertexColorData>> optimizedVertexColors = makeSceneGraphNodesForMeshBuilderLayers<MeshVertexColorData>(vertexColorLayers);
auto optimizedSkinWeights = AZStd::make_unique<SkinWeightData>();
// Copy node attributes
AZStd::apply([](const auto&&... nodePairView) {
((AZStd::for_each(begin(nodePairView), end(nodePairView), [](const auto& nodePair) {
auto& [originalNode, optimizedNode] = nodePair;
optimizedNode->CloneAttributesFrom(&originalNode.get());
})), ...);
}, std::tuple {
Views::MakePairView(uvs, optimizedUVs),
Views::MakePairView(tangents, optimizedTangents),
Views::MakePairView(bitangents, optimizedBitangents),
Views::MakePairView(vertexColors, optimizedVertexColors),
});
unsigned int indexOffset = 0;
for (size_t subMeshIndex = 0; subMeshIndex < meshBuilder.GetNumSubMeshes(); ++subMeshIndex)
{
const AZ::MeshBuilder::MeshBuilderSubMesh* subMesh = meshBuilder.GetSubMesh(subMeshIndex);
@@ -474,7 +516,7 @@ namespace AZ::SceneGenerationComponents
optimizedMesh->AddPosition(posLayer->GetVertexValue(vertexLookup.mOrgVtx, vertexLookup.mDuplicateNr));
optimizedMesh->AddNormal(normalsLayer->GetVertexValue(vertexLookup.mOrgVtx, vertexLookup.mDuplicateNr));
optimizedMesh->SetVertexIndexToControlPointIndexMap(
aznumeric_caster(optimizedMesh->GetVertexCount()),
aznumeric_caster(optimizedMesh->GetVertexCount() - 1),
orgVtxLayer->GetVertexValue(vertexLookup.mOrgVtx, vertexLookup.mDuplicateNr)
);
@@ -495,16 +537,39 @@ namespace AZ::SceneGenerationComponents
optimizedVertexColorNode->AppendColor(vertexColorLayer->GetVertexValue(vertexLookup.mOrgVtx, vertexLookup.mDuplicateNr));
}
}
AZStd::unordered_set<size_t> usedIndexes;
for (size_t polygonIndex = 0; polygonIndex < subMesh->GetNumPolygons(); ++polygonIndex)
{
optimizedMesh->AddFace(
{
aznumeric_caster(subMesh->GetIndex(polygonIndex * 3 + 0)),
aznumeric_caster(subMesh->GetIndex(polygonIndex * 3 + 1)),
aznumeric_caster(subMesh->GetIndex(polygonIndex * 3 + 2)),
},
AddFace(
optimizedMesh.get(),
aznumeric_caster(indexOffset + subMesh->GetIndex(polygonIndex * 3 + 0)),
aznumeric_caster(indexOffset + subMesh->GetIndex(polygonIndex * 3 + 1)),
aznumeric_caster(indexOffset + subMesh->GetIndex(polygonIndex * 3 + 2)),
aznumeric_caster(subMesh->GetMaterialIndex())
);
const auto& faceInfo = optimizedMesh->GetFaceInfo(optimizedMesh->GetFaceCount() - 1);
AZStd::copy(AZStd::begin(faceInfo.vertexIndex), AZStd::end(faceInfo.vertexIndex), AZStd::inserter(usedIndexes, usedIndexes.begin()));
}
indexOffset += usedIndexes.size();
}
AZStd::unique_ptr<SkinWeightData> optimizedSkinWeights;
if (MeshBuilder::MeshBuilderSkinningInfo* skinningInfo = meshBuilder.GetSkinningInfo())
{
optimizedSkinWeights = AZStd::make_unique<SkinWeightData>();
const size_t skinnedVertexCount = skinningInfo->GetNumOrgVertices();
optimizedSkinWeights->ResizeContainerSpace(skinnedVertexCount);
for (size_t vertex = 0; vertex < skinnedVertexCount; ++vertex)
{
const size_t boneCountAffectingThisVertex = skinningInfo->GetNumInfluences(vertex);
for (size_t influencingBone = 0; influencingBone < boneCountAffectingThisVertex; ++influencingBone)
{
const MeshBuilder::MeshBuilderSkinningInfo::Influence& influence = skinningInfo->GetInfluence(vertex, influencingBone);
const int boneId = optimizedSkinWeights->GetBoneId(skinWeights[0].get().GetBoneName(aznumeric_caster(influence.mNodeNr)));
optimizedSkinWeights->AppendLink(vertex, {boneId, influence.mWeight});
}
}
}
@@ -517,4 +582,22 @@ namespace AZ::SceneGenerationComponents
AZStd::move(optimizedSkinWeights)
);
}
unsigned int MeshOptimizerComponent::GetFaceMaterialId([[maybe_unused]] const AZ::SceneAPI::DataTypes::IBlendShapeData* meshData, [[maybe_unused]] unsigned int index)
{
return 0;
}
unsigned int MeshOptimizerComponent::GetFaceMaterialId(const AZ::SceneAPI::DataTypes::IMeshData* meshData, unsigned int index)
{
return meshData->GetFaceMaterialId(index);
}
void MeshOptimizerComponent::AddFace(AZ::SceneData::GraphData::BlendShapeData* blendShape, unsigned int index1, unsigned int index2, unsigned int index3, [[maybe_unused]] unsigned int faceMaterialId)
{
blendShape->AddFace({index1, index2, index3});
}
void MeshOptimizerComponent::AddFace(AZ::SceneData::GraphData::MeshData* mesh, unsigned int index1, unsigned int index2, unsigned int index3, unsigned int faceMaterialId)
{
mesh->AddFace({index1, index2, index3}, faceMaterialId);
}
} // namespace AZ::SceneGenerationComponents
@@ -22,6 +22,7 @@
#include <SceneAPI/SceneCore/Events/ProcessingResult.h>
namespace AZ { class ReflectContext; }
namespace AZ::SceneAPI::DataTypes { class IBlendShapeData; }
namespace AZ::SceneAPI::DataTypes { class IMeshData; }
namespace AZ::SceneAPI::DataTypes { class IMeshGroup; }
namespace AZ::SceneAPI::DataTypes { class IMeshVertexUVData; }
@@ -30,6 +31,8 @@ namespace AZ::SceneAPI::DataTypes { class IMeshVertexBitangentData; }
namespace AZ::SceneAPI::DataTypes { class ISkinWeightData; }
namespace AZ::SceneAPI::DataTypes { class IMeshVertexColorData; }
namespace AZ::SceneAPI::Events { class GenerateSimplificationEventContext; }
namespace AZ::SceneData::GraphData { class BlendShapeData; }
namespace AZ::SceneData::GraphData { class MeshData; }
namespace AZ::SceneData::GraphData { class MeshVertexBitangentData; }
namespace AZ::SceneData::GraphData { class MeshVertexColorData; }
namespace AZ::SceneData::GraphData { class MeshVertexTangentData; }
@@ -53,15 +56,16 @@ namespace AZ::SceneGenerationComponents
static bool HasAnyBlendShapeChild(const AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex);
private:
template<class MeshDataType>
static AZStd::tuple<
AZStd::unique_ptr<AZ::SceneAPI::DataTypes::IMeshData>,
AZStd::unique_ptr<MeshDataType>,
AZStd::vector<AZStd::unique_ptr<AZ::SceneData::GraphData::MeshVertexUVData>>,
AZStd::vector<AZStd::unique_ptr<AZ::SceneData::GraphData::MeshVertexTangentData>>,
AZStd::vector<AZStd::unique_ptr<AZ::SceneData::GraphData::MeshVertexBitangentData>>,
AZStd::vector<AZStd::unique_ptr<AZ::SceneData::GraphData::MeshVertexColorData>>,
AZStd::unique_ptr<AZ::SceneAPI::DataTypes::ISkinWeightData>
> OptimizeMesh(
const AZ::SceneAPI::DataTypes::IMeshData* meshData,
const MeshDataType* meshData,
const AZStd::vector<AZStd::reference_wrapper<const AZ::SceneAPI::DataTypes::IMeshVertexUVData>>& uvs,
const AZStd::vector<AZStd::reference_wrapper<const AZ::SceneAPI::DataTypes::IMeshVertexTangentData>>& tangents,
const AZStd::vector<AZStd::reference_wrapper<const AZ::SceneAPI::DataTypes::IMeshVertexBitangentData>>& bitangents,
@@ -69,5 +73,11 @@ namespace AZ::SceneGenerationComponents
const AZStd::vector<AZStd::reference_wrapper<const AZ::SceneAPI::DataTypes::ISkinWeightData>>& skinWeights,
const AZ::SceneAPI::DataTypes::IMeshGroup& meshGroup,
bool hasBlendShapes);
static unsigned int GetFaceMaterialId(const AZ::SceneAPI::DataTypes::IBlendShapeData* meshData, unsigned int index);
static unsigned int GetFaceMaterialId(const AZ::SceneAPI::DataTypes::IMeshData* meshData, unsigned int index);
static void AddFace(AZ::SceneData::GraphData::BlendShapeData* blendShape, unsigned int index1, unsigned int index2, unsigned int index3, unsigned int faceMaterialId);
static void AddFace(AZ::SceneData::GraphData::MeshData* mesh, unsigned int index1, unsigned int index2, unsigned int index3, unsigned int faceMaterialId);
};
} // namespace AZ::SceneGenerationComponents