Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <RC/ResourceCompilerScene/Common/AssetExportUtilities.h>
namespace AZ
{
namespace RC
{
Matrix34 AssetExportUtilities::ConvertToCryMatrix34(const SceneAPI::DataTypes::MatrixType& transform)
{
Matrix34 matrix;
matrix.m00 = transform.GetColumn(0).GetX();
matrix.m10 = transform.GetColumn(0).GetY();
matrix.m20 = transform.GetColumn(0).GetZ();
matrix.m01 = transform.GetColumn(1).GetX();
matrix.m11 = transform.GetColumn(1).GetY();
matrix.m21 = transform.GetColumn(1).GetZ();
matrix.m02 = transform.GetColumn(2).GetX();
matrix.m12 = transform.GetColumn(2).GetY();
matrix.m22 = transform.GetColumn(2).GetZ();
matrix.m03 = transform.GetColumn(3).GetX();
matrix.m13 = transform.GetColumn(3).GetY();
matrix.m23 = transform.GetColumn(3).GetZ();
return matrix;
}
float AssetExportUtilities::CryQuatDotProd(const CryQuat& q, const CryQuat& p)
{
return q.w*p.w + q.v*p.v;
}
}
}
@@ -0,0 +1,29 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Math.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
namespace RC
{
class AssetExportUtilities
{
public:
static Matrix34 ConvertToCryMatrix34(const SceneAPI::DataTypes::MatrixType& transform);
static float CryQuatDotProd(const CryQuat& q, const CryQuat& p);
};
}
}
@@ -0,0 +1,136 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h>
#include <CGFContent.h>
#include <IIndexedMesh.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/algorithm.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBlendShapeData.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IBlendShapeRule.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/BlendShapeExporter.h>
namespace AZ
{
namespace RC
{
BlendShapeExporter::BlendShapeExporter()
{
BindToCall(&BlendShapeExporter::ProcessBlendShapes);
}
void BlendShapeExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<BlendShapeExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneAPI::Events::ProcessingResult BlendShapeExporter::ProcessBlendShapes(MeshNodeExportContext& context)
{
if (context.m_phase != Phase::Filling)
{
return SceneAPI::Events::ProcessingResult::Ignored;
}
if (!context.m_group.RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::ISkinGroup::TYPEINFO_Uuid()))
{
return SceneAPI::Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<const AZ::SceneAPI::DataTypes::IBlendShapeRule> blendShapeRule = context.m_group.GetRuleContainerConst().FindFirstByType<AZ::SceneAPI::DataTypes::IBlendShapeRule>();
if (!blendShapeRule)
{
return SceneAPI::Events::ProcessingResult::Ignored;
}
const SceneAPI::Containers::SceneGraph& graph = context.m_scene.GetGraph();
CSkinningInfo* skinInfo = context.m_container.GetSkinningInfo();
for (size_t index = 0; index < blendShapeRule->GetSceneNodeSelectionList().GetSelectedNodeCount(); ++index)
{
SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex = graph.Find(blendShapeRule->GetSceneNodeSelectionList().GetSelectedNode(index));
if (!nodeIndex.IsValid())
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Invalid name %s for blend shape.", blendShapeRule->GetSceneNodeSelectionList().GetSelectedNode(index).c_str());
return SceneAPI::Events::ProcessingResult::Failure;
}
AZStd::shared_ptr<const SceneAPI::DataTypes::IBlendShapeData> blendShape =
azrtti_cast<const SceneAPI::DataTypes::IBlendShapeData*>(graph.GetNodeContent(nodeIndex));
if (!blendShape)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unable to find blend shape.");
return SceneAPI::Events::ProcessingResult::Failure;
}
SceneAPI::DataTypes::MatrixType skinTransform = SceneAPI::DataTypes::MatrixType::Identity();
//Check to see if the blend shape parent skin has a transform an propagate that transform onto the vertices.
auto view = MakeSceneGraphChildView(graph, graph.GetNodeParent(nodeIndex), graph.GetContentStorage().begin(), true);
auto transform = AZStd::find_if(view.begin(), view.end(), SceneAPI::Containers::DerivedTypeFilter<SceneAPI::DataTypes::ITransform>());
if (transform != view.end())
{
skinTransform = azrtti_cast<const SceneAPI::DataTypes::ITransform*>(*transform)->GetMatrix();
}
MorphTargets* target = new MorphTargets();
target->MeshID = -1; //Based on the collada importer there's not a great way to set this.
target->m_strName = string(graph.GetNodeName(nodeIndex).GetName());
const size_t controlPointCount = blendShape->GetUsedControlPointCount();
for (size_t controlPointIndex = 0; controlPointIndex < controlPointCount; ++controlPointIndex)
{
SMeshMorphTargetVertex vert;
vert.nVertexId = controlPointIndex;
AZ::Vector3 vtx = blendShape->GetPosition(blendShape->GetUsedPointIndexForControlPoint(controlPointIndex));
//Apply base skin transform if one exists.
vtx = skinTransform * vtx;
vert.ptVertex = Vec3(vtx.GetX(), vtx.GetY(), vtx.GetZ());
target->m_arrIntMorph.push_back(vert);
}
skinInfo->m_arrMorphTargets.push_back(target);
}
return SceneAPI::Events::ProcessingResult::Success;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
namespace AZ
{
namespace RC
{
struct MeshNodeExportContext;
class BlendShapeExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(BlendShapeExporter, "{1A27BF62-F684-4F9E-B2C6-B15E728659EA}", SceneAPI::SceneCore::RCExportingComponent);
BlendShapeExporter();
~BlendShapeExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ProcessBlendShapes(MeshNodeExportContext& context);
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,111 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for IIndexedMesh.h
#include <IIndexedMesh.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMeshAdvancedRule.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexColorData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/ColorStreamExporter.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneUtilities = AZ::SceneAPI::Utilities;
ColorStreamExporter::ColorStreamExporter()
{
BindToCall(&ColorStreamExporter::CopyVertexColorStream);
}
void ColorStreamExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ColorStreamExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult ColorStreamExporter::CopyVertexColorStream(MeshNodeExportContext& context) const
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
const SceneDataTypes::IGroup& group = context.m_group;
AZStd::shared_ptr<const SceneDataTypes::IMeshVertexColorData> colors = nullptr;
AZStd::string streamName;
AZStd::shared_ptr<const SceneDataTypes::IMeshAdvancedRule> rule = group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::IMeshAdvancedRule>();
if (!rule || rule->IsVertexColorStreamDisabled() || rule->GetVertexColorStreamName().empty())
{
return SceneEvents::ProcessingResult::Ignored;
}
AZ_TraceContext("Vertex color stream", rule->GetVertexColorStreamName());
SceneContainers::SceneGraph::NodeIndex index = graph.Find(context.m_nodeIndex, rule->GetVertexColorStreamName());
colors = azrtti_cast<const SceneDataTypes::IMeshVertexColorData*>(graph.GetNodeContent(index));
if (colors)
{
bool countMatch = context.m_mesh.GetVertexCount() == colors->GetCount();
if (!countMatch)
{
AZ_TracePrintf(SceneUtilities::ErrorWindow,
"Number of vertices in the mesh (%i) don't match with the number of stored vertex color stream (%i).",
context.m_mesh.GetVertexCount(), colors->GetCount());
return SceneEvents::ProcessingResult::Failure;
}
// Vertex coloring always uses the first vertex color stream.
context.m_mesh.ReallocStream(CMesh::COLORS, 0, context.m_mesh.GetVertexCount());
for (int i = 0; i < context.m_mesh.GetVertexCount(); ++i)
{
const SceneDataTypes::Color& color = colors->GetColor(i);
context.m_mesh.m_pColor0[i] = SMeshColor(
static_cast<uint8_t>(GetClamp<float>(color.red, 0.0f, 1.0f) * 255.0f),
static_cast<uint8_t>(GetClamp<float>(color.green, 0.0f, 1.0f) * 255.0f),
static_cast<uint8_t>(GetClamp<float>(color.blue, 0.0f, 1.0f) * 255.0f),
static_cast<uint8_t>(GetClamp<float>(color.alpha, 0.0f, 1.0f) * 255.0f));
}
}
else
{
AZ_TracePrintf(SceneUtilities::WarningWindow, "Vertex color stream not found or name doesn't refer to a vertex color stream.");
context.m_mesh.ReallocStream(CMesh::COLORS, 0, context.m_mesh.GetVertexCount());
for (int i = 0; i < context.m_mesh.GetVertexCount(); ++i)
{
context.m_mesh.m_pColor0[i] = SMeshColor(255, 255, 255, 255);
}
}
return SceneEvents::ProcessingResult::Success;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
namespace AZ
{
namespace RC
{
struct MeshNodeExportContext;
class ColorStreamExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(ColorStreamExporter, "{912F9D7B-55C1-4871-A3BE-6C63B27E6B49}", SceneAPI::SceneCore::RCExportingComponent);
ColorStreamExporter();
~ColorStreamExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult CopyVertexColorStream(MeshNodeExportContext& context) const;
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,160 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISceneNodeGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IAnimationGroup.h>
namespace AZ
{
namespace RC
{
ContainerExportContext::ContainerExportContext(SceneAPI::Events::ExportEventContext& parent,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, Phase phase)
: m_scene(parent.GetScene())
, m_outputDirectory(parent.GetOutputDirectory())
, m_group(group)
, m_container(container)
, m_phase(phase)
{
}
ContainerExportContext::ContainerExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, Phase phase)
: m_scene(scene)
, m_outputDirectory(outputDirectory)
, m_group(group)
, m_container(container)
, m_phase(phase)
{
}
ContainerExportContext::ContainerExportContext(const ContainerExportContext& copyContext, Phase phase)
: m_scene(copyContext.m_scene)
, m_outputDirectory(copyContext.m_outputDirectory)
, m_group(copyContext.m_group)
, m_container(copyContext.m_container)
, m_phase(phase)
{
}
NodeExportContext::NodeExportContext(ContainerExportContext& parent, CNodeCGF& node, const AZStd::string& nodeName,
SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex, EPhysicsGeomType physicalizeType, AZStd::string& rootBoneName, Phase phase)
: ContainerExportContext(parent, phase)
, m_node(node)
, m_nodeName(nodeName)
, m_nodeIndex(nodeIndex)
, m_physicalizeType(physicalizeType)
, m_rootBoneName(rootBoneName)
{
}
NodeExportContext::NodeExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, CNodeCGF& node,
const AZStd::string& nodeName, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex, EPhysicsGeomType physicalizeType,
AZStd::string& rootBoneName, Phase phase)
: ContainerExportContext(scene, outputDirectory, group, container, phase)
, m_node(node)
, m_nodeName(nodeName)
, m_nodeIndex(nodeIndex)
, m_physicalizeType(physicalizeType)
, m_rootBoneName(rootBoneName)
{
}
NodeExportContext::NodeExportContext(const NodeExportContext& copyContext, Phase phase)
: ContainerExportContext(copyContext, phase)
, m_node(copyContext.m_node)
, m_nodeName(copyContext.m_nodeName)
, m_nodeIndex(copyContext.m_nodeIndex)
, m_physicalizeType(copyContext.m_physicalizeType)
, m_rootBoneName(copyContext.m_rootBoneName)
{
}
MeshNodeExportContext::MeshNodeExportContext(NodeExportContext& parent, CMesh& mesh, Phase phase)
: NodeExportContext(parent, phase)
, m_mesh(mesh)
{
}
MeshNodeExportContext::MeshNodeExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, CNodeCGF& node,
const AZStd::string& nodeName, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex, EPhysicsGeomType physicalizeType,
AZStd::string& rootBoneName, CMesh& mesh, Phase phase)
: NodeExportContext(scene, outputDirectory, group, container, node, nodeName, nodeIndex, physicalizeType, rootBoneName, phase)
, m_mesh(mesh)
{
}
MeshNodeExportContext::MeshNodeExportContext(const MeshNodeExportContext& copyContext, Phase phase)
: NodeExportContext(copyContext, phase)
, m_mesh(copyContext.m_mesh)
{
}
TouchBendableMeshNodeExportContext::TouchBendableMeshNodeExportContext(const MeshNodeExportContext& copyContext, AZStd::string& rootBoneName, Phase phase)
: MeshNodeExportContext(copyContext, phase)
{
m_rootBoneName = rootBoneName;
}
ResolveRootBoneFromNodeContext::ResolveRootBoneFromNodeContext(
AZStd::string& result, const SceneAPI::Containers::Scene& scene, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex)
: m_scene(scene)
, m_rootBoneName(result)
, m_nodeIndex(nodeIndex)
{
}
ResolveRootBoneFromBoneContext::ResolveRootBoneFromBoneContext(
AZStd::string& result, const SceneAPI::Containers::Scene& scene, const AZStd::string& boneName)
: m_scene(scene)
, m_boneName(boneName)
, m_rootBoneName(result)
{
}
AddBonesToSkinningInfoContext::AddBonesToSkinningInfoContext(
CSkinningInfo& skinningInfo, const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName)
: m_scene(scene)
, m_rootBoneName(rootBoneName)
, m_skinningInfo(skinningInfo)
{
}
BuildBoneMapContext::BuildBoneMapContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName,
AZStd::unordered_map<AZStd::string, int>& boneNameIdMap)
: m_scene(scene)
, m_rootBoneName(rootBoneName)
, m_boneNameIdMap(boneNameIdMap)
{
}
SkeletonExportContext::SkeletonExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName, CSkinningInfo& skinningInfo,
[[maybe_unused]] AZStd::unordered_map<AZStd::string, int>& boneNameIdMap, Phase phase)
: m_scene(scene)
, m_rootBoneName(rootBoneName)
, m_skinningInfo(skinningInfo)
, m_phase(phase)
{
}
SkeletonExportContext::SkeletonExportContext(const SkeletonExportContext& copyContext, Phase phase)
: m_scene(copyContext.m_scene)
, m_rootBoneName(copyContext.m_rootBoneName)
, m_skinningInfo(copyContext.m_skinningInfo)
, m_phase(phase)
{
}
} // RC
} // AZ
@@ -0,0 +1,195 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
#include <SceneAPI/SceneCore/Events/ExportEventContext.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IAnimationGroup.h>
#include <RC/ResourceCompilerScene/Common/ExportContextGlobal.h>
#include <CryHeaders.h>
class CContentCGF;
struct CNodeCGF;
class CMesh;
struct CSkinningInfo;
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class IGroup;
class ISceneNodeSelectionList;
}
}
namespace RC
{
// Called while creating, filling and finalizing a CContentCGF container.
struct ContainerExportContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(ContainerExportContext, "{667A9E60-F3AA-45E1-8E66-05B0C971A094}", SceneAPI::Events::ICallContext);
ContainerExportContext(SceneAPI::Events::ExportEventContext& parent,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, Phase phase);
ContainerExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, Phase phase);
ContainerExportContext(const ContainerExportContext& copyContext, Phase phase);
ContainerExportContext(const ContainerExportContext& copyContext) = delete;
~ContainerExportContext() override = default;
ContainerExportContext& operator=(const ContainerExportContext& other) = delete;
const SceneAPI::Containers::Scene& m_scene;
const AZStd::string& m_outputDirectory;
const SceneAPI::DataTypes::IGroup& m_group;
CContentCGF& m_container;
const Phase m_phase;
};
// Called when a new CNode is added to a CContentCGF container.
struct NodeExportContext
: public ContainerExportContext
{
AZ_RTTI(NodeExportContext, "{A7D130C6-2CB2-47AC-9D9C-969FA473DFDA}", ContainerExportContext);
NodeExportContext(ContainerExportContext& parent, CNodeCGF& node, const AZStd::string& nodeName,
SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex, EPhysicsGeomType physicalizeType, AZStd::string& rootBoneName, Phase phase);
NodeExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group,
CContentCGF& container, CNodeCGF& node, const AZStd::string& nodeName, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex,
EPhysicsGeomType physicalizeType, AZStd::string& rootBoneName, Phase phase);
NodeExportContext(const NodeExportContext& copyContext, Phase phase);
NodeExportContext(const NodeExportContext& copyContext) = delete;
~NodeExportContext() override = default;
NodeExportContext& operator=(const NodeExportContext& other) = delete;
CNodeCGF& m_node;
const AZStd::string& m_nodeName;
SceneAPI::Containers::SceneGraph::NodeIndex m_nodeIndex;
EPhysicsGeomType m_physicalizeType;
AZStd::string& m_rootBoneName;
};
// Called when new mesh data was added to a CNode in a CContentCGF container.
struct MeshNodeExportContext
: public NodeExportContext
{
AZ_RTTI(MeshNodeExportContext, "{D39D08D6-8EB5-4058-B9D7-BED4EB460555}", NodeExportContext);
MeshNodeExportContext(NodeExportContext& parent, CMesh& mesh, Phase phase);
MeshNodeExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& outputDirectory,
const SceneAPI::DataTypes::IGroup& group, CContentCGF& container, CNodeCGF& node,
const AZStd::string& nodeName, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex, EPhysicsGeomType physicalizeType,
AZStd::string& rootBoneName, CMesh& mesh, Phase phase);
MeshNodeExportContext(const MeshNodeExportContext& copyContext, Phase phase);
MeshNodeExportContext(const MeshNodeExportContext& copyContext) = delete;
~MeshNodeExportContext() override = default;
MeshNodeExportContext& operator=(const MeshNodeExportContext& other) = delete;
CMesh& m_mesh;
};
struct TouchBendableMeshNodeExportContext
: public MeshNodeExportContext
{
AZ_RTTI(TouchBendableMeshNodeExportContext, "{A3370E01-EF04-4F5A-95F3-5B9ADFEFD2F0}", MeshNodeExportContext);
TouchBendableMeshNodeExportContext(const MeshNodeExportContext& copyContext, AZStd::string& rootBoneName, Phase phase);
TouchBendableMeshNodeExportContext(const TouchBendableMeshNodeExportContext& copyContext) = delete;
~TouchBendableMeshNodeExportContext() override = default;
TouchBendableMeshNodeExportContext& operator=(const TouchBendableMeshNodeExportContext& other) = delete;
};
// Finds a root bone of the skeleton that is referenced by the given node.
struct ResolveRootBoneFromNodeContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(ResolveRootBoneFromNodeContext, "{7BA28E30-E313-4B55-8200-C3BDD4EEE240}", SceneAPI::Events::ICallContext);
ResolveRootBoneFromNodeContext(AZStd::string& result, const SceneAPI::Containers::Scene& scene, SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex);
~ResolveRootBoneFromNodeContext() override = default;
const SceneAPI::Containers::Scene& m_scene;
AZStd::string& m_rootBoneName;
SceneAPI::Containers::SceneGraph::NodeIndex m_nodeIndex;
};
// Finds a root bone of the skeleton that contains m_boneName. If the given bone name is not a fully specified
// path the graph will be searched for the node that's closest to the root that matches the name.
struct ResolveRootBoneFromBoneContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(ResolveRootBoneFromBoneContext, "{DCA7DE80-28D8-42B1-845D-2FD596E7B8D5}", SceneAPI::Events::ICallContext);
ResolveRootBoneFromBoneContext(AZStd::string& result, const SceneAPI::Containers::Scene& scene, const AZStd::string& boneName);
~ResolveRootBoneFromBoneContext() override = default;
const SceneAPI::Containers::Scene& m_scene;
const AZStd::string& m_boneName;
AZStd::string& m_rootBoneName;
};
struct AddBonesToSkinningInfoContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(AddBonesToSkinningInfoContext, "{18BFBCA3-DE2D-45BF-A776-E93A991C467E}", SceneAPI::Events::ICallContext);
AddBonesToSkinningInfoContext(CSkinningInfo& skinningInfo, const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName);
~AddBonesToSkinningInfoContext() override = default;
const SceneAPI::Containers::Scene& m_scene;
const AZStd::string& m_rootBoneName;
CSkinningInfo& m_skinningInfo;
};
struct BuildBoneMapContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(BuildBoneMapContext, "{9D9EE333-EC8C-4811-AB82-CC3B414E334C}", SceneAPI::Events::ICallContext);
BuildBoneMapContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName,
AZStd::unordered_map<AZStd::string, int>& boneNameIdMap);
~BuildBoneMapContext() override = default;
const SceneAPI::Containers::Scene& m_scene;
const AZStd::string& m_rootBoneName;
AZStd::unordered_map<AZStd::string, int>& m_boneNameIdMap;
};
struct SkeletonExportContext
: public SceneAPI::Events::ICallContext
{
AZ_RTTI(SkeletonExportContext, "{40512752-150F-4BAF-BC4E-01016DAE5088}", SceneAPI::Events::ICallContext);
SkeletonExportContext(const SceneAPI::Containers::Scene& scene, const AZStd::string& rootBoneName, CSkinningInfo& skinningInfo,
AZStd::unordered_map<AZStd::string, int>& boneNameIdMap, Phase phase);
SkeletonExportContext(const SkeletonExportContext& copyContext, Phase phase);
SkeletonExportContext(const SkeletonExportContext& copyContext) = delete;
~SkeletonExportContext() override = default;
SkeletonExportContext& operator=(const SkeletonExportContext& other) = delete;
const SceneAPI::Containers::Scene& m_scene;
const AZStd::string& m_rootBoneName;
CSkinningInfo& m_skinningInfo;
const Phase m_phase;
};
} // RC
} // AZ
@@ -0,0 +1,67 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for CGFContent.h
#include <CGFContent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMeshAdvancedRule.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/ContainerSettingsExporter.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
ContainerSettingsExporter::ContainerSettingsExporter()
{
BindToCall(&ContainerSettingsExporter::ProcessContext);
}
void ContainerSettingsExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ContainerSettingsExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult ContainerSettingsExporter::ProcessContext(ContainerExportContext& context) const
{
if (context.m_phase != Phase::Construction)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::shared_ptr<const SceneDataTypes::IMeshAdvancedRule> advancedRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::IMeshAdvancedRule>();
if (advancedRule)
{
context.m_container.GetExportInfo()->bWantF32Vertices = advancedRule->Use32bitVertices();
context.m_container.GetExportInfo()->bMergeAllNodes = advancedRule->MergeMeshes();
context.m_container.GetExportInfo()->bUseCustomNormals = advancedRule->UseCustomNormals();
return SceneEvents::ProcessingResult::Success;
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
} // RC
} // AZ
@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
namespace AZ
{
namespace RC
{
struct ContainerExportContext;
class ContainerSettingsExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(ContainerSettingsExporter, "{878C641C-6614-413A-A174-EDFF84D8B119}", SceneAPI::SceneCore::RCExportingComponent);
ContainerSettingsExporter();
~ContainerSettingsExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ProcessContext(ContainerExportContext& context) const;
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,26 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace RC
{
enum class Phase
{
Construction, // The target is created.
Filling, // Data is added to the target.
Finalizing // Work on the target has completed.
};
}
}
@@ -0,0 +1,370 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h>
#include <IIndexedMesh.h>
#include <CGFContent.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <GFxFramework/MaterialIO/Material.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMaterialRule.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMaterialData.h>
#include <SceneAPI/SceneCore/Utilities/FileUtilities.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Export/MtlMaterialExporter.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/MaterialExporter.h>
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneViews = AZ::SceneAPI::Containers::Views;
MaterialExporter::MaterialExporter()
: SceneAPI::SceneCore::RCExportingComponent()
, m_cachedGroup(nullptr)
, m_exportMaterial(true)
{
m_physMaterialNames[PHYS_GEOM_TYPE_DEFAULT_PROXY] = GFxFramework::MaterialExport::g_stringPhysicsNoDraw;
BindToCall(&MaterialExporter::ConfigureContainer);
BindToCall(&MaterialExporter::ProcessNode);
BindToCall(&MaterialExporter::PatchMesh);
}
void MaterialExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MaterialExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult MaterialExporter::ConfigureContainer(ContainerExportContext& context)
{
switch (context.m_phase)
{
case Phase::Construction:
{
if (!context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::IMaterialRule>())
{
m_exportMaterial = false;
AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "Skipping material processing due to material rule not being present.");
return SceneEvents::ProcessingResult::Ignored;
}
if (!LoadMaterialFile(context))
{
m_exportMaterial = false;
AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Unable to read MTL file for processing meshes.");
return SceneEvents::ProcessingResult::Failure;
}
m_cachedGroup = &(context.m_group);
SetupGlobalMaterial(context);
return SceneEvents::ProcessingResult::Success;
}
case Phase::Finalizing:
if (!m_exportMaterial)
{
Reset();
return SceneEvents::ProcessingResult::Ignored;
}
PatchSubmeshes(context);
CreateSubMaterials(context);
Reset();
return SceneEvents::ProcessingResult::Success;
default:
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult MaterialExporter::ProcessNode(NodeExportContext& context)
{
if (context.m_phase == Phase::Filling && m_exportMaterial)
{
AssignCommonMaterial(context);
return SceneEvents::ProcessingResult::Success;
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult MaterialExporter::PatchMesh(MeshNodeExportContext& context)
{
if (context.m_phase == Phase::Filling && m_exportMaterial)
{
return PatchMaterials(context);
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
bool MaterialExporter::LoadMaterialFile(ContainerExportContext& context)
{
// Load the material from the source first. If there's no source material a temporary material should have been
// created in the cache by the MaterialExporterComponent in SceneCore.
m_materialGroup = AZStd::make_shared<GFxFramework::MaterialGroup>();
bool fileRead = false;
AZStd::string materialPath = context.m_scene.GetSourceFilename();
AzFramework::StringFunc::Path::ReplaceExtension(materialPath, GFxFramework::MaterialExport::g_mtlExtension);
AZ_TraceContext("Material source file path", materialPath);
//get if we need to upate materials in source folder
const AZ::SceneAPI::Containers::RuleContainer& rules = context.m_group.GetRuleContainerConst();
AZStd::shared_ptr<const SceneDataTypes::IMaterialRule> materialRule = rules.FindFirstByType<SceneDataTypes::IMaterialRule>();
bool updateMaterials = materialRule->UpdateMaterials();
//if the source material exist and we won't need to update material later then we load the material from source folder
if (AZ::IO::SystemFile::Exists(materialPath.c_str()) && !updateMaterials)
{
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Using source material file for linking to meshes.");
fileRead = m_materialGroup->ReadMtlFile(materialPath.c_str());
}
else
{
materialPath = SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
context.m_scene.GetName(), context.m_outputDirectory, GFxFramework::MaterialExport::g_dccMaterialExtension);
AZ_TraceContext("Material cache file path", materialPath);
if (AZ::IO::SystemFile::Exists(materialPath.c_str()))
{
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Using cached material file for linking to meshes.");
fileRead = m_materialGroup->ReadMtlFile(materialPath.c_str());
}
}
if (!fileRead)
{
m_materialGroup.reset();
}
return fileRead;
}
void MaterialExporter::SetupGlobalMaterial(ContainerExportContext& context)
{
AZ_Assert(m_cachedGroup == &context.m_group, "ContainerExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
CMaterialCGF* rootMaterial = context.m_container.GetCommonMaterial();
if (!rootMaterial)
{
rootMaterial = new CMaterialCGF();
rootMaterial->nPhysicalizeType = PHYS_GEOM_TYPE_NONE;
azstrcpy(rootMaterial->name, sizeof(rootMaterial->name), context.m_scene.GetName().c_str());
context.m_container.SetCommonMaterial(rootMaterial);
}
}
void MaterialExporter::AssignCommonMaterial(NodeExportContext& context)
{
AZ_Assert(m_cachedGroup == &context.m_group, "MeshNodeExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
CMaterialCGF* rootMaterial = context.m_container.GetCommonMaterial();
AZ_Assert(rootMaterial, "Previously assigned root material has been deleted.");
context.m_node.pMaterial = rootMaterial;
}
SceneAPI::Events::ProcessingResult MaterialExporter::PatchMaterials(MeshNodeExportContext& context)
{
AZ_Assert(m_cachedGroup == &context.m_group, "MeshNodeExportContext doesn't belong to chain of previously\
called MeshGroupExportContext.");
AZStd::vector<size_t> relocationTable;
SceneEvents::ProcessingResult result = BuildRelocationTable(relocationTable, context);
if (result == SceneEvents::ProcessingResult::Failure)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Material mapping error, mesh generation failed. \
Change FBX Setting's \"Update Materials\" to true or modify the associated material file(.mtl) to fix the issue.");
return result;
}
if (relocationTable.empty())
{
// If the relocationTable is empty no materials were assigned to any of the
// selected meshes. In this case simply leave the subsets as assigned
// so users can later manually add materials if needed.
return SceneEvents::ProcessingResult::Ignored;
}
if (context.m_container.GetExportInfo()->bMergeAllNodes)
{
// Due to a bug which cases subsets to not merge correctly (see PatchSubmeshes for more details) use the global
// table so far to patch the subset index in the face info instead. This way they will be assigned to the
// eventual global subset stored in the first mesh.
int faceCount = context.m_mesh.GetFaceCount();
for (int i = 0; i < faceCount; ++i)
{
context.m_mesh.m_pFaces[i].nSubset = relocationTable[context.m_mesh.m_pFaces[i].nSubset];
}
}
else
{
for (SMeshSubset& subset : context.m_mesh.m_subsets)
{
subset.nMatID = relocationTable[subset.nMatID];
}
}
return SceneEvents::ProcessingResult::Success;
}
void MaterialExporter::PatchSubmeshes(ContainerExportContext& context)
{
// Due to a bug in the merging process of the Compiler it will always take the number of subsets of the first mesh
// it finds. This causes files with more materials than the first model to not merge properly and ultimately cause
// the entire export to fail. (See CGFNodeMerger::MergeNodes for more details.) The work-around for now is to fill
// the first mesh up with placeholder subsets and adjust the subset indices in the face info.
AZ_Assert(m_cachedGroup == &context.m_group, "ContainerExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
if (context.m_container.GetExportInfo()->bMergeAllNodes)
{
CMesh* firstMesh = nullptr;
int nodeCount = context.m_container.GetNodeCount();
for (int i = 0; i < nodeCount; ++i)
{
CNodeCGF* node = context.m_container.GetNode(i);
if (node->pMesh && !node->bPhysicsProxy && node->type == CNodeCGF::NODE_MESH)
{
firstMesh = node->pMesh;
break;
}
}
if (firstMesh)
{
int subsetCount = firstMesh->GetSubSetCount();
size_t materialCount = m_materialGroup->GetMaterialCount();
for (int i = 0; i < subsetCount; ++i)
{
AZ_Assert(firstMesh->m_subsets[i].nMatID == i, "Materials addition order broken. (%i vs. %i)", firstMesh->m_subsets[i].nMatID, i);
}
for (size_t i = subsetCount; i < materialCount; ++i)
{
SMeshSubset meshSubset;
meshSubset.nMatID = i;
firstMesh->m_subsets.push_back(meshSubset);
}
}
}
}
SceneAPI::Events::ProcessingResult MaterialExporter::BuildRelocationTable(AZStd::vector<size_t>& table, MeshNodeExportContext& context)
{
SceneEvents::ProcessingResultCombiner result;
auto physicalizeType = context.m_physicalizeType;
if ((physicalizeType == PHYS_GEOM_TYPE_DEFAULT_PROXY) || (physicalizeType == PHYS_GEOM_TYPE_NO_COLLIDE))
{
table.push_back(m_materialGroup->FindMaterialIndex(GFxFramework::MaterialExport::g_stringPhysicsNoDraw));
}
else
{
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
auto view = SceneViews::MakeSceneGraphChildView<SceneViews::AcceptEndPointsOnly>(
graph, context.m_nodeIndex, graph.GetContentStorage().begin(), true);
for (auto it = view.begin(); it != view.end(); ++it)
{
if ((*it) && (*it)->RTTI_IsTypeOf(SceneDataTypes::IMaterialData::TYPEINFO_Uuid()))
{
AZStd::string nodeName = graph.GetNodeName(graph.ConvertToNodeIndex(it.GetHierarchyIterator())).GetName();
size_t index = m_materialGroup->FindMaterialIndex(nodeName);
if (index == GFxFramework::MaterialExport::g_materialNotFound)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unable to find material named %s in mtl file while building FBX to Lumberyard material index table.", nodeName.c_str());
result += SceneEvents::ProcessingResult::Failure;
}
table.push_back(index);
}
}
}
return result.GetResult();
}
void MaterialExporter::CreateSubMaterials(ContainerExportContext& context)
{
AZ_Assert(m_cachedGroup == &context.m_group, "MeshNodeExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
CMaterialCGF* rootMaterial = context.m_container.GetCommonMaterial();
if (!rootMaterial)
{
AZ_Assert(rootMaterial, "Previously assigned root material has been deleted.");
return;
}
// Create sub-materials stored in root material. Sub-materials will be used to assign physical types
// to subsets stored in meshes when mesh gets compiled later on.
rootMaterial->subMaterials.resize(m_materialGroup->GetMaterialCount(), nullptr);
for (size_t i = 0; i < m_materialGroup->GetMaterialCount(); ++i)
{
CMaterialCGF* materialCGF = new CMaterialCGF();
AZStd::shared_ptr<const GFxFramework::IMaterial> material = m_materialGroup->GetMaterial(i);
if (material)
{
azstrncpy(materialCGF->name, sizeof(materialCGF->name), material->GetName().c_str(), sizeof(materialCGF->name));
int materialFlags = material->GetMaterialFlags();
//MTL_FLAG_NODRAW_TOUCHBENDING and MTL_FLAG_NODRAW are mutually exclusive.
const int errorMask = AZ::GFxFramework::EMaterialFlags::MTL_FLAG_NODRAW_TOUCHBENDING |
AZ::GFxFramework::EMaterialFlags::MTL_FLAG_NODRAW;
AZ_Assert((materialFlags & errorMask) != errorMask, "A physics material can not be NODRAW and NODRAW_TOUCHBENDING at the the same time.");
if (materialFlags & AZ::GFxFramework::EMaterialFlags::MTL_FLAG_NODRAW_TOUCHBENDING)
{
materialCGF->nPhysicalizeType = PHYS_GEOM_TYPE_NO_COLLIDE;
}
else if (materialFlags & AZ::GFxFramework::EMaterialFlags::MTL_FLAG_NODRAW)
{
materialCGF->nPhysicalizeType = PHYS_GEOM_TYPE_DEFAULT_PROXY;
}
else
{
materialCGF->nPhysicalizeType = PHYS_GEOM_TYPE_NONE;
}
rootMaterial->subMaterials[i] = materialCGF;
}
}
}
void MaterialExporter::Reset()
{
m_materialGroup = nullptr;
m_exportMaterial = true;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,68 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <GFxFramework/MaterialIO/IMaterial.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class IGroup;
}
}
namespace RC
{
struct ContainerExportContext;
struct NodeExportContext;
struct MeshNodeExportContext;
class MaterialExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(MaterialExporter, "{F82300E0-ABE7-49F2-8BFF-1BFBD8BF3288}", SceneAPI::SceneCore::RCExportingComponent);
MaterialExporter();
~MaterialExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ConfigureContainer(ContainerExportContext& context);
SceneAPI::Events::ProcessingResult ProcessNode(NodeExportContext& context);
SceneAPI::Events::ProcessingResult PatchMesh(MeshNodeExportContext& context);
protected:
bool LoadMaterialFile(ContainerExportContext& context);
void SetupGlobalMaterial(ContainerExportContext& context);
void CreateSubMaterials(ContainerExportContext& context);
void PatchSubmeshes(ContainerExportContext& context);
void AssignCommonMaterial(NodeExportContext& context);
SceneAPI::Events::ProcessingResult PatchMaterials(MeshNodeExportContext& context);
SceneAPI::Events::ProcessingResult BuildRelocationTable(AZStd::vector<size_t>& table, MeshNodeExportContext& context);
void Reset();
AZStd::shared_ptr<AZ::GFxFramework::IMaterialGroup> m_materialGroup;
AZStd::unordered_map<int, AZStd::string> m_physMaterialNames;
const SceneAPI::DataTypes::IGroup* m_cachedGroup;
bool m_exportMaterial;
};
} // RC
} // AZ
@@ -0,0 +1,191 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h>
#include <IIndexedMesh.h>
#include <CGFContent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <RC/ResourceCompilerScene/Common/MeshExporter.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
MeshExporter::MeshExporter()
{
BindToCall(&MeshExporter::ProcessMesh);
}
void MeshExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult MeshExporter::ProcessMesh(NodeExportContext& context) const
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
AZStd::shared_ptr<const SceneDataTypes::IMeshData> meshData =
azrtti_cast<const SceneDataTypes::IMeshData*>(graph.GetNodeContent(context.m_nodeIndex));
if (meshData)
{
SceneEvents::ProcessingResultCombiner result;
CMesh* mesh = new CMesh();
result += SceneEvents::Process<MeshNodeExportContext>(context, *mesh, Phase::Construction);
MeshNodeExportContext meshNodeContextFilling(context, *mesh, Phase::Filling);
SetMeshFaces(*meshData, *mesh, context.m_physicalizeType);
if (!SetMeshVertices(*meshData, *mesh))
{
return SceneEvents::ProcessingResult::Failure;
}
if (!SetMeshNormals(*meshData, *mesh))
{
return SceneEvents::ProcessingResult::Failure;
}
SetMeshTopologyIds(*meshData, *mesh, context);
context.m_node.type = CNodeCGF::NODE_MESH;
context.m_node.pMesh = mesh;
result += SceneEvents::Process(meshNodeContextFilling);
MeshNodeExportContext meshNodeContextFinalizing(context, *mesh, Phase::Finalizing);
context.m_container.GetExportInfo()->bNoMesh = false;
result += SceneEvents::Process(meshNodeContextFinalizing);
return result.GetResult();
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
void MeshExporter::SetMeshFaces(const SceneDataTypes::IMeshData& meshData, CMesh& mesh, EPhysicsGeomType physicalizeType) const
{
if (meshData.GetFaceCount() == 0)
{
AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "No mesh faces specified.");
return;
}
mesh.ReallocStream(CMesh::FACES, 0, meshData.GetFaceCount());
for (uint32_t i = 0; i < meshData.GetFaceCount(); ++i)
{
const SceneDataTypes::IMeshData::Face& face = meshData.GetFaceInfo(i);
mesh.m_pFaces[i].v[0] = face.vertexIndex[0];
mesh.m_pFaces[i].v[1] = face.vertexIndex[1];
mesh.m_pFaces[i].v[2] = face.vertexIndex[2];
// Create and use a unified subset if the mesh is chosen to be physicalized
if (physicalizeType == PHYS_GEOM_TYPE_DEFAULT_PROXY ||
physicalizeType == PHYS_GEOM_TYPE_OBSTRUCT ||
physicalizeType == PHYS_GEOM_TYPE_NO_COLLIDE)
{
mesh.m_pFaces[i].nSubset = 0;
if (mesh.m_subsets.empty())
{
SMeshSubset meshSubset;
meshSubset.nMatID = 0;
mesh.m_subsets.push_back(meshSubset);
}
}
else
{
int materialIndex = meshData.GetFaceMaterialId(i);
mesh.m_pFaces[i].nSubset = materialIndex;
while (mesh.m_subsets.size() <= materialIndex)
{
SMeshSubset meshSubset;
meshSubset.nMatID = mesh.m_subsets.size();
mesh.m_subsets.push_back(meshSubset);
}
}
}
}
bool MeshExporter::SetMeshVertices(const SceneDataTypes::IMeshData& meshData, CMesh& mesh) const
{
mesh.ReallocStream(CMesh::POSITIONS, 0, meshData.GetVertexCount());
for (uint32_t i = 0; i < meshData.GetVertexCount(); ++i)
{
const Vector3& position = meshData.GetPosition(i);
if (!position.IsFinite())
{
AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Invalid vertex data detected at index %d", i);
return false;
}
mesh.m_pPositions[i] = Vec3(position.GetX(), position.GetY(), position.GetZ());
}
return true;
}
bool MeshExporter::SetMeshNormals(const SceneDataTypes::IMeshData& meshData, CMesh& mesh) const
{
// Mesh requires normals. If they're missing add a stream of default normals.
mesh.ReallocStream(CMesh::NORMALS, 0, meshData.GetVertexCount());
if (meshData.HasNormalData())
{
for (int i = 0; i < meshData.GetVertexCount(); ++i)
{
const Vector3& normal = meshData.GetNormal(i);
if (!normal.IsFinite())
{
AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Invalid normal data detected at index %d", i);
return false;
}
mesh.m_pNorms[i] = SMeshNormal(Vec3(normal.GetX(), normal.GetY(), normal.GetZ()));
}
}
else
{
AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "No mesh normals detected. Adding default normals.");
static const SMeshNormal defaultNormal(Vec3(1.0f, 0.0f, 0.0f));
for (int i = 0; i < meshData.GetVertexCount(); ++i)
{
mesh.m_pNorms[i] = defaultNormal;
}
}
return true;
}
void MeshExporter::SetMeshTopologyIds(const SceneAPI::DataTypes::IMeshData& meshData, CMesh& mesh, NodeExportContext& context) const
{
// Note, If this is a skin mesh create dummy topology id data even though it seems to be unnecessary data.
// Currently just provide it to prevent crash during skin mesh processing due to data misalignments.
if (context.m_group.RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::ISkinGroup::TYPEINFO_Uuid()))
{
mesh.ReallocStream(CMesh::TOPOLOGY_IDS, 0, meshData.GetVertexCount());
}
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,53 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <CryHeaders.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
class CMesh;
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class IMeshData;
}
}
namespace RC
{
struct NodeExportContext;
class MeshExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(MeshExporter, "{1F826DB8-D6B0-4392-90C8-8F6E63F649CA}", SceneAPI::SceneCore::RCExportingComponent);
MeshExporter();
~MeshExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ProcessMesh(NodeExportContext& context) const;
protected:
void SetMeshFaces(const SceneAPI::DataTypes::IMeshData& meshData, CMesh& mesh, EPhysicsGeomType physicalizeType) const;
bool SetMeshVertices(const SceneAPI::DataTypes::IMeshData& meshData, CMesh& mesh) const;
bool SetMeshNormals(const SceneAPI::DataTypes::IMeshData& meshData, CMesh& mesh) const;
void SetMeshTopologyIds(const SceneAPI::DataTypes::IMeshData& meshData, CMesh& mesh, NodeExportContext& context) const;
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,312 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for CGFContent.h
#include <CryCrc32.h>
#include <CGFContent.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/SkeletonExporter.h>
#include <RC/ResourceCompilerScene/Common/AssetExportUtilities.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneUtil = AZ::SceneAPI::Utilities;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
SkeletonExporter::SkeletonExporter()
{
BindToCall(&SkeletonExporter::ResolveRootBoneFromBone);
BindToCall(&SkeletonExporter::BuildBoneMap);
BindToCall(&SkeletonExporter::AddBonesToSkinningInfo);
BindToCall(&SkeletonExporter::ProcessSkeleton);
}
void SkeletonExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SkeletonExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneAPI::Events::ProcessingResult SkeletonExporter::ResolveRootBoneFromBone(ResolveRootBoneFromBoneContext& context)
{
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
const AZStd::string& boneName = context.m_boneName;
AZ_TraceContext("Bone name", boneName.c_str());
auto contentStorage = graph.GetContentStorage();
auto nameStorage = graph.GetNameStorage();
auto nameContentView = SceneContainers::Views::MakePairView(nameStorage, contentStorage);
// If the boneName is a full graph path, use that particular bone.
SceneContainers::SceneGraph::NodeIndex boneIndex = graph.Find(boneName);
if (!boneIndex.IsValid())
{
// If the the bone index is only the name, start looking for the first bone found with that name. The bone closest to
// the root of the graph is preferred.
auto graphDownwardsView = SceneContainers::Views::MakeSceneGraphDownwardsView<SceneContainers::Views::BreadthFirst>(
graph, graph.GetRoot(), nameContentView.begin(), true);
auto it = AZStd::find_if(graphDownwardsView.begin(), graphDownwardsView.end(),
[&boneName](const decltype(*nameContentView.begin())& entry) -> bool
{
if (!entry.second || !entry.second->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
return false;
}
return azstrnicmp(entry.first.GetName(), boneName.c_str(), entry.first.GetNameLength()) == 0;
});
if (it == graphDownwardsView.end())
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Unable to find the skeleton root bone for bone");
return SceneEvents::ProcessingResult::Failure;
}
boneIndex = graph.ConvertToNodeIndex(it.GetHierarchyIterator());
}
AZ_Assert(boneIndex.IsValid(), "A bone was found but the index for it's node is still invalid.");
// Now that the bone has been found, search upwards to find the root bone of the skeleton the bone belongs to.
auto graphUpwardsView = SceneContainers::Views::MakeSceneGraphUpwardsView(graph, boneIndex, nameContentView.begin(), true);
const char* rootBoneName = nullptr;
for (const auto& it : graphUpwardsView)
{
if (it.second && it.second->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
rootBoneName = it.first.GetPath();
}
else
{
break;
}
}
AZ_Assert(rootBoneName, "The name of the first bone should have been found.");
context.m_rootBoneName = rootBoneName;
return SceneEvents::ProcessingResult::Success;
}
SceneEvents::ProcessingResult SkeletonExporter::BuildBoneMap(BuildBoneMapContext& context)
{
return BuildBoneMap(context.m_boneNameIdMap, context.m_scene.GetGraph(), context.m_rootBoneName) ?
SceneEvents::ProcessingResult::Success : SceneEvents::ProcessingResult::Failure;
}
SceneEvents::ProcessingResult SkeletonExporter::AddBonesToSkinningInfo(AddBonesToSkinningInfoContext& context)
{
return AddBonesToSkinningInfo(context.m_skinningInfo, context.m_scene.GetGraph(), context.m_rootBoneName) ?
SceneEvents::ProcessingResult::Success : SceneEvents::ProcessingResult::Failure;
}
SceneEvents::ProcessingResult SkeletonExporter::ProcessSkeleton(SkeletonExportContext& context)
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
return AddBonesToSkinningInfo(context.m_skinningInfo, context.m_scene.GetGraph(), context.m_rootBoneName) ?
SceneEvents::ProcessingResult::Success : SceneEvents::ProcessingResult::Failure;
}
bool SkeletonExporter::AddBonesToSkinningInfo(CSkinningInfo& skinningInfo, const SceneContainers::SceneGraph& graph, const AZStd::string& rootBoneName) const
{
if (rootBoneName.empty())
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Root bone name cannot be empty.");
return false;
}
AZ_TraceContext("Root bone", rootBoneName);
AZStd::unordered_map<AZStd::string, int> boneNameIdMap;
if (!BuildBoneMap(boneNameIdMap, graph, rootBoneName))
{
// Error already reported by BuildBoneMap.
return false;
}
SceneContainers::SceneGraph::NodeIndex nodeIndex = graph.Find(rootBoneName);
if (!nodeIndex.IsValid())
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Unable to find root bone in scene graph.");
return false;
}
auto contentStorage = graph.GetContentStorage();
auto nameStorage = graph.GetNameStorage();
auto pairView = SceneContainers::Views::MakePairView(contentStorage, nameStorage);
auto view = SceneContainers::Views::MakeSceneGraphDownwardsView<SceneContainers::Views::DepthFirst>(graph, nodeIndex, pairView.begin(), true);
for (auto it = view.begin(); it != view.end(); ++it)
{
if (it->first && it->first->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
AZ_TraceContext("Bone", it->second.GetPath());
AZStd::shared_ptr<const SceneDataTypes::IBoneData> boneData = azrtti_cast<const SceneDataTypes::IBoneData*>(it->first);
AZ_Assert(boneData, "Graph object couldn't be converted to bone data even though it matched the type.");
// Example fbx file exported from Maya will have default unit in centimeter.
// E.g. A global transformation in meter unit:
// 0.01 0 0 | 0.05
// 0 0.01 0 | 0
// 0 0 0.01 | 0
// while a global transform in centimeter unit:
// 1 0 0 | 5
// 0 1 0 | 0
// 0 0 1 | 0
// We need to remove scale from transform matrix (so the root bone's rotation matrix is identity) to satisfy the
// input requirement of AssetWriter
SceneAPI::DataTypes::MatrixType transformNoScale = boneData->GetWorldTransform();
AZ_Assert(transformNoScale.RetrieveScale().GetLength() >= Constants::FloatEpsilon, "Transform on bone %s has 0 scale", it->second.GetName());
transformNoScale.ExtractScale();
AddBoneDescriptor(skinningInfo, it->second.GetName(), it->second.GetNameLength(), transformNoScale);
if (!AddBoneEntity(skinningInfo, graph, graph.ConvertToNodeIndex(it.GetHierarchyIterator()), boneNameIdMap,
it->second.GetName(), it->second.GetPath(), rootBoneName))
{
// Error already reported in AddBoneEntity.
return false;
}
}
else
{
// End of bone chain or interruption in the bone chain. In both cases stop looking into this part of hierarchy further.
it.IgnoreNodeDescendants();
}
}
return true;
}
bool SkeletonExporter::BuildBoneMap(AZStd::unordered_map<AZStd::string, int>& boneNameIdMap, const SceneContainers::SceneGraph& graph, const AZStd::string& rootBoneName) const
{
if (rootBoneName.empty())
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Root bone name cannot be empty.");
return false;
}
AZ_TraceContext("Root bone", rootBoneName);
SceneContainers::SceneGraph::NodeIndex nodeIndex = graph.Find(rootBoneName);
if (!nodeIndex.IsValid())
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Unable to find root bone in scene graph.");
return false;
}
auto contentStorage = graph.GetContentStorage();
auto nameStorage = graph.GetNameStorage();
auto pairView = SceneContainers::Views::MakePairView(contentStorage, nameStorage);
auto view = SceneContainers::Views::MakeSceneGraphDownwardsView<SceneContainers::Views::DepthFirst>(graph, nodeIndex, pairView.begin(), true);
int index = 0;
for (auto it = view.begin(); it != view.end(); ++it)
{
if (it->first && it->first->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
boneNameIdMap[it->second.GetName()] = index;
index++;
}
else
{
// End of bone chain or interruption in the bone chain. In both cases stop looking into this part of hierarchy further.
it.IgnoreNodeDescendants();
}
}
return true;
}
void SkeletonExporter::AddBoneDescriptor(CSkinningInfo& skinningInfo, const char* boneName, size_t boneNameLength,
const SceneAPI::DataTypes::MatrixType& worldTransform) const
{
CryBoneDescData boneDesc;
auto convertedTransform{ AssetExportUtilities::ConvertToCryMatrix34(worldTransform) };
AZ_Assert(convertedTransform.IsValid(), "Bone %s has invalid world transform", boneName);
// Invalid transform will set off an assertion in the equals operator below - the check above is so
// in case of that assertion AP will give a hint of what to look at in the logs
boneDesc.m_DefaultB2W = convertedTransform;
boneDesc.m_DefaultW2B = boneDesc.m_DefaultB2W.GetInverted();
SetBoneName(boneName, boneNameLength, boneDesc);
boneDesc.m_nControllerID = CCrc32::ComputeLowercase(boneName);
skinningInfo.m_arrBonesDesc.push_back(boneDesc);
}
bool SkeletonExporter::AddBoneEntity(CSkinningInfo& skinningInfo, const SceneContainers::SceneGraph& graph, const SceneContainers::SceneGraph::NodeIndex index,
const AZStd::unordered_map<AZStd::string, int>& boneNameIdMap, const char* boneName, const char* bonePath, const AZStd::string& rootBoneName) const
{
BONE_ENTITY boneEntity;
memset(&boneEntity, 0, sizeof(boneEntity));
auto boneIndex = boneNameIdMap.find(boneName);
if (boneIndex != boneNameIdMap.end())
{
boneEntity.BoneID = boneIndex->second;
boneEntity.ParentID = -1;
if (rootBoneName.compare(bonePath) != 0)
{
SceneContainers::SceneGraph::NodeIndex parentIndex = graph.GetNodeParent(index);
auto parentIt = boneNameIdMap.find(graph.GetNodeName(parentIndex).GetName());
if (parentIt != boneNameIdMap.end())
{
boneEntity.ParentID = parentIt->second;
}
else
{
AZ_TracePrintf(SceneUtil::ErrorWindow, "Bone is not the root bone but doesn't have another bone as it's parent.");
return false;
}
}
}
boneEntity.ControllerID = CCrc32::ComputeLowercase(boneName);
boneEntity.phys.nPhysGeom = -1;
auto childBones = SceneContainers::Views::MakeSceneGraphChildView<SceneContainers::Views::AcceptNodesOnly>(
graph, index, graph.GetNameStorage().begin(), true);
boneEntity.nChildren = aznumeric_caster(AZStd::count_if(childBones.begin(), childBones.end(),
[&boneNameIdMap](const SceneContainers::SceneGraph::Name& name)
{
return boneNameIdMap.find(name.GetName()) != boneNameIdMap.end();
}));
skinningInfo.m_arrBoneEntities.push_back(boneEntity);
return true;
}
void SkeletonExporter::SetBoneName(const char* name, size_t nameLength, CryBoneDescData& boneDesc) const
{
static const size_t nodeNameCount = sizeof(boneDesc.m_arrBoneName) / sizeof(boneDesc.m_arrBoneName[0]);
size_t offset = (nameLength < nodeNameCount) ? 0 : (nameLength - nodeNameCount + 1);
azstrcpy(boneDesc.m_arrBoneName, nodeNameCount, name + offset);
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
struct CryBoneDescData;
struct CSkinningInfo;
namespace AZ
{
namespace RC
{
struct SkeletonExportContext;
struct ResolveRootBoneFromBoneContext;
struct BuildBoneMapContext;
struct AddBonesToSkinningInfoContext;
class SkeletonExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(SkeletonExporter, "{FDEC2360-3D9C-4027-BCFB-E8C99CAADB43}", SceneAPI::SceneCore::RCExportingComponent);
SkeletonExporter();
~SkeletonExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ResolveRootBoneFromBone(ResolveRootBoneFromBoneContext& context);
SceneAPI::Events::ProcessingResult BuildBoneMap(BuildBoneMapContext& context);
SceneAPI::Events::ProcessingResult AddBonesToSkinningInfo(AddBonesToSkinningInfoContext& context);
SceneAPI::Events::ProcessingResult ProcessSkeleton(SkeletonExportContext& context);
protected:
bool AddBonesToSkinningInfo(CSkinningInfo& skinningInfo,
const AZ::SceneAPI::Containers::SceneGraph& graph, const AZStd::string& rootBoneName) const;
bool BuildBoneMap(AZStd::unordered_map<AZStd::string, int>& boneNameIdMap,
const AZ::SceneAPI::Containers::SceneGraph& graph, const AZStd::string& rootBoneName) const;
void AddBoneDescriptor(CSkinningInfo& skinningInfo, const char* boneName, size_t boneNameLength,
const SceneAPI::DataTypes::MatrixType& worldTransform) const;
bool AddBoneEntity(CSkinningInfo& skinningInfo, const AZ::SceneAPI::Containers::SceneGraph& graph,
const AZ::SceneAPI::Containers::SceneGraph::NodeIndex index, const AZStd::unordered_map<AZStd::string, int>& boneNameIdMap,
const char* boneName, const char* bonePath, const AZStd::string& rootBoneName) const;
void SetBoneName(const char* name, size_t nameLength, CryBoneDescData& boneDesc) const;
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,240 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h>
#include <IIndexedMesh.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/SkinWeightExporter.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneUtils = AZ::SceneAPI::Utilities;
namespace SceneViews = SceneContainers::Views;
SkinWeightExporter::SkinWeightExporter()
{
BindToCall(&SkinWeightExporter::ResolveRootBoneFromNode);
BindToCall(&SkinWeightExporter::ProcessSkinWeights);
BindToCall(&SkinWeightExporter::ProcessTouchBendableSkinWeights);
}
void SkinWeightExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SkinWeightExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult SkinWeightExporter::ResolveRootBoneFromNode(ResolveRootBoneFromNodeContext& context)
{
using namespace SceneContainers;
using namespace SceneContainers::Views;
using namespace SceneDataTypes;
using namespace SceneEvents;
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
auto attributeView = MakeSceneGraphChildView<AcceptEndPointsOnly>(graph, context.m_nodeIndex, graph.GetContentStorage().begin(), true);
auto weights = AZStd::find_if(attributeView.begin(), attributeView.end(), DerivedTypeFilter<ISkinWeightData>());
if (weights == attributeView.end() || azrtti_cast<const SceneDataTypes::ISkinWeightData*>(*weights)->GetBoneCount() == 0)
{
AZ_TracePrintf(SceneUtils::WarningWindow, "No skin weight data, skin weight data ignored.");
return SceneEvents::ProcessingResult::Ignored;
}
const AZStd::string& boneName = azrtti_cast<const SceneDataTypes::ISkinWeightData*>(*weights)->GetBoneName(0);
AZ_TraceContext("Bone name", boneName);
ProcessingResult result = SceneEvents::Process<ResolveRootBoneFromBoneContext>(context.m_rootBoneName, context.m_scene, boneName);
if (result == ProcessingResult::Ignored)
{
AZ_TracePrintf(SceneUtils::WarningWindow, "No system registered that can resolve bone names.");
}
else if (result == ProcessingResult::Failure)
{
AZ_TracePrintf(SceneUtils::ErrorWindow, "Failed to resolve skeleton from bone.");
}
return result;
}
SceneEvents::ProcessingResult SkinWeightExporter::ProcessSkinWeights(MeshNodeExportContext& context)
{
if (context.m_phase != Phase::Filling || !context.m_group.RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::ISkinGroup::TYPEINFO_Uuid()))
{
return SceneEvents::ProcessingResult::Ignored;
}
AZ_TraceContext("Root bone", context.m_rootBoneName);
BoneNameIdMap boneNameIdMap;
SceneEvents::ProcessingResult result = SceneAPI::Events::Process<BuildBoneMapContext>(context.m_scene, context.m_rootBoneName, boneNameIdMap);
if (result == SceneEvents::ProcessingResult::Ignored)
{
AZ_TracePrintf(SceneUtils::WarningWindow, "No system registered that can handle skeletons for skins.");
return SceneEvents::ProcessingResult::Ignored;
}
else if (result == SceneEvents::ProcessingResult::Failure)
{
AZ_TracePrintf(SceneUtils::ErrorWindow, "Failed to load bone mapping for skin.");
return SceneEvents::ProcessingResult::Failure;
}
SetSkinWeights(context, boneNameIdMap);
return SceneEvents::ProcessingResult::Success;
}
SceneEvents::ProcessingResult SkinWeightExporter::ProcessTouchBendableSkinWeights(TouchBendableMeshNodeExportContext& context)
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZ_TraceContext("Root bone", context.m_rootBoneName);
BoneNameIdMap boneNameIdMap;
SceneEvents::ProcessingResult result = SceneAPI::Events::Process<BuildBoneMapContext>(context.m_scene, context.m_rootBoneName, boneNameIdMap);
if (result == SceneEvents::ProcessingResult::Ignored)
{
AZ_TracePrintf(SceneUtils::WarningWindow, "No system registered that can handle skeletons for skins.");
return SceneEvents::ProcessingResult::Ignored;
}
else if (result == SceneEvents::ProcessingResult::Failure)
{
AZ_TracePrintf(SceneUtils::ErrorWindow, "Failed to load bone mapping for skin.");
return SceneEvents::ProcessingResult::Failure;
}
SetSkinWeights(context, boneNameIdMap);
return SceneEvents::ProcessingResult::Success;
}
void SkinWeightExporter::SetSkinWeights(MeshNodeExportContext& context, BoneNameIdMap boneNameIdMap)
{
AZStd::shared_ptr<const SceneDataTypes::ISkinWeightData> skinWeights = nullptr;
AZStd::shared_ptr<const SceneData::GraphData::MeshData> meshData = nullptr;
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
SceneContainers::SceneGraph::NodeIndex index = graph.GetNodeChild(context.m_nodeIndex);
while (index.IsValid())
{
skinWeights = azrtti_cast<const SceneDataTypes::ISkinWeightData*>(graph.GetNodeContent(index));
if (skinWeights)
{
// Support first set of skin weights for now
auto parentIndex = graph.GetNodeParent(index);
if (parentIndex.IsValid())
{
meshData = azrtti_cast<const SceneData::GraphData::MeshData*>(graph.GetNodeContent(parentIndex));
}
else
{
AZ_TracePrintf(SceneUtils::WarningWindow, "Invalid mesh parent data for skin weights data");
}
break;
}
index = graph.GetNodeSibling(index);
}
if (skinWeights)
{
if (skinWeights->GetVertexCount() == 0)
{
AZ_TracePrintf(SceneUtils::WarningWindow, "Empty skin weight data, skin weight data ignored.");
return;
}
bool hasExtraWeights = false;
for (size_t vertexIndex = 0; vertexIndex < skinWeights->GetVertexCount(); ++vertexIndex)
{
if (skinWeights->GetLinkCount(vertexIndex) > 4)
{
hasExtraWeights = true;
break;
}
}
context.m_mesh.ReallocStream(CMesh::BONEMAPPING, 0, context.m_mesh.GetVertexCount());
if (hasExtraWeights)
{
context.m_mesh.ReallocStream(CMesh::EXTRABONEMAPPING, 0, context.m_mesh.GetVertexCount());
}
for (size_t vertexIndex = 0; vertexIndex < context.m_mesh.GetVertexCount(); ++vertexIndex)
{
int controlPointIndex = meshData->GetControlPointIndex(vertexIndex);
size_t linkCount = skinWeights->GetLinkCount(controlPointIndex);
for (size_t linkIndex = 0; linkIndex < 4 && linkIndex < linkCount; ++linkIndex)
{
const SceneDataTypes::ISkinWeightData::Link& link = skinWeights->GetLink(controlPointIndex, linkIndex);
context.m_mesh.m_pBoneMapping[vertexIndex].weights[linkIndex] = aznumeric_caster(GetClamp<float>(255.0f*link.weight, 0.0f, 255.0f));
context.m_mesh.m_pBoneMapping[vertexIndex].boneIds[linkIndex] =
aznumeric_caster(GetGlobalBoneId(skinWeights, boneNameIdMap, link.boneId));
}
if (hasExtraWeights)
{
for (size_t linkIndex = 4; linkIndex < 8 && linkIndex < linkCount; ++linkIndex)
{
const SceneDataTypes::ISkinWeightData::Link& link = skinWeights->GetLink(controlPointIndex, linkIndex);
context.m_mesh.m_pExtraBoneMapping[vertexIndex].weights[linkIndex - 4] = aznumeric_caster(GetClamp<float>(255.0f*link.weight, 0.0f, 255.0f));
context.m_mesh.m_pExtraBoneMapping[vertexIndex].boneIds[linkIndex - 4] =
aznumeric_caster(GetGlobalBoneId(skinWeights, boneNameIdMap, link.boneId));
}
}
}
}
}
int SkinWeightExporter::GetGlobalBoneId(
const AZStd::shared_ptr<const SceneDataTypes::ISkinWeightData>& skinWeights, BoneNameIdMap boneNameIdMap, int boneId)
{
AZ_TraceContext("Bone id", boneId);
const AZStd::string& boneName = skinWeights->GetBoneName(boneId);
AZ_TraceContext("Bone name", boneName);
if (boneName.empty())
{
AZ_TracePrintf(SceneUtils::WarningWindow, "Invalid local bone id referenced in skin weight data");
return -1;
}
auto it = boneNameIdMap.find(boneName);
if (it == boneNameIdMap.end())
{
AZ_TracePrintf(SceneUtils::WarningWindow, "Local bone name referenced in skin weight data doesn't exist in global bone map");
return -1;
}
return it->second;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class ISkinWeightData;
}
}
namespace RC
{
struct ResolveRootBoneFromNodeContext;
struct MeshNodeExportContext;
class SkinWeightExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
using BoneNameIdMap = AZStd::unordered_map<AZStd::string, int>;
AZ_COMPONENT(SkinWeightExporter, "{97C7D185-14F5-4BB1-AAE0-120A722882D1}", SceneAPI::SceneCore::RCExportingComponent);
SkinWeightExporter();
~SkinWeightExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ResolveRootBoneFromNode(ResolveRootBoneFromNodeContext& context);
SceneAPI::Events::ProcessingResult ProcessSkinWeights(MeshNodeExportContext& context);
SceneAPI::Events::ProcessingResult ProcessTouchBendableSkinWeights(TouchBendableMeshNodeExportContext& context);
protected:
void SetSkinWeights(MeshNodeExportContext& context, BoneNameIdMap boneNameIdMap);
int GetGlobalBoneId(const AZStd::shared_ptr<const SceneAPI::DataTypes::ISkinWeightData>& skinWeights, BoneNameIdMap boneNameIdMap, int boneId);
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,223 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for CGFContent.h
#include <CGFContent.h>
#include <PropertyHelpers.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ITouchBendingRule.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <RC/ResourceCompilerScene/Common/ExportContextGlobal.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/TouchBendingExporter.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h> //Needed by CgfExportContexts.h
#include <RC/ResourceCompilerScene/Cgf/CgfExportContexts.h>
#include <RC/ResourceCompilerScene/Cgf/CgfUtils.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneUtil = AZ::SceneAPI::Utilities;
namespace SceneViews = AZ::SceneAPI::Containers::Views;
namespace AzStringFunc = AzFramework::StringFunc;
TouchBendingExporter::TouchBendingExporter()
: AZ::SceneAPI::SceneCore::RCExportingComponent()
{
BindToCall(&TouchBendingExporter::ConfigureContainer);
BindToCall(&TouchBendingExporter::ProcessSkinnedMesh);
}
void TouchBendingExporter::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<TouchBendingExporter, AZ::SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult TouchBendingExporter::ConfigureContainer(ContainerExportContext& context)
{
switch (context.m_phase)
{
case Phase::Filling:
{
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
AZStd::vector<AZStd::string> noCollideTargetNodes = SceneUtil::SceneGraphSelector::GenerateTargetNodes(graph, touchBendingRule->GetSceneNodeSelectionList(), SceneUtil::SceneGraphSelector::IsMesh);
ProcessMeshType(context, context.m_container, noCollideTargetNodes, PHYS_GEOM_TYPE_NO_COLLIDE);
}
return SceneEvents::ProcessingResult::Success;
case Phase::Finalizing:
{
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
//Let's make sure we have valid CSkinningInfo, otherwise,
//there's no point in adding the Bone Tree helper nodes.
CSkinningInfo* skinningInfo = context.m_container.GetSkinningInfo();
if (skinningInfo->m_arrBonesDesc.size() < 1)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::string rootBoneName = touchBendingRule->GetRootBoneName();
AddHelperBoneNodes(context, context.m_container, rootBoneName,
touchBendingRule->ShouldOverrideDamping(), touchBendingRule->GetOverrideDamping(),
touchBendingRule->ShouldOverrideStiffness(), touchBendingRule->GetOverrideStiffness(),
touchBendingRule->ShouldOverrideThickness(), touchBendingRule->GetOverrideThickness());
}
return SceneEvents::ProcessingResult::Success;
default:
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult TouchBendingExporter::ProcessSkinnedMesh(AZ::RC::MeshNodeExportContext& context)
{
if (context.m_physicalizeType != PHYS_GEOM_TYPE_NONE)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::string rootBoneName = touchBendingRule->GetRootBoneName();
SceneEvents::ProcessingResult result = SceneEvents::ProcessingResult::Ignored;
switch (context.m_phase)
{
case Phase::Filling:
result = SceneEvents::Process<TouchBendableMeshNodeExportContext>(
context, rootBoneName, Phase::Filling);
break;
case Phase::Construction:
{
//Add the Bones to CSkinningInfo only if they have not been added already.
CSkinningInfo* skinningInfo = context.m_container.GetSkinningInfo();
if (skinningInfo->m_arrBonesDesc.size() == 0)
{
result = SceneEvents::Process<AddBonesToSkinningInfoContext>(
*skinningInfo, context.m_scene, rootBoneName);
}
}
break;
default:
break;
}
return result;
}
/*!
The format is based on Cry's PropertyHelpers::SetPropertyValue.
This version doesn't do any nullptr checking or white space trimming,
because those errors are guaranteed not to happen.
*/
static void AddPropertyValue(AZStd::string& inoutPropertiesString, const char* propertyName, float value, const char * propertySeparator)
{
char valueStr[16];
snprintf(valueStr, sizeof(valueStr), "%f", value);
AzStringFunc::Append(inoutPropertiesString, propertyName);
AzStringFunc::Append(inoutPropertiesString, '=');
AzStringFunc::Append(inoutPropertiesString, valueStr);
if (propertySeparator)
{
AzStringFunc::Append(inoutPropertiesString, propertySeparator);
}
}
bool TouchBendingExporter::AddHelperBoneNodes(AZ::RC::ContainerExportContext& context, CContentCGF& content, AZStd::string& rootBoneName,
[[maybe_unused]] bool shouldOverrideDamping, float damping,
[[maybe_unused]] bool shouldOverrideStiffness, float stiffness,
[[maybe_unused]] bool shouldOverrideThickness, float thickness)
{
AZ_TraceContext("AddHelperBoneNodes() rootBoneName:", rootBoneName);
if (rootBoneName.empty())
{
AZ_TracePrintf(TraceWindowName, "Root bone name cannot be empty.");
return false;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
SceneContainers::SceneGraph::NodeIndex nodeIndex = graph.Find(rootBoneName);
if (!nodeIndex.IsValid())
{
AZ_TracePrintf(TraceWindowName, "Unable to find root bone in scene graph.");
return false;
}
auto contentStorage = graph.GetContentStorage();
auto nameStorage = graph.GetNameStorage();
auto pairView = SceneViews::MakePairView(contentStorage, nameStorage);
auto view = SceneViews::MakeSceneGraphDownwardsView<SceneViews::DepthFirst>(graph, nodeIndex, pairView.begin(), true);
int index = 0;
//Once SceneAPI supports Per Node Attributes, the string with properties
//should be built per Node. In the meantime, because all the properties are
//the same for all nodes, the string can be built once.
AZStd::string nodeProperties;
AddPropertyValue(nodeProperties, NODE_PROPERTY_DAMPING, damping, "\r\n");
AddPropertyValue(nodeProperties, NODE_PROPERTY_STIFFNESS, stiffness, "\r\n");
AddPropertyValue(nodeProperties, NODE_PROPERTY_THICKNESS, thickness, nullptr);
for (auto it = view.begin(); it != view.end(); ++it)
{
if (it->first && it->first->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
//These very dummy nodes, are only used to define the name
//of the spines. It is not necessary to set transform matrices,
//nor it is relevant to set parent pointers, etc.
CNodeCGF* nodeCgf = new CNodeCGF();
SetNodeName(it->second.GetName(), *nodeCgf);
nodeCgf->type = CNodeCGF::NODE_HELPER;
nodeCgf->helperType = HP_POINT;
nodeCgf->properties = nodeProperties.c_str();
content.AddNode(nodeCgf);
}
else
{
// End of bone chain or interruption in the bone chain. In both cases stop looking into this part of hierarchy further.
it.IgnoreNodeDescendants();
}
}
return true;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,60 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
struct CNodeCGF;
class CContentCGF;
namespace AZ
{
class ReflectContext;
namespace RC
{
struct CgfGroupExportContext;
struct ContainerExportContext;
struct MeshNodeExportContext;
class TouchBendingExporter
: public AZ::SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(TouchBendingExporter, "{4C6694B3-F7A8-48D8-A10A-46D57F8CC75E}", AZ::SceneAPI::SceneCore::RCExportingComponent);
TouchBendingExporter();
~TouchBendingExporter() override = default;
static void Reflect(AZ::ReflectContext* context);
SceneAPI::Events::ProcessingResult ConfigureContainer(AZ::RC::ContainerExportContext& context);
SceneAPI::Events::ProcessingResult ProcessSkinnedMesh(AZ::RC::MeshNodeExportContext& context);
static constexpr const char * const TraceWindowName = "TouchBending";
protected:
/*!
StaticObjectCompiler, when building SFoliageInfoCGF, uses the "branch%d_%d" named bones to build the spines.
This methods adds the tree of CNodeCGF helper nodes from Bones with such names.
*/
bool AddHelperBoneNodes(AZ::RC::ContainerExportContext& context, CContentCGF& content, AZStd::string& rootBoneName,
bool shouldOverrideDamping, float damping,
bool shouldOverrideStiffness, float stiffness,
bool shouldOverrideThickness, float thickness);
}; //class TouchBendingCgfExporter
} // namespace RC
} //namespace AZ
@@ -0,0 +1,149 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for IIndexedMesh.h
#include <IIndexedMesh.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMeshAdvancedRule.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexUVData.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/UVStreamExporter.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneUtilities = AZ::SceneAPI::Utilities;
UVStreamExporter::UVStreamExporter()
{
BindToCall(&UVStreamExporter::CopyUVStream);
}
void UVStreamExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<UVStreamExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult UVStreamExporter::CopyUVStream(MeshNodeExportContext& context) const
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
const SceneDataTypes::IGroup& group = context.m_group;
SceneEvents::ProcessingResultCombiner result;
AZStd::vector<AZStd::shared_ptr<const SceneDataTypes::IMeshVertexUVData>> uvStreams;
// Find all uv streams and save them into uvStreams to be used later
SceneContainers::SceneGraph::NodeIndex index = graph.GetNodeChild(context.m_nodeIndex);
while (index.IsValid())
{
AZStd::string streamName;
AZStd::shared_ptr<const SceneDataTypes::IMeshVertexUVData> uvStream = azrtti_cast<const SceneDataTypes::IMeshVertexUVData*>(graph.GetNodeContent(index));
if (uvStream)
{
uvStreams.push_back(uvStream);
streamName = graph.GetNodeName(index).GetName();
AZ_TraceContext("UV set", streamName);
if (context.m_mesh.GetVertexCount() != uvStream->GetCount())
{
AZ_TracePrintf(SceneUtilities::ErrorWindow,
"Number of vertices in the mesh (%i) doesn't match with the number of stored UVs (%i).",
context.m_mesh.GetVertexCount(), uvStream->GetCount(), streamName.c_str());
result += SceneEvents::ProcessingResult::Failure;
}
}
index = graph.GetNodeSibling(index);
}
// Populate a default uv if there is no existing uv stream.
if (uvStreams.size() == 0)
{
AZ_TraceContext("UV set", "UVs not used");
uvStreams.emplace_back(nullptr);
}
for (size_t uvIndex = 0; uvIndex < AZStd::min((size_t)s_uvMaxStreamCount, uvStreams.size()); ++uvIndex)
{
AZStd::shared_ptr<const SceneDataTypes::IMeshVertexUVData> uvs = uvStreams[uvIndex];
result += PopulateUVStream(context, uvIndex, uvs);
}
return result.GetResult();
}
SceneEvents::ProcessingResult UVStreamExporter::PopulateUVStream(MeshNodeExportContext& context, int index, AZStd::shared_ptr<const SceneDataTypes::IMeshVertexUVData> uvs) const
{
context.m_mesh.ReallocStream(CMesh::TEXCOORDS, index, context.m_mesh.GetVertexCount());
SMeshTexCoord* uvStream = context.m_mesh.template GetStreamPtr<SMeshTexCoord>(CMesh::TEXCOORDS, index);
if (uvs)
{
for (int i = 0; i < context.m_mesh.GetVertexCount(); ++i)
{
const AZ::Vector2& uv = uvs->GetUV(i);
if (!uv.IsFinite())
{
AZ_TracePrintf(SceneUtilities::ErrorWindow, "Invalid UV data detected at index %d.", i);
return SceneEvents::ProcessingResult::Failure;
}
// Note: If this is a skin mesh the y value of texture coordinate needs to be inverted, because as it processes
// through CharacterCompiler::ProcessWork, it will get inverted again. This pre-corrects things to ensure the
// finally generated skin's uv texture coordinates are correct.
if (context.m_group.RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::ISkinGroup::TYPEINFO_Uuid()))
{
uvStream[i] = SMeshTexCoord(uv.GetX(), 1.0f - uv.GetY());
}
else
{
uvStream[i] = SMeshTexCoord(uv.GetX(), uv.GetY());
}
}
}
//Default to a dummy stream of data.
else
{
static const SMeshTexCoord defaultTextureCoordinate(0.0f, 0.0f);
for (int i = 0; i < context.m_mesh.GetVertexCount(); ++i)
{
uvStream[i] = defaultTextureCoordinate;
}
}
return SceneEvents::ProcessingResult::Success;
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,41 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexUVData.h>
namespace AZ
{
namespace RC
{
struct MeshNodeExportContext;
class UVStreamExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(UVStreamExporter, "{3840C94B-C131-4C34-B35B-C8E8CFC5AFD1}", SceneAPI::SceneCore::RCExportingComponent);
UVStreamExporter();
~UVStreamExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult CopyUVStream(MeshNodeExportContext& context) const;
protected:
SceneAPI::Events::ProcessingResult PopulateUVStream(MeshNodeExportContext& context, int index, AZStd::shared_ptr<const SceneAPI::DataTypes::IMeshVertexUVData> uvs) const;
static const size_t s_uvMaxStreamCount = 2;
};
} // namespace RC
} // namespace AZ
@@ -0,0 +1,199 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Cry_Geo.h> // Needed for CGFContent.h
#include <CGFContent.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IOriginRule.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/WorldMatrixExporter.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneViews = AZ::SceneAPI::Containers::Views;
WorldMatrixExporter::WorldMatrixExporter()
: m_cachedRootMatrix(MatrixType::CreateIdentity())
, m_cachedGroup(nullptr)
, m_cachedRootMatrixIsSet(false)
{
BindToCall(&WorldMatrixExporter::ProcessMeshGroup);
BindToCall(&WorldMatrixExporter::ProcessNode);
}
void WorldMatrixExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<WorldMatrixExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult WorldMatrixExporter::ProcessMeshGroup(ContainerExportContext& context)
{
if (context.m_phase != Phase::Construction)
{
return SceneEvents::ProcessingResult::Ignored;
}
m_cachedGroup = &context.m_group;
m_cachedRootMatrix = MatrixType::CreateIdentity();
m_cachedRootMatrixIsSet = false;
AZStd::shared_ptr<const SceneDataTypes::IOriginRule> rule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::IOriginRule>();
if (rule)
{
if (rule->GetTranslation() != Vector3(0.0f, 0.0f, 0.0f) || !rule->GetRotation().IsIdentity())
{
m_cachedRootMatrix = MatrixType::CreateFromQuaternionAndTranslation(rule->GetRotation(), rule->GetTranslation());
m_cachedRootMatrixIsSet = true;
}
if (rule->GetScale() != 1.0f)
{
float scale = rule->GetScale();
m_cachedRootMatrix.MultiplyByScale(Vector3(scale, scale, scale));
m_cachedRootMatrixIsSet = true;
}
if (!rule->GetOriginNodeName().empty() && !rule->UseRootAsOrigin())
{
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
SceneContainers::SceneGraph::NodeIndex index = graph.Find(rule->GetOriginNodeName());
if (index.IsValid())
{
MatrixType worldMatrix = MatrixType::CreateIdentity();
if (ConcatenateMatricesUpwards(worldMatrix, graph.ConvertToHierarchyIterator(index), graph))
{
worldMatrix.InvertFull();
m_cachedRootMatrix *= worldMatrix;
m_cachedRootMatrixIsSet = true;
}
}
}
return m_cachedRootMatrixIsSet ? SceneEvents::ProcessingResult::Success : SceneEvents::ProcessingResult::Ignored;
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult WorldMatrixExporter::ProcessNode(NodeExportContext& context)
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
MatrixType worldMatrix = MatrixType::CreateIdentity();
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
HierarchyStorageIterator nodeIterator = graph.ConvertToHierarchyIterator(context.m_nodeIndex);
bool translated = ConcatenateMatricesUpwards(worldMatrix, nodeIterator, graph);
AZ_Assert(m_cachedGroup == &context.m_group, "NodeExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
if (m_cachedRootMatrixIsSet)
{
worldMatrix = m_cachedRootMatrix * worldMatrix;
translated = true;
}
//If we aren't merging nodes we need to put the transforms into the localTM
//due to how the CGFSaver works inside the ResourceCompilerPC code.
if (!context.m_container.GetExportInfo()->bMergeAllNodes)
{
SceneAPIMatrixTypeToMatrix34(context.m_node.localTM, worldMatrix);
}
else
{
SceneAPIMatrixTypeToMatrix34(context.m_node.worldTM, worldMatrix);
}
context.m_node.bIdentityMatrix = !translated;
return SceneEvents::ProcessingResult::Success;
}
bool WorldMatrixExporter::ConcatenateMatricesUpwards(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneContainers::SceneGraph& graph) const
{
bool translated = false;
auto view = SceneViews::MakeSceneGraphUpwardsView(graph, nodeIterator, graph.GetContentStorage().cbegin(), true);
for (auto it = view.begin(); it != view.end(); ++it)
{
if (!(*it))
{
continue;
}
const SceneDataTypes::ITransform* nodeTransform = azrtti_cast<const SceneDataTypes::ITransform*>(it->get());
if (nodeTransform)
{
transform = nodeTransform->GetMatrix() * transform;
translated = true;
}
else
{
bool endPointTransform = MultiplyEndPointTransforms(transform, it.GetHierarchyIterator(), graph);
translated = translated || endPointTransform;
}
}
return translated;
}
bool WorldMatrixExporter::MultiplyEndPointTransforms(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneContainers::SceneGraph& graph) const
{
// If the translation is not an end point it means it's its own group as opposed to being
// a component of the parent, so only list end point children.
auto view = SceneViews::MakeSceneGraphChildView<SceneViews::AcceptEndPointsOnly>(graph, nodeIterator,
graph.GetContentStorage().begin(), true);
auto result = AZStd::find_if(view.begin(), view.end(), SceneContainers::DerivedTypeFilter<SceneDataTypes::ITransform>());
if (result != view.end())
{
transform = azrtti_cast<const SceneDataTypes::ITransform*>(result->get())->GetMatrix() * transform;
return true;
}
else
{
return false;
}
}
void WorldMatrixExporter::SceneAPIMatrixTypeToMatrix34(Matrix34& out, const MatrixType& in) const
{
// Setting column instead of row because as of writing Matrix34 doesn't support adding
// full rows, as the translation has to be done separately.
for (int column = 0; column < 4; ++column)
{
Vector3 data = in.GetColumn(column);
out.SetColumn(column, Vec3(data.GetX(), data.GetY(), data.GetZ()));
}
}
} // namespace RC
} // namespace AZ
@@ -0,0 +1,65 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Cry_Matrix34.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
class Transform;
namespace SceneAPI
{
namespace DataTypes
{
class IOriginRule;
class IGroup;
}
}
namespace RC
{
struct ContainerExportContext;
struct NodeExportContext;
class WorldMatrixExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(WorldMatrixExporter, "{65A0914C-5953-405F-819B-0E6EB96938F1}", SceneAPI::SceneCore::RCExportingComponent);
WorldMatrixExporter();
~WorldMatrixExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ProcessMeshGroup(ContainerExportContext& context);
SceneAPI::Events::ProcessingResult ProcessNode(NodeExportContext& context);
protected:
using HierarchyStorageIterator = SceneAPI::Containers::SceneGraph::HierarchyStorageConstIterator;
using MatrixType = SceneAPI::DataTypes::MatrixType;
bool ConcatenateMatricesUpwards(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneAPI::Containers::SceneGraph& graph) const;
bool MultiplyEndPointTransforms(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneAPI::Containers::SceneGraph& graph) const;
void SceneAPIMatrixTypeToMatrix34(Matrix34& out, const MatrixType& in) const;
MatrixType m_cachedRootMatrix;
const SceneAPI::DataTypes::IGroup* m_cachedGroup;
bool m_cachedRootMatrixIsSet;
};
} // namespace RC
} // namespace AZ