Integrating github/staging through commit ab87ed9
This commit is contained in:
+53
-93
@@ -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
-40
@@ -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)
|
||||
|
||||
+18
-14
@@ -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
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+107
-24
@@ -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
|
||||
|
||||
+12
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user