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,76 @@
#
# 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.
#
if (NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_add_target(
NAME FbxSceneBuilder.Static STATIC
NAMESPACE AZ
FILES_CMAKE
fbxscenebuilder_files.cmake
Platform/${PAL_PLATFORM_NAME}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
COMPILE_DEFINITIONS
PRIVATE
FBX_SCENE_BUILDER_EXPORTS
INCLUDE_DIRECTORIES
PUBLIC
../..
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
PUBLIC
AZ::AzToolsFramework
AZ::FbxSDKWrapper
AZ::SceneCore
AZ::SceneData
)
ly_add_target(
NAME FbxSceneBuilder MODULE
NAMESPACE AZ
FILES_CMAKE
fbxscenebuilder_shared_files.cmake
COMPILE_DEFINITIONS
PRIVATE
FBX_SCENE_BUILDER_EXPORTS
INCLUDE_DIRECTORIES
PUBLIC
../..
BUILD_DEPENDENCIES
PUBLIC
AZ::FbxSceneBuilder.Static
PRIVATE
AZ::AzCore
)
ly_add_dependencies(AssetBuilder AZ::FbxSceneBuilder)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME FbxSceneBuilder.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
fbxscenebuilder_testing_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
AZ::FbxSceneBuilder
)
ly_add_googletest(
NAME AZ::FbxSceneBuilder.Tests
)
endif()
@@ -0,0 +1,158 @@
/*
* 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.
*
*/
#if !defined(AZ_MONOLITHIC_BUILD)
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Module/Environment.h>
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
#include <SceneAPI/FbxSceneBuilder/FbxImporter.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.h>
#endif
#include <SceneAPI/FbxSceneBuilder/Importers/FbxAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxMaterialImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxUvMapImporter.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
static AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler* g_fbxImporter = nullptr;
static AZStd::vector<AZ::ComponentDescriptor*> g_componentDescriptors;
void Initialize()
{
// Currently it's still needed to explicitly create an instance of this instead of letting
// it be a normal component. This is because ResourceCompilerScene needs to return
// the list of available extensions before it can start the application.
if (!g_fbxImporter)
{
g_fbxImporter = aznew AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler();
g_fbxImporter->Activate();
}
}
void Reflect(AZ::SerializeContext* /*context*/)
{
// Descriptor registration is done in Reflect instead of Initialize because the ResourceCompilerScene initializes the libraries before
// there's an application.
using namespace AZ::SceneAPI;
using namespace AZ::SceneAPI::FbxSceneBuilder;
if (g_componentDescriptors.empty())
{
// Global importer and behavior
g_componentDescriptors.push_back(FbxSceneBuilder::FbxImporter::CreateDescriptor());
// Node and attribute importers
g_componentDescriptors.push_back(FbxAnimationImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxBlendShapeImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxBoneImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxColorStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxMaterialImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxMeshImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxSkinImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxSkinWeightsImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxTransformImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxUvMapImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxTangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxBitangentStreamImporter::CreateDescriptor());
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
g_componentDescriptors.push_back(AssImpColorStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMaterialImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMeshImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpTransformImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpUvMapImporter::CreateDescriptor());
#endif
for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors)
{
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Handler::RegisterComponentDescriptor, descriptor);
}
}
}
void ReflectBehavior([[maybe_unused]] AZ::BehaviorContext* context)
{
// stub in until LYN-1284 is done
}
void Activate()
{
}
void Deactivate()
{
}
void Uninitialize()
{
if (!g_componentDescriptors.empty())
{
for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors)
{
descriptor->ReleaseDescriptor();
}
g_componentDescriptors.clear();
g_componentDescriptors.shrink_to_fit();
}
if (g_fbxImporter)
{
g_fbxImporter->Deactivate();
delete g_fbxImporter;
g_fbxImporter = nullptr;
}
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env)
{
AZ::Environment::Attach(static_cast<AZ::EnvironmentInstance>(env));
AZ::SceneAPI::FbxSceneBuilder::Initialize();
}
extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context)
{
AZ::SceneAPI::FbxSceneBuilder::Reflect(context);
}
extern "C" AZ_DLL_EXPORT void ReflectBehavior(AZ::BehaviorContext* context)
{
AZ::SceneAPI::FbxSceneBuilder::ReflectBehavior(context);
}
extern "C" AZ_DLL_EXPORT void UninitializeDynamicModule()
{
AZ::SceneAPI::FbxSceneBuilder::Uninitialize();
AZ::Environment::Detach();
}
#endif // !defined(AZ_MONOLITHIC_BUILD)
@@ -0,0 +1,78 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneImporter
{
const char* FbxImportRequestHandler::s_extension = ".fbx";
void FbxImportRequestHandler::Activate()
{
BusConnect();
}
void FbxImportRequestHandler::Deactivate()
{
BusDisconnect();
}
void FbxImportRequestHandler::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxImportRequestHandler, SceneCore::BehaviorComponent>()->Version(1);
}
}
void FbxImportRequestHandler::GetSupportedFileExtensions(AZStd::unordered_set<AZStd::string>& extensions)
{
extensions.insert(s_extension);
}
Events::LoadingResult FbxImportRequestHandler::LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid, [[maybe_unused]] RequestingApplication requester)
{
if (!AzFramework::StringFunc::Path::IsExtension(path.c_str(), s_extension))
{
return Events::LoadingResult::Ignored;
}
scene.SetSource(path, guid);
// Push contexts
Events::ProcessingResultCombiner contextResult;
contextResult += Events::Process<Events::PreImportEventContext>(path);
contextResult += Events::Process<Events::ImportEventContext>(path, scene);
contextResult += Events::Process<Events::PostImportEventContext>(scene);
if (contextResult.GetResult() == Events::ProcessingResult::Success)
{
return Events::LoadingResult::AssetLoaded;
}
else
{
return Events::LoadingResult::AssetFailure;
}
}
} // namespace Import
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,46 @@
/*
* 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/BehaviorComponent.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneImporter
{
class FbxImportRequestHandler
: public SceneCore::BehaviorComponent
, public Events::AssetImportRequestBus::Handler
{
public:
AZ_COMPONENT(FbxImportRequestHandler, "{9F4B189C-0A96-4F44-A5F0-E087FF1561F8}", SceneCore::BehaviorComponent);
~FbxImportRequestHandler() override = default;
void Activate() override;
void Deactivate() override;
static void Reflect(ReflectContext* context);
void GetSupportedFileExtensions(AZStd::unordered_set<AZStd::string>& extensions) override;
Events::LoadingResult LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid,
RequestingApplication requester) override;
private:
static const char* s_extension;
};
} // namespace FbxSceneImporter
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,437 @@
/*
* 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/Casting/numeric_cast.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/queue.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxImporter.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#endif
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/TransformData.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#endif
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
struct QueueNode
{
std::shared_ptr<SDKNode::NodeWrapper> m_node;
Containers::SceneGraph::NodeIndex m_parent;
QueueNode() = delete;
QueueNode(std::shared_ptr<SDKNode::NodeWrapper>&& node, Containers::SceneGraph::NodeIndex parent)
: m_node(std::move(node))
, m_parent(parent)
{
}
};
FbxImporter::FbxImporter()
: m_sceneSystem(new FbxSceneSystem())
{
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
if (m_useAssetImporterSDK)
{
m_sceneWrapper = AZStd::make_unique<AssImpSDKWrapper::AssImpSceneWrapper>();
}
else
{
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
}
#else
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
#endif
BindToCall(&FbxImporter::ImportProcessing);
}
void FbxImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxImporter::ImportProcessing(Events::ImportEventContext& context)
{
m_sceneWrapper->Clear();
if (!m_sceneWrapper->LoadSceneFromFile(context.GetInputDirectory().c_str()))
{
return Events::ProcessingResult::Failure;
}
typedef AZStd::function<bool(Containers::Scene & scene)> ConvertFunc;
ConvertFunc convertFunc;
m_sceneSystem->Set(m_sceneWrapper.get());
if (azrtti_istypeof<FbxSDKWrapper::FbxSceneWrapper>(m_sceneWrapper.get()))
{
convertFunc = AZStd::bind(&FbxImporter::ConvertFbxSceneContext, this, AZStd::placeholders::_1);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
convertFunc = AZStd::bind(&FbxImporter::ConvertFbxScene, this, AZStd::placeholders::_1);
}
#endif
if (convertFunc(context.GetScene()))
{
return Events::ProcessingResult::Success;
}
else
{
return Events::ProcessingResult::Failure;
}
}
bool FbxImporter::ConvertFbxSceneContext(Containers::Scene& scene) const
{
std::shared_ptr<SDKNode::NodeWrapper> fbxRoot = m_sceneWrapper->GetRootNode();
if (!fbxRoot)
{
return false;
}
FbxSDKWrapper::FbxSceneWrapper* fbxSceneWrapper = azrtti_cast <FbxSDKWrapper::FbxSceneWrapper*>(m_sceneWrapper.get());
int sign = 0;
FbxSDKWrapper::FbxAxisSystemWrapper::UpVector upVector = fbxSceneWrapper->GetAxisSystem()->GetUpVector(sign);
AZ_Assert(sign != 0, "sign failed to populate which is a failure in GetUpVector");
if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::Z)
{
if (sign > 0)
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::ZUp);
}
else
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegZUp);
AZ_Assert(false, "Negative Z Up scene orientation is not a currently supported orientation.");
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative Z Up scene orientation is not a currently supported orientation.");
}
}
else if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::Y)
{
if (sign > 0)
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::YUp);
}
else
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegYUp);
AZ_Assert(false, "Negative Y Up scene orientation is not a currently supported orientation.");
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative Y Up scene orientation is not a currently supported orientation.");
}
}
else if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::X)
{
if (sign > 0)
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::XUp);
AZ_Assert(false, "Positive X Up scene orientation is not a currently supported orientation.");
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Positive X Up scene orientation is not a currently supported orientation.");
}
else
{
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegXUp);
AZ_Assert(false, "Negative X Up scene orientation is not a currently supported orientation.");
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative X Up scene orientation is not a currently supported orientation.");
}
}
AZStd::queue<FbxSceneBuilder::QueueNode> nodes;
nodes.emplace(AZStd::move(fbxRoot), scene.GetGraph().GetRoot());
RenamedNodesMap nodeNameMap;
while (!nodes.empty())
{
FbxSceneBuilder::QueueNode& node = nodes.front();
AZ_Assert(node.m_node, "Empty fbx node queued");
if (!nodeNameMap.RegisterNode(node.m_node, scene.GetGraph(), node.m_parent))
{
AZ_TracePrintf(Utilities::ErrorWindow, "Failed to register fbx node in name table.");
continue;
}
AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node);
AZ_TraceContext("SceneAPI Node Name", nodeName);
Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str());
AZ_Assert(newNode.IsValid(), "Failed to add node to scene graph");
if (!newNode.IsValid())
{
continue;
}
FbxNodeEncounteredContext sourceNodeEncountered(scene, newNode, *fbxSceneWrapper, *m_sceneSystem, nodeNameMap, *azrtti_cast<AZ::FbxSDKWrapper::FbxNodeWrapper*>(node.m_node.get()));
Events::ProcessingResultCombiner nodeResult;
nodeResult += Events::Process(sourceNodeEncountered);
// If no importer created data, we still create an empty node that may eventually contain a transform
if (sourceNodeEncountered.m_createdData.empty())
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Success,
"Importers returned success but no data was created");
AZStd::shared_ptr<DataTypes::IGraphObject> nullData(nullptr);
sourceNodeEncountered.m_createdData.emplace_back(nullData);
nodeResult += Events::ProcessingResult::Success;
}
// Create single node since only one piece of graph data was created
if (sourceNodeEncountered.m_createdData.size() == 1)
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
"An importer created data, but did not return success");
if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
{
AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
}
SceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
sourceNodeEncountered.m_createdData[0], nodeName.c_str());
Events::ProcessingResult result = AddDataNodeWithContexts(dataProcessed);
if (result != Events::ProcessingResult::Failure)
{
newNode = dataProcessed.m_currentGraphPosition;
}
}
// Create an empty parent node and place all data under it. The remaining
// tree will be built off of this as the logical parent
else
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
"%i importers created data, but did not return success",
sourceNodeEncountered.m_createdData.size());
if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
{
AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
}
size_t offset = nodeName.length();
for (size_t i = 0; i < sourceNodeEncountered.m_createdData.size(); ++i)
{
nodeName += '_';
nodeName += AZStd::to_string(aznumeric_cast<AZ::u64>(i + 1));
Containers::SceneGraph::NodeIndex subNode =
scene.GetGraph().AddChild(newNode, nodeName.c_str());
AZ_Assert(subNode.IsValid(), "Failed to create new scene sub node");
SceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
sourceNodeEncountered.m_createdData[i], nodeName);
dataProcessed.m_currentGraphPosition = subNode;
AddDataNodeWithContexts(dataProcessed);
// Remove the temporary extension again.
nodeName.erase(offset, nodeName.length() - offset);
}
}
AZ_Assert(nodeResult.GetResult() == Events::ProcessingResult::Success,
"No importers successfully added processed scene data.");
AZ_Assert(newNode != node.m_parent,
"Failed to update current graph position during data processing.");
int childCount = node.m_node->GetChildCount();
for (int i = 0; i < childCount; ++i)
{
std::shared_ptr<FbxSDKWrapper::FbxNodeWrapper> child = std::make_shared<FbxSDKWrapper::FbxNodeWrapper>(node.m_node->GetChild(i)->GetFbxNode());
if (child)
{
nodes.emplace(AZStd::move(child), newNode);
}
}
nodes.pop();
}
Events::ProcessingResult result = Events::Process<FinalizeSceneContext>(scene, *fbxSceneWrapper, *m_sceneSystem, nodeNameMap);
if (result == Events::ProcessingResult::Failure)
{
return false;
}
return true;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool FbxImporter::ConvertFbxScene(Containers::Scene& scene) const
{
std::shared_ptr<SDKNode::NodeWrapper> fbxRoot = m_sceneWrapper->GetRootNode();
if (!fbxRoot)
{
return false;
}
const AssImpSDKWrapper::AssImpSceneWrapper* assImpSceneWrapper = azrtti_cast <AssImpSDKWrapper::AssImpSceneWrapper*>(m_sceneWrapper.get());
AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> upAxisAndSign = assImpSceneWrapper->GetUpVectorAndSign();
if (upAxisAndSign.second <= 0)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative scene orientation is not a currently supported orientation.");
return false;
}
switch (upAxisAndSign.first)
{
case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::X:
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::XUp);
break;
case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Y:
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::YUp);
break;
case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Z:
scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::ZUp);
break;
default:
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unknown scene orientation, %d.", upAxisAndSign.first);
AZ_Assert(false, "Unknown scene orientation, %d.", upAxisAndSign.first);
break;
}
AZStd::queue<FbxSceneBuilder::QueueNode> nodes;
nodes.emplace(AZStd::move(fbxRoot), scene.GetGraph().GetRoot());
RenamedNodesMap nodeNameMap;
while (!nodes.empty())
{
FbxSceneBuilder::QueueNode& node = nodes.front();
AZ_Assert(node.m_node, "Empty asset importer node queued");
if (!nodeNameMap.RegisterNode(node.m_node, scene.GetGraph(), node.m_parent))
{
AZ_TracePrintf(Utilities::ErrorWindow, "Failed to register asset importer node in name table.");
continue;
}
AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node);
AZ_TraceContext("SceneAPI Node Name", nodeName);
Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str());
AZ_Error(Utilities::ErrorWindow, newNode.IsValid(), "Failed to add Asset Importer node to scene graph");
if (!newNode.IsValid())
{
continue;
}
AssImpNodeEncounteredContext sourceNodeEncountered(scene, newNode, *assImpSceneWrapper, *m_sceneSystem, nodeNameMap, *azrtti_cast<AZ::AssImpSDKWrapper::AssImpNodeWrapper*>(node.m_node.get()));
Events::ProcessingResultCombiner nodeResult;
nodeResult += Events::Process(sourceNodeEncountered);
// If no importer created data, we still create an empty node that may eventually contain a transform
if (sourceNodeEncountered.m_createdData.empty())
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Success,
"Importers returned success but no data was created");
AZStd::shared_ptr<DataTypes::IGraphObject> nullData(nullptr);
sourceNodeEncountered.m_createdData.emplace_back(nullData);
nodeResult += Events::ProcessingResult::Success;
}
// Create single node since only one piece of graph data was created
if (sourceNodeEncountered.m_createdData.size() == 1)
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
"An importer created data, but did not return success");
if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
{
AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
}
AssImpSceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
sourceNodeEncountered.m_createdData[0], nodeName.c_str());
Events::ProcessingResult result = AddDataNodeWithContexts(dataProcessed);
if (result != Events::ProcessingResult::Failure)
{
newNode = dataProcessed.m_currentGraphPosition;
}
}
// Create an empty parent node and place all data under it. The remaining
// tree will be built off of this as the logical parent
else
{
AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored,
"%i importers created data, but did not return success",
sourceNodeEncountered.m_createdData.size());
if (nodeResult.GetResult() == Events::ProcessingResult::Failure)
{
AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data.");
}
size_t offset = nodeName.length();
for (size_t i = 0; i < sourceNodeEncountered.m_createdData.size(); ++i)
{
nodeName += '_';
nodeName += AZStd::to_string(aznumeric_cast<AZ::u64>(i + 1));
Containers::SceneGraph::NodeIndex subNode =
scene.GetGraph().AddChild(newNode, nodeName.c_str());
AZ_Assert(subNode.IsValid(), "Failed to create new scene sub node");
AssImpSceneDataPopulatedContext dataProcessed(sourceNodeEncountered,
sourceNodeEncountered.m_createdData[i], nodeName);
dataProcessed.m_currentGraphPosition = subNode;
AddDataNodeWithContexts(dataProcessed);
// Remove the temporary extension again.
nodeName.erase(offset, nodeName.length() - offset);
}
}
AZ_Assert(nodeResult.GetResult() == Events::ProcessingResult::Success,
"No importers successfully added processed scene data.");
AZ_Assert(newNode != node.m_parent,
"Failed to update current graph position during data processing.");
int childCount = node.m_node->GetChildCount();
for (int i = 0; i < childCount; ++i)
{
std::shared_ptr<AssImpSDKWrapper::AssImpNodeWrapper> child = std::make_shared<AssImpSDKWrapper::AssImpNodeWrapper>(node.m_node->GetChild(i)->GetAssImpNode());
if (child)
{
nodes.emplace(AZStd::move(child), newNode);
}
}
nodes.pop();
};
Events::ProcessingResult result = Events::Process<AssImpFinalizeSceneContext>(scene, *assImpSceneWrapper, *m_sceneSystem, nodeNameMap);
if (result == Events::ProcessingResult::Failure)
{
return false;
}
return true;
}
#endif
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // 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/smart_ptr/unique_ptr.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/SDKWrapper/SceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class Scene;
}
namespace FbxSceneBuilder
{
class FbxImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxImporter, "{D5EE21B6-8B73-45BF-B711-31346E0BEDB3}", SceneCore::LoadingComponent);
FbxImporter();
~FbxImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportProcessing(Events::ImportEventContext& context);
protected:
bool ConvertFbxSceneContext(Containers::Scene& scene) const;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool ConvertFbxScene(Containers::Scene& scene) const;
#endif
AZStd::unique_ptr<SDKScene::SceneWrapperBase> m_sceneWrapper;
AZStd::shared_ptr<FbxSceneSystem> m_sceneSystem;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool m_useAssetImporterSDK = false;
#endif
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,25 @@
#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/PlatformDef.h>
#if defined(AZ_MONOLITHIC_BUILD)
#define FBX_SCENE_BUILDER_API
#else
#ifdef FBX_SCENE_BUILDER_EXPORTS
#define FBX_SCENE_BUILDER_API AZ_DLL_EXPORT
#else
#define FBX_SCENE_BUILDER_API AZ_DLL_IMPORT
#endif
#endif // AZ_MONOLITHIC_BUILD
@@ -0,0 +1,180 @@
/*
* 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/Math/Vector3.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <assimp/scene.h>
#endif
namespace AZ
{
namespace SceneAPI
{
FbxSceneSystem::FbxSceneSystem() :
m_unitSizeInMeters(1.0f),
m_originalUnitSizeInMeters(1.0f),
m_adjustTransform(nullptr),
m_adjustTransformInverse(nullptr)
{
}
void FbxSceneSystem::Set(const SDKScene::SceneWrapperBase* fbxScene)
{
// Get unit conversion factor to meter.
if (azrtti_istypeof<FbxSDKWrapper::FbxSceneWrapper>(fbxScene))
{
const FbxSDKWrapper::FbxSceneWrapper* fbxSDKScene = azrtti_cast <const FbxSDKWrapper::FbxSceneWrapper*>(fbxScene);
m_unitSizeInMeters = fbxSDKScene->GetSystemUnit()->GetConversionFactorTo(FbxSDKWrapper::FbxSystemUnitWrapper::m);
const FbxGlobalSettings& globalSettings = fbxSDKScene->GetFbxScene()->GetGlobalSettings();
m_originalUnitSizeInMeters = static_cast<float>(globalSettings.GetOriginalSystemUnit().GetConversionFactorTo(FbxSystemUnit::m));
int sign = 0;
FbxSDKWrapper::FbxAxisSystemWrapper::UpVector upVector = fbxSDKScene->GetAxisSystem()->GetUpVector(sign);
if (upVector != FbxSDKWrapper::FbxAxisSystemWrapper::Z && upVector != FbxSDKWrapper::FbxAxisSystemWrapper::Unknown)
{
m_adjustTransform.reset(new DataTypes::MatrixType(fbxSDKScene->GetAxisSystem()->CalculateConversionTransform(FbxSDKWrapper::FbxAxisSystemWrapper::Z)));
m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
}
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else if (azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(fbxScene))
{
const AssImpSDKWrapper::AssImpSceneWrapper* assImpScene = azrtti_cast<const AssImpSDKWrapper::AssImpSceneWrapper*>(fbxScene);
// If either meta data piece is not available, the default of 1 will be used.
assImpScene->GetAssImpScene()->mMetaData->Get("UnitScaleFactor", m_unitSizeInMeters);
assImpScene->GetAssImpScene()->mMetaData->Get("OriginalUnitScaleFactor", m_originalUnitSizeInMeters);
/* Conversion factor for converting from centimeters to meters */
m_unitSizeInMeters = m_unitSizeInMeters *.01f;
AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> upAxisAndSign = assImpScene->GetUpVectorAndSign();
if (upAxisAndSign.second <= 0)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative scene orientation is not a currently supported orientation.");
return;
}
AZStd::pair<AssImpSDKWrapper::AssImpSceneWrapper::AxisVector, int32_t> frontAxisAndSign = assImpScene->GetFrontVectorAndSign();
if (upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Z &&
upAxisAndSign.first != AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Unknown)
{
AZ::Matrix4x4 currentCoordMatrix = AZ::Matrix4x4::CreateIdentity();
//(UpVector = +Z, FrontVector = +Y, CoordSystem = -X(RightHanded))
AZ::Matrix4x4 targetCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(-1, 0, 0, 0),
AZ::Vector4(0, 0, 1, 0),
AZ::Vector4(0, 1, 0, 0),
AZ::Vector4(0, 0, 0, 1));
switch (upAxisAndSign.first)
{
case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::X:
{
if (frontAxisAndSign.second == 1)
{
currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(0, -1, 0, 0),
AZ::Vector4(1, 0, 0, 0),
AZ::Vector4(0, 0, 1, 0),
AZ::Vector4(0, 0, 0, 1));
}
else
{
currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(0, 1, 0, 0),
AZ::Vector4(1, 0, 0, 0),
AZ::Vector4(0, 0, -1, 0),
AZ::Vector4(0, 0, 0, 1));
}
}
break;
case AssImpSDKWrapper::AssImpSceneWrapper::AxisVector::Y:
{
if (frontAxisAndSign.second == 1)
{
currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(1, 0, 0, 0),
AZ::Vector4(0, 1, 0, 0),
AZ::Vector4(0, 0, 1, 0),
AZ::Vector4(0, 0, 0, 1));
}
else
{
currentCoordMatrix = AZ::Matrix4x4::CreateFromColumns(
AZ::Vector4(-1, 0, 0, 0),
AZ::Vector4(0, 1, 0, 0),
AZ::Vector4(0, 0, -1, 0),
AZ::Vector4(0, 0, 0, 1));
}
}
break;
}
AZ::Matrix4x4 inverse = currentCoordMatrix.GetInverseTransform();
AZ::Matrix4x4 adjustmatrix = targetCoordMatrix * currentCoordMatrix.GetInverseTransform();
m_adjustTransform.reset(new DataTypes::MatrixType(AssImpSDKWrapper::AssImpTypeConverter::ToTransform(adjustmatrix)));
m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
}
}
#endif
}
void FbxSceneSystem::SwapVec3ForUpAxis(Vector3& swapVector) const
{
if (m_adjustTransform)
{
swapVector = *m_adjustTransform * swapVector;
}
}
void FbxSceneSystem::SwapTransformForUpAxis(DataTypes::MatrixType& inOutTransform) const
{
if (m_adjustTransform)
{
inOutTransform = (*m_adjustTransform * inOutTransform) * *m_adjustTransformInverse;
}
}
void FbxSceneSystem::ConvertUnit(Vector3& scaleVector) const
{
scaleVector *= m_unitSizeInMeters;
}
void FbxSceneSystem::ConvertUnit(DataTypes::MatrixType& inOutTransform) const
{
Vector3 translation = inOutTransform.GetTranslation();
translation *= m_unitSizeInMeters;
inOutTransform.SetTranslation(translation);
}
void FbxSceneSystem::ConvertBoneUnit(DataTypes::MatrixType& inOutTransform) const
{
// Need to scale translation explicitly as MultiplyByScale won't change the translation component
// and we need to convert to meter unit
Vector3 translation = inOutTransform.GetTranslation();
translation *= m_unitSizeInMeters;
inOutTransform.SetTranslation(translation);
}
}
}
@@ -0,0 +1,61 @@
#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/smart_ptr/unique_ptr.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneBuilderConfiguration.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
class Vector3;
namespace SDKScene
{
class SceneWrapperBase;
}
namespace SceneAPI
{
class FBX_SCENE_BUILDER_API FbxSceneSystem
{
public:
FbxSceneSystem();
void Set(const SDKScene::SceneWrapperBase* sceneWrapper);
void SwapVec3ForUpAxis(Vector3& swapVector) const;
void SwapTransformForUpAxis(DataTypes::MatrixType& inOutTransform) const;
void ConvertUnit(Vector3& scaleVector) const;
void ConvertUnit(DataTypes::MatrixType& inOutTransform) const;
void ConvertBoneUnit(DataTypes::MatrixType& inOutTransform) const;
//! Get effect unit size in meters of this Fbx Scene, internally FBX saves it in the following manner
//! GlobalSettings: {
//! P : "UnitScaleFactor", "double", "Number", "", 2.54
float GetUnitSizeInMeters() const { return m_unitSizeInMeters; }
//! Get original unit size in meters of this Fbx Scene, internally FBX saves it in the following manner
//! GlobalSettings: {
//! P : "OriginalUnitScaleFactor", "double", "Number", "", 2.54
float GetOriginalUnitSizeInMeters() const { return m_originalUnitSizeInMeters; }
protected:
float m_unitSizeInMeters = 1;
float m_originalUnitSizeInMeters = 1;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZStd::unique_ptr<DataTypes::MatrixType> m_adjustTransform;
AZStd::unique_ptr<DataTypes::MatrixType> m_adjustTransformInverse;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
}
};
@@ -0,0 +1,129 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpImportContext::AssImpImportContext(const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode)
: m_sourceScene(sourceScene)
, m_sourceSceneSystem(sourceSceneSystem)
, m_sourceNode(sourceNode)
{
}
AssImpNodeEncounteredContext::AssImpNodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode)
: AssImpImportContext(sourceScene, sourceSceneSystem, sourceNode)
, NodeEncounteredContext(scene, currentGraphPosition, nodeNameMap)
{
}
AssImpNodeEncounteredContext::AssImpNodeEncounteredContext(
Events::ImportEventContext& parent,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode)
: AssImpImportContext(sourceScene, sourceSceneSystem, sourceNode)
, NodeEncounteredContext(parent.GetScene(), currentGraphPosition, nodeNameMap)
{
}
AssImpSceneDataPopulatedContext::AssImpSceneDataPopulatedContext(AssImpNodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& graphData, const AZStd::string& dataName)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneDataPopulatedContextBase(parent, graphData, dataName)
{
}
AssImpSceneDataPopulatedContext::AssImpSceneDataPopulatedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const AZStd::string& dataName)
: AssImpImportContext(sourceScene, sourceSceneSystem, sourceNode)
, SceneDataPopulatedContextBase(scene, currentGraphPosition, nodeNameMap, nodeData, dataName)
{
}
AssImpSceneNodeAppendedContext::AssImpSceneNodeAppendedContext(AssImpSceneDataPopulatedContext& parent,
Containers::SceneGraph::NodeIndex newIndex)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeAppendedContextBase(parent.m_scene, newIndex, parent.m_nodeNameMap)
{
}
AssImpSceneNodeAppendedContext::AssImpSceneNodeAppendedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap, AssImpSDKWrapper::AssImpNodeWrapper& sourceNode)
: AssImpImportContext(sourceScene, sourceSceneSystem, sourceNode)
, SceneNodeAppendedContextBase(scene, currentGraphPosition, nodeNameMap)
{
}
AssImpSceneAttributeDataPopulatedContext::AssImpSceneAttributeDataPopulatedContext(AssImpSceneNodeAppendedContext& parent, const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const Containers::SceneGraph::NodeIndex attributeNodeIndex, const AZStd::string& dataName)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneAttributeDataPopulatedContextBase(parent, nodeData, attributeNodeIndex, dataName)
{
}
AssImpSceneAttributeNodeAppendedContext::AssImpSceneAttributeNodeAppendedContext(AssImpSceneAttributeDataPopulatedContext& parent, Containers::SceneGraph::NodeIndex newIndex)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneAttributeNodeAppendedContextBase(parent, newIndex)
{
}
AssImpSceneNodeAddedAttributesContext::AssImpSceneNodeAddedAttributesContext(AssImpSceneNodeAppendedContext& parent)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeAddedAttributesContextBase(parent)
{
}
AssImpSceneNodeFinalizeContext::AssImpSceneNodeFinalizeContext(AssImpSceneNodeAddedAttributesContext& parent)
: AssImpImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeFinalizeContextBase(parent)
{
}
AssImpFinalizeSceneContext::AssImpFinalizeSceneContext(Containers::Scene& scene,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap)
: FinalizeSceneContextBase(scene, nodeNameMap)
, m_sourceScene(sourceScene)
, m_sourceSceneSystem(sourceSceneSystem)
{
}
} // namespace SceneAPI
} // namespace FbxSceneBuilder
} // namespace AZ
@@ -0,0 +1,187 @@
/*
* 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/RTTI/RTTI.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/ImportContexts.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
namespace AZ
{
namespace AssImpSDKWrapper
{
class AssImpNodeWrapper;
class AssImpSceneWrapper;
}
namespace SceneAPI
{
class FbxSceneSystem;
namespace FbxSceneBuilder
{
class RenamedNodesMap;
// AssImpImportContext
// Base structure containing common data needed for all import contexts
// Member Variables:
// m_sourceNode - AssImp node being used for data processing.
struct AssImpImportContext
{
AZ_RTTI(AssImpImportContext, "{B1076AFF-991B-423C-8D3E-D5C9230434AB}");
AssImpImportContext(const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode);
const AssImpSDKWrapper::AssImpSceneWrapper& m_sourceScene;
AssImpSDKWrapper::AssImpNodeWrapper& m_sourceNode;
const FbxSceneSystem& m_sourceSceneSystem; // Needed for unit and axis conversion
};
// AssImpNodeEncounteredContext
// Context pushed to indicate that a new AssImp Node has been found and any
// importers that have means to process the contained data should do so
struct AssImpNodeEncounteredContext
: public AssImpImportContext
, public NodeEncounteredContext
{
AZ_RTTI(AssImpNodeEncounteredContext, "{C2305BC5-EAEC-4515-BAD6-45E63C3FBD3D}", AssImpImportContext, NodeEncounteredContext);
AssImpNodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode);
AssImpNodeEncounteredContext(Events::ImportEventContext& parent,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode);
};
// AssImpSceneDataPopulatedContext
// Context pushed to indicate that a piece of scene data has been fully
// processed and any importers that wish to place it within the scene graph
// may now do so.
struct AssImpSceneDataPopulatedContext
: public AssImpImportContext
, public SceneDataPopulatedContextBase
{
AZ_RTTI(AssImpSceneDataPopulatedContext, "{888DA37E-4234-4990-AD50-E6E54AFA9C35}", AssImpImportContext, SceneDataPopulatedContextBase);
AssImpSceneDataPopulatedContext(AssImpNodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const AZStd::string& dataName);
AssImpSceneDataPopulatedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const AZStd::string& dataName);
};
// AssImpSceneNodeAppendedContext
// Context pushed to indicate that data has been added to the scene graph.
// Generally created due to the insertion of a node during SceneDataPopulatedContext
// processing.
struct AssImpSceneNodeAppendedContext
: public AssImpImportContext
, public SceneNodeAppendedContextBase
{
AZ_RTTI(AssImpSceneNodeAppendedContext, "{9C8B688E-8ECD-4EF0-9AC6-21BBCFE8F5A3}", AssImpImportContext, SceneNodeAppendedContextBase);
AssImpSceneNodeAppendedContext(AssImpSceneDataPopulatedContext& parent, Containers::SceneGraph::NodeIndex newIndex);
AssImpSceneNodeAppendedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap,
AssImpSDKWrapper::AssImpNodeWrapper& sourceNode);
};
// AssImpSceneAttributeDataPopulatedContext
// Context pushed to indicate that attribute data has been found and processed
struct AssImpSceneAttributeDataPopulatedContext
: public AssImpImportContext
, public SceneAttributeDataPopulatedContextBase
{
AZ_RTTI(AssImpSceneAttributeDataPopulatedContext, "{A5EFB485-2F36-4214-972B-0EFF4EFBF33D}", AssImpImportContext, SceneAttributeDataPopulatedContextBase);
AssImpSceneAttributeDataPopulatedContext(AssImpSceneNodeAppendedContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const Containers::SceneGraph::NodeIndex attributeNodeIndex,const AZStd::string& dataName);
};
// AssImpSceneAttributeNodeAppendedContext
// Context pushed to indicate that an attribute node has been added to the scene graph
struct AssImpSceneAttributeNodeAppendedContext
: public AssImpImportContext
, public SceneAttributeNodeAppendedContextBase
{
AZ_RTTI(AssImpSceneAttributeNodeAppendedContext, "{96FDC405-2D3B-4030-A301-B3A2B5432498}", AssImpImportContext, SceneAttributeNodeAppendedContextBase);
AssImpSceneAttributeNodeAppendedContext(AssImpSceneAttributeDataPopulatedContext& parent, Containers::SceneGraph::NodeIndex newIndex);
};
// AssImpSceneNodeAddedAttributesContext
// Context pushed to indicate that all attribute processors have completed their
// work for a specific data node.
struct AssImpSceneNodeAddedAttributesContext
: public AssImpImportContext
, public SceneNodeAddedAttributesContextBase
{
AZ_RTTI(AssImpSceneNodeAddedAttributesContext, "{D305EAA5-5F16-4AAD-805D-DF07A1B355B9}", AssImpImportContext, SceneNodeAddedAttributesContextBase);
AssImpSceneNodeAddedAttributesContext(AssImpSceneNodeAppendedContext& parent);
};
// AssImpSceneNodeFinalizeContext
// Context pushed last after all other contexts for a scene node to allow any
// post-processing needed for an importer.
struct AssImpSceneNodeFinalizeContext
: public AssImpImportContext
, public SceneNodeFinalizeContextBase
{
AZ_RTTI(AssImpSceneNodeFinalizeContext, "{FD8B4AD5-3735-4D55-9455-504AB1DCA655}", AssImpImportContext, SceneNodeFinalizeContextBase);
AssImpSceneNodeFinalizeContext(AssImpSceneNodeAddedAttributesContext& parent);
};
// AssImpFinalizeSceneContext
// Context pushed after the scene has been fully created. This can be used to finalize pending work
// such as resolving named links.
struct AssImpFinalizeSceneContext
: public FinalizeSceneContextBase
{
AZ_RTTI(AssImpFinalizeSceneContext, "{6B23A54A-44BF-4661-A130-6B4D06A57B9F}", FinalizeSceneContextBase);
AssImpFinalizeSceneContext(
Containers::Scene& scene,
const AssImpSDKWrapper::AssImpSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap);
const AssImpSDKWrapper::AssImpSceneWrapper& m_sourceScene;
const FbxSceneSystem& m_sourceSceneSystem; // Needed for unit and axis conversion
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,115 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxImportContext::FbxImportContext(const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, FbxSDKWrapper::FbxNodeWrapper& sourceNode)
: m_sourceScene(sourceScene)
, m_sourceSceneSystem(sourceSceneSystem)
, m_sourceNode(sourceNode)
{
}
FbxNodeEncounteredContext::FbxNodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode)
: FbxImportContext(sourceScene, sourceSceneSystem, sourceNode)
, NodeEncounteredContext(scene, currentGraphPosition, nodeNameMap)
{
}
FbxNodeEncounteredContext::FbxNodeEncounteredContext(
Events::ImportEventContext& parent, Containers::SceneGraph::NodeIndex currentGraphPosition,
const FbxSDKWrapper::FbxSceneWrapper& sourceScene, const FbxSceneSystem& sourceSceneSystem,
RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode)
: FbxImportContext(sourceScene, sourceSceneSystem, sourceNode)
, NodeEncounteredContext(parent.GetScene(), currentGraphPosition, nodeNameMap)
{
}
SceneDataPopulatedContext::SceneDataPopulatedContext(FbxNodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& graphData, const AZStd::string& dataName)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneDataPopulatedContextBase(parent, graphData, dataName)
{
}
SceneDataPopulatedContext::SceneDataPopulatedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const AZStd::string& dataName)
: FbxImportContext(sourceScene, sourceSceneSystem, sourceNode)
, SceneDataPopulatedContextBase(scene, currentGraphPosition, nodeNameMap, nodeData, dataName)
{
}
SceneNodeAppendedContext::SceneNodeAppendedContext(SceneDataPopulatedContext& parent,
Containers::SceneGraph::NodeIndex newIndex)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeAppendedContextBase(parent.m_scene, newIndex, parent.m_nodeNameMap)
{
}
SceneNodeAppendedContext::SceneNodeAppendedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode)
: FbxImportContext(sourceScene, sourceSceneSystem, sourceNode)
, SceneNodeAppendedContextBase(scene, currentGraphPosition, nodeNameMap)
{
}
SceneAttributeDataPopulatedContext::SceneAttributeDataPopulatedContext(SceneNodeAppendedContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const Containers::SceneGraph::NodeIndex attributeNodeIndex, const AZStd::string& dataName)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneAttributeDataPopulatedContextBase(parent, nodeData, attributeNodeIndex, dataName)
{
}
SceneAttributeNodeAppendedContext::SceneAttributeNodeAppendedContext(
SceneAttributeDataPopulatedContext& parent, Containers::SceneGraph::NodeIndex newIndex)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneAttributeNodeAppendedContextBase(parent, newIndex)
{
}
SceneNodeAddedAttributesContext::SceneNodeAddedAttributesContext(SceneNodeAppendedContext& parent)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeAddedAttributesContextBase(parent)
{
}
SceneNodeFinalizeContext::SceneNodeFinalizeContext(SceneNodeAddedAttributesContext& parent)
: FbxImportContext(parent.m_sourceScene, parent.m_sourceSceneSystem, parent.m_sourceNode)
, SceneNodeFinalizeContextBase(parent)
{
}
FinalizeSceneContext::FinalizeSceneContext(Containers::Scene& scene, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap)
: FinalizeSceneContextBase(scene, nodeNameMap)
, m_sourceScene(sourceScene)
, m_sourceSceneSystem(sourceSceneSystem)
{
}
} // namespace SceneAPI
} // namespace FbxSceneBuilder
} // namespace AZ
@@ -0,0 +1,184 @@
/*
* 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/RTTI/RTTI.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/ImportContexts.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxSceneWrapper;
class FbxNodeWrapper;
}
namespace SceneAPI
{
class FbxSceneSystem;
namespace FbxSceneBuilder
{
class RenamedNodesMap;
// FbxImportContext
// Base structure containing common data needed for all import contexts
// Member Variables:
// m_sourceScene - Basic scene data extracted from the FBX Scene. Used to
// transform data.
// m_sourceNode - FBX node being used for data processing.
struct FbxImportContext
{
AZ_RTTI(FbxImportContext, "{C8D665D5-E871-41AD-90E7-C84CF6842BCF}");
FbxImportContext(const FbxSDKWrapper::FbxSceneWrapper& sourceScene, const FbxSceneSystem& sourceSceneSystem,
FbxSDKWrapper::FbxNodeWrapper& sourceNode);
const FbxSDKWrapper::FbxSceneWrapper& m_sourceScene;
const FbxSceneSystem& m_sourceSceneSystem; // Needed for unit and axis conversion
FbxSDKWrapper::FbxNodeWrapper& m_sourceNode;
};
// FbxNodeEncounteredContext
// Context pushed to indicate that a new FBX Node has been found and any
// importers that have means to process the contained data should do so
// Member Variables:
// m_createdData - out container that importers must add their created data
// to.
struct FbxNodeEncounteredContext
: public FbxImportContext
, public NodeEncounteredContext
{
AZ_RTTI(FbxNodeEncounteredContext, "{BE21E324-6745-41FD-A79C-A6CA7AB15A7A}", FbxImportContext, NodeEncounteredContext);
FbxNodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode);
FbxNodeEncounteredContext(Events::ImportEventContext& parent,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode);
};
// SceneDataPopulatedContext
// Context pushed to indicate that a piece of scene data has been fully
// processed and any importers that wish to place it within the scene graph
// may now do so. This may be triggered by processing a FbxNodeEncounteredContext
// (for base data, e.g. bones, meshes) or from a SceneNodeAppendedContext
// (for attribute data, e.g. UV Maps, materials)
// Member Variables:
// m_graphData - the piece of data that should be inserted in the graph
// m_dataName - the name that should be used as the basis for the scene node
// name
// m_isAttribute - Indicates whether the graph data is an attribute
struct SceneDataPopulatedContext
: public FbxImportContext
, public SceneDataPopulatedContextBase
{
AZ_RTTI(SceneDataPopulatedContext, "{DF17306C-FE28-4BEB-9CF0-88CF0472B8A8}", FbxImportContext, SceneDataPopulatedContextBase);
SceneDataPopulatedContext(FbxNodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const AZStd::string& dataName);
SceneDataPopulatedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const AZStd::string& dataName);
};
// SceneNodeAppendedContext
// Context pushed to indicate that data has been added to the scene graph.
// Generally created due to the insertion of a node during SceneDataPopulatedContext
// processing.
struct SceneNodeAppendedContext
: public FbxImportContext
, public SceneNodeAppendedContextBase
{
AZ_RTTI(SceneNodeAppendedContext, "{72C1C37A-C6ED-4CB7-B929-DA03AA44131C}", FbxImportContext, SceneNodeAppendedContextBase);
SceneNodeAppendedContext(SceneDataPopulatedContext& parent, Containers::SceneGraph::NodeIndex newIndex);
SceneNodeAppendedContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap, FbxSDKWrapper::FbxNodeWrapper& sourceNode);
};
// SceneAttributeDataPopulatedContext
// Context pushed to indicate that attribute data has been found and processed
struct SceneAttributeDataPopulatedContext
: public FbxImportContext
, public SceneAttributeDataPopulatedContextBase
{
AZ_RTTI(SceneAttributeDataPopulatedContext, "{93E67C26-5A40-4385-8189-947A626E3CDA}", FbxImportContext, SceneAttributeDataPopulatedContextBase);
SceneAttributeDataPopulatedContext(SceneNodeAppendedContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const Containers::SceneGraph::NodeIndex attributeNodeIndex, const AZStd::string& dataName);
};
// SceneAttributeNodeAppendedContext
// Context pushed to indicate that an attribute node has been added to the scene graph
struct SceneAttributeNodeAppendedContext
: public FbxImportContext
, public SceneAttributeNodeAppendedContextBase
{
AZ_RTTI(SceneAttributeNodeAppendedContext, "{C0DD4F39-5C61-4CA0-96C5-9EA3AC40D98B}", FbxImportContext, SceneAttributeNodeAppendedContextBase);
SceneAttributeNodeAppendedContext(SceneAttributeDataPopulatedContext& parent,
Containers::SceneGraph::NodeIndex newIndex);
};
// SceneNodeAddedAttributesContext
// Context pushed to indicate that all attribute processors have completed their
// work for a specific data node.
struct SceneNodeAddedAttributesContext
: public FbxImportContext
, public SceneNodeAddedAttributesContextBase
{
AZ_RTTI(SceneNodeAddedAttributesContext, "{1601900C-5109-4D37-83F1-22317A4D7C78}", FbxImportContext, SceneNodeAddedAttributesContextBase);
SceneNodeAddedAttributesContext(SceneNodeAppendedContext& parent);
};
// SceneNodeFinalizeContext
// Context pushed last after all other contexts for a scene node to allow any
// post-processing needed for an importer.
struct SceneNodeFinalizeContext
: public FbxImportContext
, public SceneNodeFinalizeContextBase
{
AZ_RTTI(SceneNodeFinalizeContext, "{D1D9839A-EA48-425D-BB7A-A9AEA65B8B7A}", FbxImportContext, SceneNodeFinalizeContextBase);
SceneNodeFinalizeContext(SceneNodeAddedAttributesContext& parent);
};
// FinalizeSceneContext
// Context pushed after the scene has been fully created. This can be used to finalize pending work
// such as resolving named links.
struct FinalizeSceneContext
: public FinalizeSceneContextBase
{
AZ_RTTI(FinalizeSceneContext, "{C8D665D5-E871-41AD-90E7-C84CF6842BCF}", FinalizeSceneContextBase);
FinalizeSceneContext(Containers::Scene& scene, const FbxSDKWrapper::FbxSceneWrapper& sourceScene,
const FbxSceneSystem& sourceSceneSystem, RenamedNodesMap& nodeNameMap);
const FbxSDKWrapper::FbxSceneWrapper& m_sourceScene;
const FbxSceneSystem& m_sourceSceneSystem; // Needed for unit and axis conversion
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,112 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/ImportContexts.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
ImportContext::ImportContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap)
: m_scene(scene)
, m_currentGraphPosition(currentGraphPosition)
, m_nodeNameMap(nodeNameMap)
{
}
ImportContext::ImportContext(Containers::Scene& scene, RenamedNodesMap& nodeNameMap)
: m_scene(scene)
, m_nodeNameMap(nodeNameMap)
{
m_currentGraphPosition = Containers::SceneGraph::NodeIndex();
}
NodeEncounteredContext::NodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap)
: ImportContext(scene, currentGraphPosition, nodeNameMap)
{
}
NodeEncounteredContext::NodeEncounteredContext(
Events::ImportEventContext& parent, Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap)
: ImportContext(parent.GetScene(), currentGraphPosition, nodeNameMap)
{
}
SceneDataPopulatedContextBase::SceneDataPopulatedContextBase(NodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& graphData, const AZStd::string& dataName)
: ImportContext(parent.m_scene, parent.m_currentGraphPosition, parent.m_nodeNameMap)
, m_graphData(graphData)
, m_dataName(dataName)
{
}
SceneDataPopulatedContextBase::SceneDataPopulatedContextBase(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const AZStd::string& dataName)
: ImportContext(scene, currentGraphPosition, nodeNameMap)
, m_graphData(nodeData)
, m_dataName(dataName)
{
}
SceneNodeAppendedContextBase::SceneNodeAppendedContextBase(SceneDataPopulatedContextBase& parent,
Containers::SceneGraph::NodeIndex newIndex)
: ImportContext(parent.m_scene, newIndex, parent.m_nodeNameMap)
{
}
SceneNodeAppendedContextBase::SceneNodeAppendedContextBase(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, RenamedNodesMap& nodeNameMap)
: ImportContext(scene, currentGraphPosition, nodeNameMap)
{
}
SceneAttributeDataPopulatedContextBase::SceneAttributeDataPopulatedContextBase(SceneNodeAppendedContextBase& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const Containers::SceneGraph::NodeIndex attributeNodeIndex, const AZStd::string& dataName)
: ImportContext(parent.m_scene, attributeNodeIndex, parent.m_nodeNameMap)
, m_graphData(nodeData)
, m_dataName(dataName)
{
}
SceneAttributeNodeAppendedContextBase::SceneAttributeNodeAppendedContextBase(SceneAttributeDataPopulatedContextBase& parent, Containers::SceneGraph::NodeIndex newIndex)
: ImportContext(parent.m_scene, newIndex, parent.m_nodeNameMap)
{
}
SceneNodeAddedAttributesContextBase::SceneNodeAddedAttributesContextBase(SceneNodeAppendedContextBase& parent)
: ImportContext(parent.m_scene, parent.m_currentGraphPosition, parent.m_nodeNameMap)
{
}
SceneNodeFinalizeContextBase::SceneNodeFinalizeContextBase(SceneNodeAddedAttributesContextBase& parent)
: ImportContext(parent.m_scene, parent.m_currentGraphPosition, parent.m_nodeNameMap)
{
}
FinalizeSceneContextBase::FinalizeSceneContextBase(Containers::Scene& scene, RenamedNodesMap& nodeNameMap)
: ImportContext(scene, nodeNameMap)
{
}
} // namespace SceneAPI
} // namespace FbxSceneBuilder
} // namespace AZ
@@ -0,0 +1,184 @@
/*
* 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/RTTI/RTTI.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class Scene;
}
namespace DataTypes
{
class IGraphObject;
}
namespace Events
{
class ImportEventContext;
}
namespace FbxSceneBuilder
{
class RenamedNodesMap;
// ImportContext
// Base structure containing common data needed for all import contexts
struct ImportContext
: public Events::ICallContext
{
AZ_RTTI(ImportContext, "{68E546D5-9B79-4293-AD37-4A4BA688892F}", Events::ICallContext);
ImportContext(Containers::Scene& scene, Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap);
ImportContext(Containers::Scene& scene, RenamedNodesMap& nodeNameMap);
Containers::Scene& m_scene;
Containers::SceneGraph::NodeIndex m_currentGraphPosition;
RenamedNodesMap& m_nodeNameMap; // Map of the nodes that have received a new name.
};
// NodeEncounteredContext
// Context pushed to indicate that a new Node has been found and any
// importers that have means to process the contained data should do so
// Member Variables:
// m_createdData - out container that importers must add their created data
// to.
struct NodeEncounteredContext
: public ImportContext
{
AZ_RTTI(NodeEncounteredContext, "{40C31D76-7101-4ACD-8849-0D6D0AF62855}", ImportContext);
NodeEncounteredContext(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap);
NodeEncounteredContext(Events::ImportEventContext& parent,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap);
AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>> m_createdData;
};
// SceneDataPopulatedContextBase
// Context pushed to indicate that a piece of scene data has been fully
// processed and any importers that wish to place it within the scene graph
// may now do so.
// Member Variables:
// m_graphData - the piece of data that should be inserted in the graph
// m_dataName - the name that should be used as the basis for the scene node
// name
struct SceneDataPopulatedContextBase
: public ImportContext
{
AZ_RTTI(SceneDataPopulatedContextBase, "{5F4CE8D2-EEAC-49F7-8065-0B6372162D6F}", ImportContext);
SceneDataPopulatedContextBase(NodeEncounteredContext& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const AZStd::string& dataName);
SceneDataPopulatedContextBase(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition,
RenamedNodesMap& nodeNameMap,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData, const AZStd::string& dataName);
const AZStd::shared_ptr<DataTypes::IGraphObject>& m_graphData;
const AZStd::string m_dataName;
};
// SceneNodeAppendedContextBase
// Context pushed to indicate that data has been added to the scene graph.
// Generally created due to the insertion of a node during SceneDataPopulatedContextBase
// processing.
struct SceneNodeAppendedContextBase
: public ImportContext
{
AZ_RTTI(SceneNodeAppendedContextBase, "{0A69FB6C-2B1B-46E7-AEC3-C4B8ABBFDD69}", ImportContext);
SceneNodeAppendedContextBase(SceneDataPopulatedContextBase& parent, Containers::SceneGraph::NodeIndex newIndex);
SceneNodeAppendedContextBase(Containers::Scene& scene,
Containers::SceneGraph::NodeIndex currentGraphPosition, RenamedNodesMap& nodeNameMap);
};
// SceneAttributeDataPopulatedContextBase
// Context pushed to indicate that attribute data has been found and processed
struct SceneAttributeDataPopulatedContextBase
: public ImportContext
{
AZ_RTTI(SceneAttributeDataPopulatedContextBase, "{DA133E14-0770-435B-9A4E-38679367F56C}", ImportContext);
SceneAttributeDataPopulatedContextBase(SceneNodeAppendedContextBase& parent,
const AZStd::shared_ptr<DataTypes::IGraphObject>& nodeData,
const Containers::SceneGraph::NodeIndex attributeNodeIndex, const AZStd::string& dataName);
const AZStd::shared_ptr<DataTypes::IGraphObject>& m_graphData;
const AZStd::string m_dataName;
};
// SceneAttributeNodeAppendedContextBase
// Context pushed to indicate that an attribute node has been added to the scene graph
struct SceneAttributeNodeAppendedContextBase
: public ImportContext
{
AZ_RTTI(SceneAttributeNodeAppendedContextBase, "{8A382A1E-CFE7-47D2-BA5B-CFDF1FB9F03D}", ImportContext);
SceneAttributeNodeAppendedContextBase(SceneAttributeDataPopulatedContextBase& parent,
Containers::SceneGraph::NodeIndex newIndex);
};
// SceneNodeAddedAttributesContextBase
// Context pushed to indicate that all attribute processors have completed their
// work for a specific data node.
struct SceneNodeAddedAttributesContextBase
: public ImportContext
{
AZ_RTTI(SceneNodeAddedAttributesContextBase, "{65B97E48-16A0-4BBD-B364-CFDA9E3600B6}", ImportContext);
SceneNodeAddedAttributesContextBase(SceneNodeAppendedContextBase& parent);
};
// SceneNodeFinalizeContextBase
// Context pushed last after all other contexts for a scene node to allow any
// post-processing needed for an importer.
struct SceneNodeFinalizeContextBase
: public ImportContext
{
AZ_RTTI(SceneNodeFinalizeContextBase, "{F2C7D1BC-8065-423E-9212-241EB426A2BB}", ImportContext);
SceneNodeFinalizeContextBase(SceneNodeAddedAttributesContextBase& parent);
};
// FinalizeSceneContextBase
// Context pushed after the scene has been fully created. This can be used to finalize pending work
// such as resolving named links.
struct FinalizeSceneContextBase
: public ImportContext
{
AZ_RTTI(FinalizeSceneContextBase, "{91C54F51-9B4D-4C61-956C-9D530725D737}", ImportContext);
FinalizeSceneContextBase(Containers::Scene& scene, RenamedNodesMap& nodeNameMap);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,119 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpColorStreamImporter::m_defaultNodeName = "Col";
AssImpColorStreamImporter::AssImpColorStreamImporter()
{
BindToCall(&AssImpColorStreamImporter::ImportColorStreams);
}
void AssImpColorStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpColorStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpColorStreamImporter::ImportColorStreams(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", m_defaultNodeName);
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(
parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct color stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
if (sdkMeshIndex < 0)
{
AZ_Error(
Utilities::ErrorWindow,
false,
"Tried to construct color stream attribute for invalid or non-mesh parent data, mesh index is missing");
return Events::ProcessingResult::Failure;
}
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
Events::ProcessingResultCombiner combinedVertexColorResults;
for (int colorSetIndex = 0; colorSetIndex < mesh->GetNumColorChannels(); ++colorSetIndex)
{
AZStd::shared_ptr<SceneData::GraphData::MeshVertexColorData> vertexColors =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexColorData>();
vertexColors->ReserveContainerSpace(vertexCount);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
AZ::SceneAPI::DataTypes::Color vertexColor(
AssImpSDKWrapper::AssImpTypeConverter::ToColor(mesh->mColors[colorSetIndex][v]));
vertexColors->AppendColor(vertexColor);
}
AZStd::string nodeName(AZStd::string::format("%s%d",m_defaultNodeName,colorSetIndex));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult colorMapResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, vertexColors, newIndex, nodeName.c_str());
colorMapResults = Events::Process(dataPopulated);
if (colorMapResults != Events::ProcessingResult::Failure)
{
colorMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedVertexColorResults += colorMapResults;
}
return combinedVertexColorResults.GetResult();
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,40 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpColorStreamImporter : public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpColorStreamImporter, "{071F4764-F3B0-438A-9CB7-19A1248F3B54}", SceneCore::LoadingComponent);
AssImpColorStreamImporter();
~AssImpColorStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportColorStreams(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,140 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpMaterialWrapper.h>
#include <SceneAPI/SceneData/GraphData/MaterialData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Events/ProcessingResult.h>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpMaterialImporter::AssImpMaterialImporter()
{
BindToCall(&AssImpMaterialImporter::ImportMaterials);
}
void AssImpMaterialImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpMaterialImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpMaterialImporter::ImportMaterials(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Material");
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedMaterialImportResults;
for (int idx = 0; idx < context.m_sourceNode.m_assImpNode->mNumMeshes; ++idx)
{
int meshIndex = context.m_sourceNode.m_assImpNode->mMeshes[idx];
aiMesh* assImpMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshIndex];
AZ_Assert(assImpMesh, "Asset Importer Mesh should not be null.");
int materialIndex = assImpMesh->mMaterialIndex;
AZ_TraceContext("Material Index", materialIndex);
AZStd::unordered_map<int, AZStd::shared_ptr<SceneData::GraphData::MaterialData>> materialMap;
auto matFound = materialMap.find(materialIndex);
AZStd::shared_ptr<SceneData::GraphData::MaterialData> material;
AZStd::string materialName;
if (matFound == materialMap.end())
{
std::shared_ptr<AssImpSDKWrapper::AssImpMaterialWrapper> assImpMaterial =
std::shared_ptr<AssImpSDKWrapper::AssImpMaterialWrapper>(new AssImpSDKWrapper::AssImpMaterialWrapper(context.m_sourceScene.GetAssImpScene()->mMaterials[materialIndex]));
materialName = assImpMaterial->GetName().c_str();
RenamedNodesMap::SanitizeNodeName(materialName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "Material");
AZ_TraceContext("Material Name", materialName);
material = AZStd::make_shared<SceneData::GraphData::MaterialData>();
material->SetMaterialName(assImpMaterial->GetName());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Diffuse).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Specular,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Specular).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Bump,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Bump).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Normal,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Normal).c_str());
material->SetUniqueId(assImpMaterial->GetUniqueId());
material->SetDiffuseColor(assImpMaterial->GetDiffuseColor());
material->SetSpecularColor(assImpMaterial->GetSpecularColor());
material->SetEmissiveColor(assImpMaterial->GetEmissiveColor());
material->SetShininess(assImpMaterial->GetShininess());
AZ_Assert(material, "Failed to allocate scene material data.");
if (!material)
{
combinedMaterialImportResults += Events::ProcessingResult::Failure;
continue;
}
materialMap[materialIndex] = material;
}
else
{
material = matFound->second;
materialName = material.get()->GetMaterialName();
}
Events::ProcessingResult materialResult;
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, materialName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedMaterialImportResults += Events::ProcessingResult::Failure;
continue;
}
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, material, newIndex, materialName);
materialResult = Events::Process(dataPopulated);
if (materialResult != Events::ProcessingResult::Failure)
{
materialResult = SceneAPI::FbxSceneBuilder::AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedMaterialImportResults += materialResult;
}
return combinedMaterialImportResults.GetResult();
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpMaterialImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpMaterialImporter, "{CD936FA9-17B8-40B9-AA3C-5F593BEFFC94}", SceneCore::LoadingComponent);
AssImpMaterialImporter();
~AssImpMaterialImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMaterials(AssImpSceneNodeAppendedContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,126 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpMeshImporter::AssImpMeshImporter()
{
BindToCall(&AssImpMeshImporter::ImportMesh);
}
void AssImpMeshImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpMeshImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpMeshImporter::ImportMesh(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Mesh");
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
int lyMeshIndex = 0;
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
for (int m = 0; m < currentNode->mNumMeshes; ++m)
{
AZStd::shared_ptr<SceneData::GraphData::MeshData> newMesh =
AZStd::make_shared<SceneData::GraphData::MeshData>();
newMesh->SetUnitSizeInMeters(context.m_sourceSceneSystem.GetUnitSizeInMeters());
newMesh->SetOriginalUnitSizeInMeters(context.m_sourceSceneSystem.GetOriginalUnitSizeInMeters());
newMesh->SetSdkMeshIndex(m);
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
// Lumberyard materials are created in order based on mesh references in the scene
if (assImpMatIndexToLYIndex.find(mesh->mMaterialIndex) == assImpMatIndexToLYIndex.end())
{
assImpMatIndexToLYIndex.insert(AZStd::pair<int, int>(mesh->mMaterialIndex, lyMeshIndex++));
}
for (int vertIdx = 0; vertIdx < mesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(
mesh->mVertices[vertIdx].x,
mesh->mVertices[vertIdx].y,
mesh->mVertices[vertIdx].z);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(vertex);
context.m_sourceSceneSystem.ConvertUnit(vertex);
newMesh->AddPosition(vertex);
if (mesh->HasNormals())
{
AZ::Vector3 normal(
mesh->mNormals[vertIdx].x,
mesh->mNormals[vertIdx].y,
mesh->mNormals[vertIdx].z);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(normal);
normal.NormalizeSafe();
newMesh->AddNormal(normal);
}
}
for (int faceIdx = 0; faceIdx < mesh->mNumFaces; ++faceIdx)
{
aiFace face = mesh->mFaces[faceIdx];
AZ::SceneAPI::DataTypes::IMeshData::Face meshFace;
if (face.mNumIndices != 3)
{
// AssImp should have triangulated everything, so if this happens then someone has
// probably changed AssImp's import settings. The engine only supports triangles.
AZ_Error(Utilities::ErrorWindow, false, "Mesh has a face with %d vertices, only 3 vertices are supported per face.");
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
meshFace.vertexIndex[idx] = face.mIndices[idx];
}
newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
}
context.m_createdData.push_back(std::move(newMesh));
}
return Events::ProcessingResult::Success;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpMeshImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpMeshImporter, "{41611339-1D32-474A-A6A4-25CE4430AAFB}", SceneCore::LoadingComponent);
AssImpMeshImporter();
~AssImpMeshImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMesh(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // 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 <SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/TransformData.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpTransformImporter::s_transformNodeName = "transform";
AssImpTransformImporter::AssImpTransformImporter()
{
BindToCall(&AssImpTransformImporter::ImportTransform);
}
void AssImpTransformImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpTransformImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "transform");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(context.m_sourceNode.GetAssImpNode()->mTransformation);
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
AZStd::shared_ptr<SceneData::GraphData::TransformData> transformData =
AZStd::make_shared<SceneData::GraphData::TransformData>(localTransform);
AZ_Error(SceneAPI::Utilities::ErrorWindow, transformData, "Failed to allocate transform data.");
if (!transformData)
{
return Events::ProcessingResult::Failure;
}
// If it is non-endpoint data populated node, add a transform attribute
if (context.m_scene.GetGraph().HasNodeContent(context.m_currentGraphPosition))
{
if (!context.m_scene.GetGraph().IsNodeEndPoint(context.m_currentGraphPosition))
{
AZStd::string nodeName = s_transformNodeName;
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZ_TraceContext("Transform node name", nodeName);
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Error(SceneAPI::Utilities::ErrorWindow, newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
return Events::ProcessingResult::Failure;
}
Events::ProcessingResult transformAttributeResult;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, transformData, newIndex, nodeName);
transformAttributeResult = Events::Process(dataPopulated);
if (transformAttributeResult != Events::ProcessingResult::Failure)
{
transformAttributeResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
return transformAttributeResult;
}
}
else
{
bool addedData = context.m_scene.GetGraph().SetContent(
context.m_currentGraphPosition,
transformData);
AZ_Error(SceneAPI::Utilities::ErrorWindow, addedData, "Failed to add node data");
return addedData ? Events::ProcessingResult::Success : Events::ProcessingResult::Failure;
}
return Events::ProcessingResult::Ignored;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,40 @@
/*
* 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/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpTransformImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpTransformImporter, "{A7494C53-5822-40EF-9B60-B1FF09FBFA59}", SceneCore::LoadingComponent);
AssImpTransformImporter();
~AssImpTransformImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportTransform(AssImpSceneNodeAppendedContext& context);
static const char* s_transformNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,117 @@
/*
* 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/Math/Vector2.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpUvMapImporter::m_defaultNodeName = "UVMap";
AssImpUvMapImporter::AssImpUvMapImporter()
{
BindToCall(&AssImpUvMapImporter::ImportUvMaps);
}
void AssImpUvMapImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpUvMapImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpUvMapImporter::ImportUvMaps(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", m_defaultNodeName);
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData =
azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
AZ_Assert(sdkMeshIndex >= 0,
"Tried to construct uv stream attribute for invalid or non-mesh parent data, mesh index is missing");
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->mTextureCoords[0])
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedUvMapResults;
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
uvMap->ReserveContainerSpace(vertexCount);
uvMap->SetCustomName(m_defaultNodeName);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
AZ::Vector2 vertexUV(
mesh->mTextureCoords[0][v].x,
mesh->mTextureCoords[0][v].y);
uvMap->AppendUV(vertexUV);
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
Events::ProcessingResult uvMapResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, m_defaultNodeName);
uvMapResults = Events::Process(dataPopulated);
if (uvMapResults != Events::ProcessingResult::Failure)
{
uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedUvMapResults += uvMapResults;
return combinedUvMapResults.GetResult();
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,42 @@
/*
* 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/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpUvMapImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpUvMapImporter, "{BF02F231-848B-4CDB-9B11-55EEE15CFAA6}", SceneCore::LoadingComponent);
AssImpUvMapImporter();
~AssImpUvMapImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportUvMaps(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,216 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxTimeSpanWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimLayerWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimCurveNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimCurveWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* FbxAnimationImporter::s_animationNodeName = "animation";
const FbxSDKWrapper::FbxTimeWrapper::TimeMode FbxAnimationImporter::s_defaultTimeMode =
FbxSDKWrapper::FbxTimeWrapper::frames30;
FbxAnimationImporter::FbxAnimationImporter()
{
BindToCall(&FbxAnimationImporter::ImportAnimation);
}
void FbxAnimationImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxAnimationImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxAnimationImporter::ImportAnimation(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Animation");
// Add check for animation layers at the scene level.
if (context.m_sourceScene.GetAnimationStackCount() <= 0)
{
return Events::ProcessingResult::Ignored;
}
if (context.m_sourceNode.IsMesh())
{
return ImportBlendShapeAnimation(context);
}
if (!context.m_sourceNode.IsBone())
{
return Events::ProcessingResult::Ignored;
}
AZStd::string nodeName = s_animationNodeName;
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZ_TraceContext("Animation node name", nodeName);
auto animStackWrapper = context.m_sourceScene.GetAnimationStackAt(0);
const FbxSDKWrapper::FbxTimeWrapper startTime = animStackWrapper->GetLocalTimeSpan().GetStartTime();
const double frameRate = startTime.GetFrameRate();
if (frameRate == 0.0)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Scene has a 0 framerate. Animation cannot be processed without timing information.");
return Events::ProcessingResult::Failure;
}
const int64_t startFrame = startTime.GetFrameCount();
const int64_t numFrames = animStackWrapper->GetLocalTimeSpan().GetNumFrames();
AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::AnimationData>();
createdAnimationData->ReserveKeyFrames(numFrames);
createdAnimationData->SetTimeStepBetweenFrames(1.0 / frameRate);
{
FbxSDKWrapper::FbxTimeWrapper currTime = startTime;
for (int64_t currFrame = startFrame; currFrame < startFrame + numFrames; currFrame++)
{
currTime.SetFrame(currFrame);
SceneAPI::DataTypes::MatrixType animTransform = context.m_sourceNode.EvaluateLocalTransform(currTime);
context.m_sourceSceneSystem.SwapTransformForUpAxis(animTransform);
context.m_sourceSceneSystem.ConvertBoneUnit(animTransform);
createdAnimationData->AddKeyFrame(animTransform);
}
AZ_Assert(createdAnimationData->GetKeyFrameCount() == numFrames, "The imported animation data created does not have the same number of keyframes as the FBX data.");
}
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, nodeName.c_str(), AZStd::move(createdAnimationData));
context.m_scene.GetGraph().MakeEndPoint(addNode);
return Events::ProcessingResult::Success;
}
Events::ProcessingResult FbxAnimationImporter::ImportBlendShapeAnimation(SceneNodeAppendedContext& context)
{
FbxNode * node = context.m_sourceNode.GetFbxNode();
FbxMesh * pMesh = node->GetMesh();
if (!pMesh)
{
return Events::ProcessingResult::Ignored;
}
int deformerCount = pMesh->GetDeformerCount(FbxDeformer::eBlendShape);
int blendShapeIndex = -1;
AZStd::string nodeName;
AZStd::string animNodeName;
for (int deformerIndex = 0; deformerIndex < deformerCount; ++deformerIndex)
{
//we are assuming 1 anim stack (single animation clip export)
const FbxBlendShape* pDeformer = (FbxBlendShape*)pMesh->GetDeformer(deformerIndex, FbxDeformer::eBlendShape);
if (!pDeformer)
{
continue;
}
blendShapeIndex++;
int blendShapeChannelCount = pDeformer->GetBlendShapeChannelCount();
int stackCount = context.m_sourceScene.GetAnimationStackCount();
auto animStackWrapper = context.m_sourceScene.GetAnimationStackAt(0);
const FbxSDKWrapper::FbxTimeWrapper startTime = animStackWrapper->GetLocalTimeSpan().GetStartTime();
const double frameRate = startTime.GetFrameRate();
if (frameRate == 0.0)
{
AZ_TracePrintf("Animation_Warning", "Scene has a 0 framerate. Animation cannot be processed without timing information.");
return Events::ProcessingResult::Failure;
}
const int64_t startFrame = startTime.GetFrameCount();
const int64_t numFrames = animStackWrapper->GetLocalTimeSpan().GetNumFrames();
const int layerCount = animStackWrapper->GetAnimationLayerCount();
for (int blendShapeChannelIdx = 0; blendShapeChannelIdx < blendShapeChannelCount; ++blendShapeChannelIdx)
{
const FbxBlendShapeChannel* pChannel = pDeformer->GetBlendShapeChannel(blendShapeChannelIdx);
if (!pChannel)
{
continue;
}
for (int layerIndex = 0; layerIndex < layerCount; layerIndex++)
{
FbxAnimLayer* animationLayer = animStackWrapper->GetAnimationLayerAt(layerIndex)->GetFbxLayer();
FbxAnimCurve* animCurve = pMesh->GetShapeChannel(blendShapeIndex, blendShapeChannelIdx, animationLayer);
if (!animCurve)
{
continue;
}
AZStd::shared_ptr<FbxSDKWrapper::FbxAnimCurveWrapper> animCurveWrapper = AZStd::make_shared<FbxSDKWrapper::FbxAnimCurveWrapper>(animCurve);
AZStd::shared_ptr<SceneData::GraphData::BlendShapeAnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::BlendShapeAnimationData>();
createdAnimationData->ReserveKeyFrames(numFrames);
createdAnimationData->SetTimeStepBetweenFrames(1.0 / frameRate);
{
FbxSDKWrapper::FbxTimeWrapper currTime = startTime;
for (int64_t currFrame = startFrame; currFrame < startFrame + numFrames; currFrame++)
{
currTime.SetFrame(currFrame);
//weight values from FBX are range 0 - 100
float sampleValue = animCurveWrapper->Evaluate(currTime) / 100.0f;
createdAnimationData->AddKeyFrame(sampleValue);
}
AZ_Assert(createdAnimationData->GetKeyFrameCount() == numFrames, "Imported animation blend data does not contain the same number of keyframes as the source FBX data.")
}
nodeName = pChannel->GetName();
const size_t dotIndex = nodeName.find_last_of('.');
nodeName = nodeName.substr(dotIndex + 1);
createdAnimationData->SetBlendShapeName(nodeName.c_str());
animNodeName = AZStd::string::format("%s_%s", s_animationNodeName, nodeName.c_str());
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, animNodeName.c_str(), AZStd::move(createdAnimationData));
context.m_scene.GetGraph().MakeEndPoint(addNode);
}
}
}
return Events::ProcessingResult::Success;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,46 @@
/*
* 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 <fbxsdk.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSDKWrapper/FbxTimeWrapper.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxAnimationImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxAnimationImporter, "{26ABDA62-9DB7-4B4D-961D-44B5F5F56808}", SceneCore::LoadingComponent);
FbxAnimationImporter();
~FbxAnimationImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportAnimation(SceneNodeAppendedContext& context);
Events::ProcessingResult ImportBlendShapeAnimation(SceneNodeAppendedContext& context);
protected:
static const char* s_animationNodeName;
static const FbxSDKWrapper::FbxTimeWrapper::TimeMode s_defaultTimeMode;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // 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 <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxVertexBitangentWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxBitangentStreamImporter::FbxBitangentStreamImporter()
{
BindToCall(&FbxBitangentStreamImporter::ImportBitangents);
}
void FbxBitangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxBitangentStreamImporter::ImportBitangents(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Bitangents");
std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> fbxMesh = context.m_sourceNode.GetMesh();
if (!fbxMesh)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedStreamResults;
const int numBitangentSets = context.m_sourceNode.GetMesh()->GetElementBitangentCount();
for (int elementIndex = 0; elementIndex < numBitangentSets; ++elementIndex)
{
AZ_TraceContext("Bitangent set index", elementIndex);
FbxSDKWrapper::FbxVertexBitangentWrapper fbxVertexBitangents = fbxMesh->GetElementBitangent(elementIndex);
if (!fbxVertexBitangents.IsValid())
{
AZ_TracePrintf(Utilities::WarningWindow, "Invalid bitangent set found, ignoring");
continue;
}
const AZStd::string originalNodeName = AZStd::string::format("BitangentSet_Fbx_%d", elementIndex);
const AZStd::string nodeName = AZ::SceneAPI::DataTypes::Utilities::CreateUniqueName<SceneData::GraphData::MeshVertexBitangentData>(originalNodeName, context.m_scene.GetManifest());
AZ_TraceContext("Bitangent Set Name", nodeName);
if (originalNodeName != nodeName)
{
AZ_TracePrintf(Utilities::WarningWindow, "Bitangent set '%s' has been renamed to '%s' because the name was already in use.", originalNodeName.c_str(), nodeName.c_str());
}
AZStd::shared_ptr<DataTypes::IGraphObject> parentData = context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()), "Tried to construct bitangent set attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const size_t vertexCount = parentMeshData->GetVertexCount();
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> bitangentStream = BuildVertexBitangentData(fbxVertexBitangents, vertexCount, fbxMesh);
AZ_Assert(bitangentStream, "Failed to allocate bitangent data for scene graph.");
if (!bitangentStream)
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
bitangentStream->SetBitangentSetIndex(elementIndex);
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
Containers::SceneGraph::NodeIndex newIndex = context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult streamResults;
SceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, nodeName);
streamResults = Events::Process(dataPopulated);
if (streamResults != Events::ProcessingResult::Failure)
{
streamResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedStreamResults += streamResults;
}
return combinedStreamResults.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> FbxBitangentStreamImporter::BuildVertexBitangentData(const FbxSDKWrapper::FbxVertexBitangentWrapper& bitangents, size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh)
{
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> bitangentData = AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexBitangentData>();
bitangentData->ReserveContainerSpace(vertexCount);
const int fbxPolygonCount = fbxMesh->GetPolygonCount();
const int* const fbxPolygonVertices = fbxMesh->GetPolygonVertices();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = fbxMesh->GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
const int fbxVertexStartIndex = fbxMesh->GetPolygonVertexIndex(fbxPolygonIndex);
for (int index = 0; index < fbxPolygonVertexCount; ++index)
{
const int fbxPolygonVertexIndex = fbxVertexStartIndex + index;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
const Vector3 bitangent = bitangents.GetElementAt(fbxPolygonIndex, fbxPolygonVertexIndex, fbxControlPointIndex);
bitangentData->AppendBitangent(bitangent);
}
}
if (bitangentData->GetCount() != vertexCount)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Vertex count (%i) doesn't match the number of entries for the bitangent stream %s (%i)", vertexCount, bitangents.GetName(), bitangentData->GetCount());
return nullptr;
}
return bitangentData;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,58 @@
/*
* 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/smart_ptr/shared_ptr.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneData
{
namespace GraphData
{
class MeshVertexBitangentData;
}
}
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
class FbxVertexBitangentWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxBitangentStreamImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxBitangentStreamImporter, "{B68F90E6-9F9D-448F-A874-CABA9F67E5FD}", SceneCore::LoadingComponent);
FbxBitangentStreamImporter();
~FbxBitangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBitangents(SceneNodeAppendedContext& context);
protected:
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> BuildVertexBitangentData(const FbxSDKWrapper::FbxVertexBitangentWrapper& bitangents,
size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,128 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/FbxMeshImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxBlendShapeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxBlendShapeChannelWrapper.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxBlendShapeImporter::FbxBlendShapeImporter()
{
BindToCall(&FbxBlendShapeImporter::ImportBlendShapes);
}
void FbxBlendShapeImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxBlendShapeImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxBlendShapeImporter::ImportBlendShapes(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Blend Shapes");
if (!IsSkinnedMesh(context.m_sourceNode))
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedBlendShapeResult;
const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> sourceMesh = context.m_sourceNode.GetMesh();
int blendShapeDeformerCount = sourceMesh->GetDeformerCount(FbxDeformer::eBlendShape);
for (int deformerIndex = 0; deformerIndex < blendShapeDeformerCount; ++deformerIndex)
{
AZ_TraceContext("Deformer Index", deformerIndex);
AZStd::shared_ptr<const FbxSDKWrapper::FbxBlendShapeWrapper> fbxBlendShape = sourceMesh->GetBlendShape(deformerIndex);
if (!fbxBlendShape)
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unable to extract BlendShape Deformer at index %d", deformerIndex);
return Events::ProcessingResult::Failure;
}
int blendShapeChannelCount = fbxBlendShape->GetBlendShapeChannelCount();
for (int channelIndex = 0; channelIndex < blendShapeChannelCount; ++channelIndex)
{
//extract the mesh and build a blendshape data object.
AZStd::shared_ptr<const FbxSDKWrapper::FbxBlendShapeChannelWrapper> blendShapeChannel = fbxBlendShape->GetBlendShapeChannel(channelIndex);
int shapeCount = blendShapeChannel->GetTargetShapeCount();
//We do not support percentage blends at this time. Take only the final shape.
AZStd::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper> mesh = blendShapeChannel->GetTargetShape(shapeCount - 1);
if (mesh)
{
//Maya is creating node names of the form cone_skin_blendShapeNode.cone_squash during export.
//We need the name after the period for our naming purposes.
AZStd::string nodeName(blendShapeChannel->GetName());
size_t dotIndex = nodeName.rfind('.');
if (dotIndex != AZStd::string::npos)
{
nodeName.erase(0, dotIndex + 1);
}
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "BlendShape");
AZ_TraceContext("Blend shape name", nodeName);
AZStd::shared_ptr<SceneData::GraphData::BlendShapeData> blendShapeData =
AZStd::make_shared<SceneData::GraphData::BlendShapeData>();
BuildSceneBlendShapeFromFbxBlendShape(blendShapeData, mesh, context.m_sourceSceneSystem);
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult blendShapeResult;
SceneAttributeDataPopulatedContext dataPopulated(context, blendShapeData, newIndex, nodeName);
blendShapeResult = Events::Process(dataPopulated);
if (blendShapeResult != Events::ProcessingResult::Failure)
{
blendShapeResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedBlendShapeResult += blendShapeResult;
}
else
{
AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Unable to extract blendshape mesh for node '%s' from BlendShapeChannel %d", sourceMesh->GetName(), channelIndex);
combinedBlendShapeResult += Events::ProcessingResult::Failure;
}
}
}
return combinedBlendShapeResult.GetResult();
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxBlendShapeImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxBlendShapeImporter, "{3E733F1B-B4A1-4F6F-B2EE-A1C501830E91}", SceneCore::LoadingComponent);
FbxBlendShapeImporter();
~FbxBlendShapeImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBlendShapes(SceneNodeAppendedContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,84 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/RootBoneData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxBoneImporter::FbxBoneImporter()
{
BindToCall(&FbxBoneImporter::ImportBone);
}
void FbxBoneImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxBoneImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxBoneImporter::ImportBone(FbxNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Bone");
if (!context.m_sourceNode.IsBone())
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<DataTypes::IGraphObject> boneGraphData;
// If the current scene node (our eventual parent) contains bone data, we are not a root bone
AZStd::shared_ptr<SceneData::GraphData::BoneData> createdBoneData;
if (NodeHasAncestorOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition,
DataTypes::IBoneData::TYPEINFO_Uuid()))
{
createdBoneData = AZStd::make_shared<SceneData::GraphData::BoneData>();
}
else
{
createdBoneData = AZStd::make_shared<SceneData::GraphData::RootBoneData>();
}
SceneAPI::DataTypes::MatrixType globalTransform = context.m_sourceNode.EvaluateGlobalTransform();
context.m_sourceSceneSystem.SwapTransformForUpAxis(globalTransform);
context.m_sourceSceneSystem.ConvertBoneUnit(globalTransform);
createdBoneData->SetWorldTransform(globalTransform);
context.m_createdData.push_back(AZStd::move(createdBoneData));
return Events::ProcessingResult::Success;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxBoneImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxBoneImporter, "{3575F356-BC2F-45F6-B57C-9C590ED54995}", SceneCore::LoadingComponent);
FbxBoneImporter();
~FbxBoneImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBone(FbxNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,163 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxVertexColorWrapper.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxColorStreamImporter::FbxColorStreamImporter()
{
BindToCall(&FbxColorStreamImporter::ImportColorStreams);
}
void FbxColorStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxColorStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxColorStreamImporter::ImportColorStreams(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Color Stream");
std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> fbxMesh =
context.m_sourceNode.GetMesh();
if (!fbxMesh)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedVertexColorResults;
for (int i = 0; i < context.m_sourceNode.GetMesh()->GetElementVertexColorCount(); ++i)
{
AZ_TraceContext("Vertex color index", i);
FbxSDKWrapper::FbxVertexColorWrapper fbxVertexColors =
fbxMesh->GetElementVertexColor(i);
if (!fbxVertexColors.IsValid())
{
AZ_TracePrintf(Utilities::WarningWindow, "Invalid vertex color channel found, ignoring");
continue;
}
AZStd::string nodeName = fbxVertexColors.GetName();
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "ColorStream");
AZ_TraceContext("Color Stream Name", nodeName);
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct color stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
combinedVertexColorResults += Events::ProcessingResult::Failure;
continue;
}
SceneData::GraphData::MeshData* parentMeshData =
azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
AZStd::shared_ptr<SceneData::GraphData::MeshVertexColorData> vertexColors =
BuildVertexColorData(fbxVertexColors, vertexCount, fbxMesh);
AZ_Assert(vertexColors, "Failed to allocate vertex color data for scene graph.");
if (!vertexColors)
{
combinedVertexColorResults += Events::ProcessingResult::Failure;
continue;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedVertexColorResults += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult vertexColorResult;
SceneAttributeDataPopulatedContext dataPopulated(context, vertexColors, newIndex, nodeName);
vertexColorResult = AddAttributeDataNodeWithContexts(dataPopulated);
combinedVertexColorResults += vertexColorResult;
}
return combinedVertexColorResults.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexColorData> FbxColorStreamImporter::BuildVertexColorData(const FbxSDKWrapper::FbxVertexColorWrapper& fbxVertexColors, size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh)
{
AZ_Assert(fbxVertexColors.IsValid(), "BuildVertexColorData was called for invalid color stream data.");
if (!fbxVertexColors.IsValid())
{
return nullptr;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexColorData> colorData = AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexColorData>();
colorData->ReserveContainerSpace(vertexCount);
colorData->SetCustomName(fbxVertexColors.GetName());
const int fbxPolygonCount = fbxMesh->GetPolygonCount();
const int* const fbxPolygonVertices = fbxMesh->GetPolygonVertices();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = fbxMesh->GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount < 3)
{
continue;
}
const int fbxVertexStartIndex = fbxMesh->GetPolygonVertexIndex(fbxPolygonIndex);
for (int polygonVertexIndex = 0; polygonVertexIndex < fbxPolygonVertexCount; ++polygonVertexIndex)
{
const int fbxPolygonVertexIndex = fbxVertexStartIndex + polygonVertexIndex;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
FbxSDKWrapper::FbxColorWrapper color = fbxVertexColors.GetElementAt(fbxPolygonIndex, fbxPolygonVertexIndex, fbxControlPointIndex);
colorData->AppendColor({color.GetR(), color.GetG(), color.GetB(), color.GetAlpha()});
}
}
if (colorData->GetCount() != vertexCount)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Vertex count (%i) doesn't match the number of entries for the vertex color stream %s (%i)",
vertexCount, fbxVertexColors.GetName(), colorData->GetCount());
return nullptr;
}
return colorData;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // 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/smart_ptr/shared_ptr.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneData
{
namespace GraphData
{
class MeshVertexColorData;
}
}
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
class FbxVertexColorWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxColorStreamImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxColorStreamImporter, "{96A25361-04FC-43EC-A443-C81E2E28F3BB}", SceneCore::LoadingComponent);
FbxColorStreamImporter();
~FbxColorStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportColorStreams(SceneNodeAppendedContext& context);
protected:
AZStd::shared_ptr<SceneData::GraphData::MeshVertexColorData> BuildVertexColorData(const FbxSDKWrapper::FbxVertexColorWrapper& fbxVertexColors, size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,507 @@
/*
* 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/Math/Transform.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxTypeConverter.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/MaterialData.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
#include <SceneAPI/SceneData/GraphData/TransformData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
static const float g_sceneUtilityEqualityEpsilon = 0.001f;
CoreProcessingResult AddDataNodeWithContexts(SceneDataPopulatedContextBase& dataPopulated)
{
AZ_TraceContext("Node Name", dataPopulated.m_dataName);
const char* nodeTypeName = dataPopulated.m_graphData ? dataPopulated.m_graphData->RTTI_GetTypeName() : "Null";
AZ_TraceContext("Node Type", (!nodeTypeName || nodeTypeName[0] == '\0' ? "Null" : nodeTypeName));
Events::ProcessingResultCombiner nodeResults;
nodeResults += Events::Process(dataPopulated);
dataPopulated.m_scene.GetGraph().SetContent(dataPopulated.m_currentGraphPosition,
AZStd::move(dataPopulated.m_graphData));
if (azrtti_istypeof<SceneDataPopulatedContext>(dataPopulated))
{
SceneDataPopulatedContext* dataPopulatedContext = azrtti_cast<SceneDataPopulatedContext*>(&dataPopulated);
SceneNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
SceneNodeAddedAttributesContext addedAttributes(nodeAppended);
nodeResults += Events::Process(addedAttributes);
SceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
AssImpSceneDataPopulatedContext* dataPopulatedContext = azrtti_cast<AssImpSceneDataPopulatedContext*>(&dataPopulated);
AssImpSceneNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
AssImpSceneNodeAddedAttributesContext addedAttributes(nodeAppended);
nodeResults += Events::Process(addedAttributes);
AssImpSceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#endif
return nodeResults.GetResult();
}
CoreProcessingResult AddAttributeDataNodeWithContexts(SceneAttributeDataPopulatedContextBase& dataPopulated)
{
AZ_TraceContext("Node Name", dataPopulated.m_dataName);
const char* nodeTypeName = dataPopulated.m_graphData ? dataPopulated.m_graphData->RTTI_GetTypeName() : "Null";
AZ_TraceContext("Node Type", (!nodeTypeName || nodeTypeName[0] == '\0' ? "Null" : nodeTypeName));
Events::ProcessingResultCombiner nodeResults;
nodeResults += Events::Process(dataPopulated);
dataPopulated.m_scene.GetGraph().MakeEndPoint(dataPopulated.m_currentGraphPosition);
dataPopulated.m_scene.GetGraph().SetContent(dataPopulated.m_currentGraphPosition,
AZStd::move(dataPopulated.m_graphData));
if (azrtti_istypeof<SceneAttributeDataPopulatedContext>(dataPopulated))
{
SceneAttributeDataPopulatedContext* dataPopulatedContext = azrtti_cast<SceneAttributeDataPopulatedContext*>(&dataPopulated);
SceneAttributeNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
AssImpSceneAttributeDataPopulatedContext* dataPopulatedContext = azrtti_cast<AssImpSceneAttributeDataPopulatedContext*>(&dataPopulated);
AssImpSceneAttributeNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
}
#endif
return nodeResults.GetResult();
}
bool AreSceneGraphsEqual(const CoreSceneGraph& lhsGraph, const CoreSceneGraph& rhsGraph)
{
auto lhsContentStorage = lhsGraph.GetContentStorage();
auto lhsNameStorage = lhsGraph.GetNameStorage();
auto lhsNameContentView = Containers::Views::MakePairView(lhsNameStorage, lhsContentStorage);
Containers::SceneGraph::NodeIndex lhsRootIndex = lhsGraph.GetRoot();
auto lhsDownwardView =
Containers::Views::MakeSceneGraphDownwardsView<Containers::Views::BreadthFirst>(lhsGraph, lhsRootIndex,
lhsNameContentView.begin(), true);
auto rhsContentStorage = rhsGraph.GetContentStorage();
auto rhsNameStorage = rhsGraph.GetNameStorage();
auto rhsNameContentView = Containers::Views::MakePairView(rhsNameStorage, rhsContentStorage);
Containers::SceneGraph::NodeIndex rhsRootIndex = rhsGraph.GetRoot();
auto rhsDownwardView =
Containers::Views::MakeSceneGraphDownwardsView<Containers::Views::BreadthFirst>(rhsGraph, rhsRootIndex,
rhsNameContentView.begin(), true);
auto lhsIt = lhsDownwardView.begin();
auto rhsIt = rhsDownwardView.begin();
while (lhsIt != lhsDownwardView.end() && rhsIt != rhsDownwardView.end())
{
if (!IsGraphDataEqual(lhsIt->second, rhsIt->second))
{
return false;
}
if (lhsIt->first != rhsIt->first)
{
return false;
}
++lhsIt;
++rhsIt;
}
return (lhsIt == lhsDownwardView.end() && rhsIt == rhsDownwardView.end());
}
bool operator==(const SceneData::GraphData::MeshData& lhs,
const SceneData::GraphData::MeshData& rhs)
{
if (lhs.GetVertexCount() != rhs.GetVertexCount())
{
return false;
}
if (lhs.HasNormalData() != rhs.HasNormalData())
{
return false;
}
if (lhs.GetFaceCount() != rhs.GetFaceCount())
{
return false;
}
bool hasNormals = lhs.HasNormalData();
unsigned int vertexCount = lhs.GetVertexCount();
for (unsigned int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
{
if (lhs.GetPosition(vertexIndex) != rhs.GetPosition(vertexIndex))
{
return false;
}
if (hasNormals && (lhs.GetNormal(vertexIndex) != rhs.GetNormal(vertexIndex)))
{
return false;
}
}
unsigned int faceCount = lhs.GetFaceCount();
for (unsigned int faceIndex = 0; faceIndex < faceCount; ++faceIndex)
{
if (lhs.GetFaceMaterialId(faceIndex) != rhs.GetFaceMaterialId(faceIndex))
{
return false;
}
if (lhs.GetFaceInfo(faceIndex) != rhs.GetFaceInfo(faceIndex))
{
return false;
}
}
return true;
}
bool operator==(const SceneData::GraphData::SkinWeightData& lhs,
const SceneData::GraphData::SkinWeightData& rhs)
{
if (lhs.GetVertexCount() != rhs.GetVertexCount())
{
return false;
}
if (lhs.GetBoneCount() != rhs.GetBoneCount())
{
return false;
}
size_t vertexCount = lhs.GetVertexCount();
for (size_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
{
if (lhs.GetLinkCount(vertexIndex) != rhs.GetLinkCount(vertexIndex))
{
return false;
}
size_t linkCount = lhs.GetLinkCount(vertexIndex);
for (size_t linkIndex = 0; linkIndex < linkCount; ++linkIndex)
{
const DataTypes::ISkinWeightData::Link lhsLink = lhs.GetLink(vertexIndex, linkIndex);
const DataTypes::ISkinWeightData::Link rhsLink = rhs.GetLink(vertexIndex, linkIndex);
if (lhsLink.boneId != rhsLink.boneId || !IsClose(lhsLink.weight, rhsLink.weight, g_sceneUtilityEqualityEpsilon))
{
return false;
}
if (lhs.GetBoneName(lhsLink.boneId) != rhs.GetBoneName(rhsLink.boneId))
{
return false;
}
}
}
return true;
}
bool operator==(const SceneData::GraphData::BoneData& lhs,
const SceneData::GraphData::BoneData& rhs)
{
return (lhs.GetWorldTransform() == rhs.GetWorldTransform());
}
bool operator==(const DataTypes::Color& lhs, const DataTypes::Color& rhs)
{
if (!IsClose(lhs.alpha, rhs.alpha, g_sceneUtilityEqualityEpsilon) ||
!IsClose(lhs.blue, rhs.blue, g_sceneUtilityEqualityEpsilon) ||
!IsClose(lhs.green, rhs.green, g_sceneUtilityEqualityEpsilon) ||
!IsClose(lhs.red, rhs.red, g_sceneUtilityEqualityEpsilon))
{
return false;
}
return true;
}
bool operator!=(const DataTypes::Color& lhs, const DataTypes::Color& rhs)
{
return !(lhs == rhs);
}
bool operator==(const SceneData::GraphData::MeshVertexColorData& lhs,
const SceneData::GraphData::MeshVertexColorData& rhs)
{
if (lhs.GetCount() != rhs.GetCount())
{
return false;
}
size_t colorCount = lhs.GetCount();
for (size_t colorIndex = 0; colorIndex < colorCount; ++colorIndex)
{
if (lhs.GetColor(colorIndex) != rhs.GetColor(colorIndex))
{
return false;
}
}
return true;
}
bool operator==(const SceneData::GraphData::MeshVertexUVData& lhs,
const SceneData::GraphData::MeshVertexUVData& rhs)
{
if (lhs.GetCount() != rhs.GetCount())
{
return false;
}
size_t uvCount = lhs.GetCount();
for (size_t uvIndex = 0; uvIndex < uvCount; ++uvIndex)
{
if (lhs.GetUV(uvIndex) != rhs.GetUV(uvIndex))
{
return false;
}
}
return true;
}
bool operator==(const SceneData::GraphData::MaterialData& lhs,
const SceneData::GraphData::MaterialData& rhs)
{
if (lhs.IsNoDraw() != rhs.IsNoDraw())
{
return false;
}
if (lhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse) !=
rhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse))
{
return false;
}
if (lhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Specular) !=
rhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Specular))
{
return false;
}
if (lhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Bump) !=
rhs.GetTexture(DataTypes::IMaterialData::TextureMapType::Bump))
{
return false;
}
return true;
}
bool operator==(const SceneData::GraphData::TransformData& lhs,
const SceneData::GraphData::TransformData& rhs)
{
return lhs.GetMatrix() == rhs.GetMatrix();
}
bool operator==(const SceneData::GraphData::AnimationData& lhs,
const SceneData::GraphData::AnimationData& rhs)
{
if (lhs.GetKeyFrameCount() != rhs.GetKeyFrameCount())
{
return false;
}
size_t keyFrameCount = lhs.GetKeyFrameCount();
for (size_t keyFrameIndex = 0; keyFrameIndex < keyFrameCount; ++keyFrameIndex)
{
if (lhs.GetKeyFrame(keyFrameIndex) != rhs.GetKeyFrame(keyFrameIndex))
{
return false;
}
}
return true;
}
bool IsGraphDataEqual(const AZStd::shared_ptr<const DataTypes::IGraphObject>& lhs,
const AZStd::shared_ptr<const DataTypes::IGraphObject>& rhs)
{
// If both are null, they are considered equal
if (!lhs && !rhs)
{
return true;
}
// If only one is null, they are considered not equal
if (!lhs || !rhs)
{
return false;
}
// If they have disparate types they are considered not equal
if (lhs->RTTI_GetType() != rhs->RTTI_GetType())
{
return false;
}
if (lhs->RTTI_IsTypeOf(SceneData::GraphData::BoneData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::BoneData* lhsBone =
azrtti_cast<const SceneData::GraphData::BoneData*>(lhs.get());
const SceneData::GraphData::BoneData* rhsBone =
azrtti_cast<const SceneData::GraphData::BoneData*>(rhs.get());
return (*lhsBone == *rhsBone);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::MeshData* lhsMesh =
azrtti_cast<const SceneData::GraphData::MeshData*>(lhs.get());
const SceneData::GraphData::MeshData* rhsMesh =
azrtti_cast<const SceneData::GraphData::MeshData*>(rhs.get());
return (*lhsMesh == *rhsMesh);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::SkinWeightData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::SkinWeightData* lhsSkinWeights =
azrtti_cast<const SceneData::GraphData::SkinWeightData*>(lhs.get());
const SceneData::GraphData::SkinWeightData* rhsSkinWeights =
azrtti_cast<const SceneData::GraphData::SkinWeightData*>(rhs.get());
return (*lhsSkinWeights == *rhsSkinWeights);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::MeshVertexColorData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::MeshVertexColorData* lhsColorData =
azrtti_cast<const SceneData::GraphData::MeshVertexColorData*>(lhs.get());
const SceneData::GraphData::MeshVertexColorData* rhsColorData =
azrtti_cast<const SceneData::GraphData::MeshVertexColorData*>(rhs.get());
return (*lhsColorData == *rhsColorData);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::MeshVertexUVData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::MeshVertexUVData* lhsUVData =
azrtti_cast<const SceneData::GraphData::MeshVertexUVData*>(lhs.get());
const SceneData::GraphData::MeshVertexUVData* rhsUVData =
azrtti_cast<const SceneData::GraphData::MeshVertexUVData*>(rhs.get());
return (*lhsUVData == *rhsUVData);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::MaterialData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::MaterialData* lhsMaterialData =
azrtti_cast<const SceneData::GraphData::MaterialData*>(lhs.get());
const SceneData::GraphData::MaterialData* rhsMaterialData =
azrtti_cast<const SceneData::GraphData::MaterialData*>(rhs.get());
return (*lhsMaterialData == *rhsMaterialData);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::TransformData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::TransformData* lhsTransform =
azrtti_cast<const SceneData::GraphData::TransformData*>(lhs.get());
const SceneData::GraphData::TransformData* rhsTransform =
azrtti_cast<const SceneData::GraphData::TransformData*>(rhs.get());
return (*lhsTransform == *rhsTransform);
}
else if (lhs->RTTI_IsTypeOf(SceneData::GraphData::AnimationData::TYPEINFO_Uuid()))
{
const SceneData::GraphData::AnimationData* lhsAnimation =
azrtti_cast<const SceneData::GraphData::AnimationData*>(lhs.get());
const SceneData::GraphData::AnimationData* rhsAnimation =
azrtti_cast<const SceneData::GraphData::AnimationData*>(rhs.get());
return (*lhsAnimation == *rhsAnimation);
}
return true;
}
bool GetBindPoseLocalTransform(const FbxSDKWrapper::FbxSceneWrapper& sceneWrapper,
FbxSDKWrapper::FbxNodeWrapper& nodeWrapper, SceneAPI::DataTypes::MatrixType& xf)
{
PoseList poseList;
FbxArray<int> nodeIndices;
FbxNode* node = nodeWrapper.GetFbxNode();
FbxScene* scene = sceneWrapper.GetFbxScene();
FbxMatrix nodeMatrix;
if (FbxPose::GetBindPoseContaining(scene, node, poseList, nodeIndices))
{
nodeMatrix = poseList[0]->GetMatrix(nodeIndices[0]);
}
else
{
return false;
}
// We are after the local transform of the node while fbx bind pose provides the global transform.
// To get the local transform, we multiply with the inverse of the parent's global transform.
FbxNode* parentNode = node->GetParent();
FbxMatrix parentMatrix;
if (parentNode)
{
poseList.Clear();
nodeIndices.Clear();
if (FbxPose::GetBindPoseContaining(scene, parentNode, poseList, nodeIndices))
{
parentMatrix = poseList[0]->GetMatrix(nodeIndices[0]);
}
else
{
parentMatrix = parentNode->EvaluateGlobalTransform();
}
}
FbxMatrix nodeLocalMatrix = parentMatrix.Inverse() * nodeMatrix;
xf = FbxSDKWrapper::FbxTypeConverter::ToTransform(nodeLocalMatrix);
return true;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,63 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
namespace AZ
{
struct Uuid;
namespace FbxSDKWrapper
{
class FbxNodeWrapper;
class FbxSceneWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
struct FbxImportContext;
using CoreScene = Containers::Scene;
using CoreSceneGraph = Containers::SceneGraph;
using CoreGraphNodeIndex = Containers::SceneGraph::NodeIndex;
using CoreProcessingResult = Events::ProcessingResult;
inline bool NodeIsOfType(const CoreSceneGraph& graph, CoreGraphNodeIndex nodeIndex, const AZ::Uuid& uuid);
inline bool NodeParentIsOfType(const CoreSceneGraph& graph, CoreGraphNodeIndex nodeIndex,
const AZ::Uuid& uuid);
inline bool NodeHasAncestorOfType(const CoreSceneGraph& graph, CoreGraphNodeIndex nodeIndex,
const AZ::Uuid& uuid);
inline bool IsSkinnedMesh(const FbxSDKWrapper::FbxNodeWrapper& sourceNode);
CoreProcessingResult AddDataNodeWithContexts(SceneDataPopulatedContextBase& dataContext);
CoreProcessingResult AddAttributeDataNodeWithContexts(SceneAttributeDataPopulatedContextBase& dataContext);
bool AreSceneGraphsEqual(const CoreSceneGraph& lhsGraph, const CoreSceneGraph& rhsGraph);
inline bool AreScenesEqual(const CoreScene& lhs, const CoreScene& rhs);
bool IsGraphDataEqual(const AZStd::shared_ptr<const DataTypes::IGraphObject>& lhs,
const AZStd::shared_ptr<const DataTypes::IGraphObject>& rhs);
// If the scene contains bindpose information for the node, returns true and sets "xf" to the local transform
// of the node in bindpose. Returns false if bindpose info is not available for the node.
bool GetBindPoseLocalTransform(const FbxSDKWrapper::FbxSceneWrapper& sceneWrapper,
FbxSDKWrapper::FbxNodeWrapper& nodeWrapper, DataTypes::MatrixType& xf);
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.inl>
@@ -0,0 +1,82 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSkinWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
bool NodeIsOfType(const CoreSceneGraph& sceneGraph, CoreGraphNodeIndex nodeIndex, const AZ::Uuid& uuid)
{
if (nodeIndex.IsValid() && sceneGraph.HasNodeContent(nodeIndex) &&
sceneGraph.GetNodeContent(nodeIndex)->RTTI_IsTypeOf(uuid))
{
return true;
}
else
{
return false;
}
}
bool NodeParentIsOfType(const CoreSceneGraph& sceneGraph, CoreGraphNodeIndex nodeIndex, const AZ::Uuid& uuid)
{
CoreGraphNodeIndex parentIndex = sceneGraph.GetNodeParent(nodeIndex);
return NodeIsOfType(sceneGraph, parentIndex, uuid);
}
bool NodeHasAncestorOfType(const CoreSceneGraph& sceneGraph, CoreGraphNodeIndex nodeIndex, const AZ::Uuid& uuid)
{
CoreGraphNodeIndex parentIndex = sceneGraph.GetNodeParent(nodeIndex);
while (parentIndex.IsValid())
{
if (NodeIsOfType(sceneGraph, parentIndex, uuid))
{
return true;
}
parentIndex = sceneGraph.GetNodeParent(parentIndex);
}
return false;
}
bool IsSkinnedMesh(const FbxSDKWrapper::FbxNodeWrapper& sourceNode)
{
const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> fbxMesh = sourceNode.GetMesh();
return (fbxMesh && (fbxMesh->GetDeformerCount(FbxDeformer::eSkin) > 0 || fbxMesh->GetDeformerCount(FbxDeformer::eBlendShape) > 0));
}
bool AreScenesEqual(const CoreScene& lhs, const CoreScene& rhs)
{
if (lhs.GetGraph().GetNodeCount() != rhs.GetGraph().GetNodeCount())
{
return false;
}
if (!AreSceneGraphsEqual(lhs.GetGraph(), rhs.GetGraph()))
{
return false;
}
return true;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,159 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxMaterialImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxMaterialWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/MaterialData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxMaterialImporter::FbxMaterialImporter()
{
BindToCall(&FbxMaterialImporter::ImportMaterials);
}
void FbxMaterialImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxMaterialImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxMaterialImporter::ImportMaterials(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Material");
if (!context.m_sourceNode.GetMesh())
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedMaterialImportResults;
for (int materialIndex = 0; materialIndex < context.m_sourceNode.GetMaterialCount(); ++materialIndex)
{
AZ_TraceContext("Material Index", materialIndex);
const std::shared_ptr<FbxSDKWrapper::FbxMaterialWrapper> fbxMaterial =
context.m_sourceNode.GetMaterial(materialIndex);
if (!fbxMaterial)
{
AZ_TracePrintf(Utilities::WarningWindow, "Invalid material data found, ignoring.");
continue;
}
AZStd::string materialName = fbxMaterial->GetName().c_str();
RenamedNodesMap::SanitizeNodeName(materialName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "Material");
AZ_TraceContext("Material Name", materialName);
AZStd::shared_ptr<SceneData::GraphData::MaterialData> materialData =
BuildMaterial(context.m_sourceNode, materialIndex);
AZ_Assert(materialData, "Failed to allocate scene material data.");
if (!materialData)
{
combinedMaterialImportResults += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult materialResult;
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, materialName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if(!newIndex.IsValid())
{
combinedMaterialImportResults += Events::ProcessingResult::Failure;
continue;
}
SceneAttributeDataPopulatedContext dataPopulated(context, materialData, newIndex, materialName);
materialResult = Events::Process(dataPopulated);
if (materialResult != Events::ProcessingResult::Failure)
{
materialResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedMaterialImportResults += materialResult;
}
return combinedMaterialImportResults.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::MaterialData> FbxMaterialImporter::BuildMaterial(FbxSDKWrapper::FbxNodeWrapper& node, int materialIndex) const
{
AZ_Assert(materialIndex < node.GetMaterialCount(), "Invalid material index (%i)", materialIndex);
const std::shared_ptr<FbxSDKWrapper::FbxMaterialWrapper> fbxMaterial = node.GetMaterial(materialIndex);
if (!fbxMaterial)
{
return nullptr;
}
AZStd::shared_ptr<SceneData::GraphData::MaterialData> material = AZStd::make_shared<SceneData::GraphData::MaterialData>();
material->SetMaterialName(fbxMaterial->GetName());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse,
fbxMaterial->GetTextureFileName(FbxSDKWrapper::FbxMaterialWrapper::MaterialMapType::Diffuse).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Specular,
fbxMaterial->GetTextureFileName(FbxSDKWrapper::FbxMaterialWrapper::MaterialMapType::Specular).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Bump,
fbxMaterial->GetTextureFileName(FbxSDKWrapper::FbxMaterialWrapper::MaterialMapType::Bump).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Normal,
fbxMaterial->GetTextureFileName(FbxSDKWrapper::FbxMaterialWrapper::MaterialMapType::Normal).c_str());
material->SetDiffuseColor(fbxMaterial->GetDiffuseColor());
material->SetSpecularColor(fbxMaterial->GetSpecularColor());
material->SetEmissiveColor(fbxMaterial->GetEmissiveColor());
material->SetShininess(fbxMaterial->GetShininess());
float opacity = fbxMaterial->GetOpacity();
if (opacity == 0.0f)
{
opacity = 1.0f;
AZ_TracePrintf(Utilities::WarningWindow, "Opacity has been changed from 0 to full. Some DCC tools ignore the opacity and "
"write 0 to indicate opacity is not used. This causes meshes to turn invisible, which is often not the intention so "
"the opacity has been set to full automatically. If the intention was for a fully transparent mesh, please update "
"the opacity in Lumberyards material editor.");
}
material->SetOpacity(opacity);
// Due to the fact that fbxMaterial->GetUniqueId() will return a different ID
// each time when the fbx is reprocessed, we need a more stable ID.
// The current best candidate is probably the name of the material.
// But this will also force the user to update the material component for overrides
// if the fbx material name is changed outside from apps like dcc tools.
// (Ideally, only changing the material properties in the dcc tool will force the user to update the material component)
//
// Using 32-bit CRC as it is mathematically stable and enough within the same fbx.
uint64_t id = uint32_t(AZ::Crc32(fbxMaterial->GetName()));
material->SetUniqueId(id);
return material;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,51 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Events/ProcessingResult.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneData
{
namespace GraphData
{
class MaterialData;
}
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxMaterialImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxMaterialImporter, "{E1DF4182-793D-4188-B833-1236D33CCEB4}", SceneCore::LoadingComponent);
FbxMaterialImporter();
~FbxMaterialImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMaterials(SceneNodeAppendedContext& context);
protected:
AZStd::shared_ptr<SceneData::GraphData::MaterialData> BuildMaterial(FbxSDKWrapper::FbxNodeWrapper& node, int materialIndex) const;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,69 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/FbxMeshImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxMeshImporter::FbxMeshImporter()
{
BindToCall(&FbxMeshImporter::ImportMesh);
}
void FbxMeshImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxMeshImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxMeshImporter::ImportMesh(FbxNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Mesh");
if (!context.m_sourceNode.GetMesh() ||
IsSkinnedMesh(context.m_sourceNode))
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::MeshData> createdData =
AZStd::make_shared<SceneData::GraphData::MeshData>();
if (BuildSceneMeshFromFbxMesh(createdData, *context.m_sourceNode.GetMesh(), context.m_sourceSceneSystem))
{
context.m_createdData.push_back(std::move(createdData));
return Events::ProcessingResult::Success;
}
else
{
return Events::ProcessingResult::Failure;
}
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,54 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class MeshData;
}
}
namespace SceneAPI
{
class FbxSceneSystem;
namespace FbxSceneBuilder
{
class FbxMeshImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxMeshImporter, "{8D131E77-4D53-486A-B3C6-80ACC27A6D50}", SceneCore::LoadingComponent);
FbxMeshImporter();
~FbxMeshImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMesh(FbxNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,69 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/FbxMeshImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxSkinImporter::FbxSkinImporter()
{
BindToCall(&FbxSkinImporter::ImportSkin);
}
void FbxSkinImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxSkinImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxSkinImporter::ImportSkin(FbxNodeEncounteredContext& context)
{
if (!context.m_sourceNode.GetMesh() ||
!IsSkinnedMesh(context.m_sourceNode))
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::SkinMeshData> createdData =
AZStd::make_shared<SceneData::GraphData::SkinMeshData>();
if (BuildSceneMeshFromFbxMesh(createdData, *context.m_sourceNode.GetMesh(), context.m_sourceSceneSystem))
{
context.m_createdData.push_back(std::move(createdData));
return Events::ProcessingResult::Success;
}
else
{
return Events::ProcessingResult::Failure;
}
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxSkinImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxSkinImporter, "{22108E92-7037-442D-94E0-A2E92554A79F}", SceneCore::LoadingComponent);
FbxSkinImporter();
~FbxSkinImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkin(FbxNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,177 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const AZStd::string FbxSkinWeightsImporter::s_skinWeightName = "SkinWeight_";
FbxSkinWeightsImporter::FbxSkinWeightsImporter()
{
BindToCall(&FbxSkinWeightsImporter::ImportSkinWeights);
BindToCall(&FbxSkinWeightsImporter::SetupNamedBoneLinks);
}
void FbxSkinWeightsImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxSkinWeightsImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxSkinWeightsImporter::ImportSkinWeights(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Skin Weights");
if (!IsSkinnedMesh(context.m_sourceNode))
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedSkinWeightsResult;
for (int deformerIndex = 0; deformerIndex < context.m_sourceNode.GetMesh()->GetDeformerCount(FbxDeformer::eSkin); ++deformerIndex)
{
AZ_TraceContext("Deformer Index", deformerIndex);
AZStd::shared_ptr<const FbxSDKWrapper::FbxSkinWrapper> fbxSkin =
context.m_sourceNode.GetMesh()->GetSkin(deformerIndex);
if (!fbxSkin)
{
return Events::ProcessingResult::Failure;
}
AZStd::string skinWeightName = s_skinWeightName;
skinWeightName += AZStd::to_string(deformerIndex);
RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> skinDeformer =
BuildSkinWeightData(context.m_sourceNode.GetMesh(), deformerIndex);
AZ_Assert(skinDeformer, "Failed to allocate skin weighting data.");
if (!skinDeformer)
{
combinedSkinWeightsResult += Events::ProcessingResult::Failure;
continue;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, skinWeightName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedSkinWeightsResult += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult skinWeightsResult;
SceneAttributeDataPopulatedContext dataPopulated(context, skinDeformer, newIndex, skinWeightName);
skinWeightsResult = Events::Process(dataPopulated);
if (skinWeightsResult != Events::ProcessingResult::Failure)
{
skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedSkinWeightsResult += skinWeightsResult;
}
return combinedSkinWeightsResult.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> FbxSkinWeightsImporter::BuildSkinWeightData(
const std::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper>& fbxMesh, int skinIndex)
{
AZStd::shared_ptr<const FbxSDKWrapper::FbxSkinWrapper> fbxSkin = fbxMesh->GetSkin(skinIndex);
AZ_Assert(fbxSkin, "BuildSkinWeightData was called for index %i which doesn't contain a skin deformer.",
skinIndex);
if (!fbxSkin)
{
return nullptr;
}
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> skinWeightData =
AZStd::make_shared<SceneData::GraphData::SkinWeightData>();
// Cache the new object and the link info for now so it can be resolved at a later point when all
// names have been updated.
Pending pending;
pending.m_fbxMesh = fbxMesh;
pending.m_fbxSkin = fbxSkin;
pending.m_skinWeightData = skinWeightData;
m_pendingSkinWeights.push_back(pending);
return skinWeightData;
}
Events::ProcessingResult FbxSkinWeightsImporter::SetupNamedBoneLinks(FinalizeSceneContext& context)
{
AZ_TraceContext("Importer", "Skin Weights");
for (auto& it : m_pendingSkinWeights)
{
int controlPointCount = it.m_fbxMesh->GetControlPointsCount();
it.m_skinWeightData->ResizeContainerSpace(controlPointCount);
int clusterCount = it.m_fbxSkin->GetClusterCount();
for (int clusterIndex = 0; clusterIndex < clusterCount; ++clusterIndex)
{
int controlPointCount2 = it.m_fbxSkin->GetClusterControlPointIndicesCount(clusterIndex);
AZStd::shared_ptr<const FbxSDKWrapper::FbxNodeWrapper> fbxLink = it.m_fbxSkin->GetClusterLink(clusterIndex);
if (!fbxLink)
{
AZ_TracePrintf(Utilities::WarningWindow, "FBX data contains null skin cluster link at index %i", clusterIndex);
continue;
}
// The name of the bones may be updated as they get processed. Processing of bones may not necessarily happen before
// processing skin weights so to avoid storing names that will be updated later delay setting up the link until
// all processing has completed.
AZStd::string boneName = context.m_nodeNameMap.GetNodeName(fbxLink);
int boneId = it.m_skinWeightData->GetBoneId(boneName);
for (int pointIndex = 0; pointIndex < controlPointCount2; ++pointIndex)
{
SceneAPI::DataTypes::ISkinWeightData::Link link;
link.boneId = boneId;
link.weight = aznumeric_caster(it.m_fbxSkin->GetClusterControlPointWeight(clusterIndex, pointIndex));
it.m_skinWeightData->AppendLink(it.m_fbxSkin->GetClusterControlPointIndex(clusterIndex, pointIndex), link);
}
}
}
const auto result = m_pendingSkinWeights.empty() ? Events::ProcessingResult::Ignored : Events::ProcessingResult::Success;
m_pendingSkinWeights.clear();
return result;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,79 @@
/*
* 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/vector.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class SkinWeightData;
}
}
namespace SceneAPI
{
namespace Events
{
class PostImportEventContext;
}
namespace FbxSceneBuilder
{
class FbxSkinWeightsImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxSkinWeightsImporter, "{95FCD291-5E1F-4591-90AD-AB5EA2599C3E}", SceneCore::LoadingComponent);
FbxSkinWeightsImporter();
~FbxSkinWeightsImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkinWeights(SceneNodeAppendedContext& context);
Events::ProcessingResult SetupNamedBoneLinks(FinalizeSceneContext& context);
protected:
struct Pending
{
std::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper> m_fbxMesh;
AZStd::shared_ptr<const FbxSDKWrapper::FbxSkinWrapper> m_fbxSkin;
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> m_skinWeightData;
};
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> BuildSkinWeightData(
const std::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper>& fbxMesh, int skinIndex);
//! List of skin weights that still need to be filled in. Setting the data for skin weights is
//! delayed until after the tree has been fully constructed as bones are linked by name, but until
//! the graph has been fully filled in, those names can change which would break the names recorded
//! for the skin.
AZStd::vector<Pending> m_pendingSkinWeights;
static const AZStd::string s_skinWeightName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,162 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxVertexTangentWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxTangentStreamImporter::FbxTangentStreamImporter()
{
BindToCall(&FbxTangentStreamImporter::ImportTangents);
}
void FbxTangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxTangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxTangentStreamImporter::ImportTangents(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Tangents");
std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> fbxMesh = context.m_sourceNode.GetMesh();
if (!fbxMesh)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedStreamResults;
const int numTangentSets = context.m_sourceNode.GetMesh()->GetElementTangentCount();
for (int elementIndex = 0; elementIndex < numTangentSets; ++elementIndex)
{
AZ_TraceContext("Tangent set index", elementIndex);
FbxSDKWrapper::FbxVertexTangentWrapper fbxVertexTangents = fbxMesh->GetElementTangent(elementIndex);
if (!fbxVertexTangents.IsValid())
{
AZ_TracePrintf(Utilities::WarningWindow, "Invalid tangent set found, ignoring");
continue;
}
const AZStd::string originalNodeName = AZStd::string::format("TangentSet_Fbx_%d", elementIndex);
const AZStd::string nodeName = AZ::SceneAPI::DataTypes::Utilities::CreateUniqueName<SceneData::GraphData::MeshVertexTangentData>(originalNodeName, context.m_scene.GetManifest());
AZ_TraceContext("Tangent Set Name", nodeName);
if (originalNodeName != nodeName)
{
AZ_TracePrintf(Utilities::WarningWindow, "Tangent set '%s' has been renamed to '%s' because the name was already in use.", originalNodeName.c_str(), nodeName.c_str());
}
AZStd::shared_ptr<DataTypes::IGraphObject> parentData = context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()), "Tried to construct tangent set attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const size_t vertexCount = parentMeshData->GetVertexCount();
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> tangentStream = BuildVertexTangentData(fbxVertexTangents, vertexCount, fbxMesh);
AZ_Assert(tangentStream, "Failed to allocate tangent data for scene graph.");
if (!tangentStream)
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
tangentStream->SetTangentSetIndex(elementIndex);
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
const Containers::SceneGraph::NodeIndex newIndex = context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedStreamResults += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult streamResults;
SceneAttributeDataPopulatedContext dataPopulated(context, tangentStream, newIndex, nodeName);
streamResults = Events::Process(dataPopulated);
if (streamResults != Events::ProcessingResult::Failure)
{
streamResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedStreamResults += streamResults;
}
return combinedStreamResults.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> FbxTangentStreamImporter::BuildVertexTangentData(const FbxSDKWrapper::FbxVertexTangentWrapper& tangents, size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh)
{
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> tangentData = AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexTangentData>();
tangentData->ReserveContainerSpace(vertexCount);
const int fbxPolygonCount = fbxMesh->GetPolygonCount();
const int* const fbxPolygonVertices = fbxMesh->GetPolygonVertices();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = fbxMesh->GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
const int fbxVertexStartIndex = fbxMesh->GetPolygonVertexIndex(fbxPolygonIndex);
for (int index = 0; index < fbxPolygonVertexCount; ++index)
{
const int fbxPolygonVertexIndex = fbxVertexStartIndex + index;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
const Vector3 tangent = tangents.GetElementAt(fbxPolygonIndex, fbxPolygonVertexIndex, fbxControlPointIndex);
tangentData->AppendTangent(AZ::Vector4(tangent.GetX(), tangent.GetY(), tangent.GetZ(), 1.0f));
}
}
if (tangentData->GetCount() != vertexCount)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Vertex count (%i) doesn't match the number of entries for the tangent stream %s (%i)", vertexCount, tangents.GetName(), tangentData->GetCount());
return nullptr;
}
return tangentData;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,58 @@
/*
* 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/smart_ptr/shared_ptr.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneData
{
namespace GraphData
{
class MeshVertexTangentData;
}
}
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
class FbxVertexTangentWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxTangentStreamImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxTangentStreamImporter, "{70F3A9F5-5BB1-4FE2-BD63-A60C2DCA4589}", SceneCore::LoadingComponent);
FbxTangentStreamImporter();
~FbxTangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportTangents(SceneNodeAppendedContext& context);
protected:
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> BuildVertexTangentData(const FbxSDKWrapper::FbxVertexTangentWrapper& tangents,
size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,121 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/TransformData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* FbxTransformImporter::s_transformNodeName = "transform";
FbxTransformImporter::FbxTransformImporter()
{
BindToCall(&FbxTransformImporter::ImportTransform);
}
void FbxTransformImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxTransformImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxTransformImporter::ImportTransform(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Transform");
DataTypes::MatrixType localTransform;
if (!GetBindPoseLocalTransform(context.m_sourceScene, context.m_sourceNode, localTransform))
{
localTransform = context.m_sourceNode.EvaluateLocalTransform();
DataTypes::MatrixType geoTransform = context.m_sourceNode.GetGeometricTransform(); // transform of the pivot
localTransform *= geoTransform;
}
if (localTransform == DataTypes::MatrixType::Identity())
{
return Events::ProcessingResult::Ignored;
}
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
AZStd::shared_ptr<SceneData::GraphData::TransformData> transformData =
AZStd::make_shared<SceneData::GraphData::TransformData>(localTransform);
AZ_Assert(transformData, "Failed to allocate transform data.");
if (!transformData)
{
return Events::ProcessingResult::Failure;
}
// If it is non-endpoint data populated node, add a transform attribute
if (context.m_scene.GetGraph().HasNodeContent(context.m_currentGraphPosition))
{
if (!context.m_scene.GetGraph().IsNodeEndPoint(context.m_currentGraphPosition))
{
AZStd::string nodeName = s_transformNodeName;
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZ_TraceContext("Transform node name", nodeName);
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
return Events::ProcessingResult::Failure;
}
Events::ProcessingResult transformAttributeResult;
SceneAttributeDataPopulatedContext dataPopulated(context, transformData, newIndex, nodeName);
transformAttributeResult = Events::Process(dataPopulated);
if (transformAttributeResult != Events::ProcessingResult::Failure)
{
transformAttributeResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
return transformAttributeResult;
}
}
else
{
bool addedData = context.m_scene.GetGraph().SetContent(
context.m_currentGraphPosition,
transformData);
AZ_Assert(addedData, "Failed to add node data");
return addedData ? Events::ProcessingResult::Success : Events::ProcessingResult::Failure;
}
return Events::ProcessingResult::Ignored;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* 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/Math/Transform.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxTransformImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxTransformImporter, "{354EAAE2-DF31-4E11-BD8A-619419A3EA17}", SceneCore::LoadingComponent);
FbxTransformImporter();
~FbxTransformImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportTransform(SceneNodeAppendedContext& context);
protected:
static const char* s_transformNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,164 @@
/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxUvMapImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxUVWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
FbxUvMapImporter::FbxUvMapImporter()
{
BindToCall(&FbxUvMapImporter::ImportUvMaps);
}
void FbxUvMapImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxUvMapImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult FbxUvMapImporter::ImportUvMaps(SceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "UV Map");
std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper> fbxMesh =
context.m_sourceNode.GetMesh();
if (!fbxMesh)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedUvMapResults;
for (int uvElementIndex = 0; uvElementIndex < context.m_sourceNode.GetMesh()->GetElementUVCount(); ++uvElementIndex)
{
AZ_TraceContext("UV Map index", uvElementIndex);
FbxSDKWrapper::FbxUVWrapper fbxVertexUVs = fbxMesh->GetElementUV(uvElementIndex);
if (!fbxVertexUVs.IsValid())
{
AZ_TracePrintf(Utilities::WarningWindow, "Invalid UV Map found, ignoring");
continue;
}
AZStd::string nodeName = fbxVertexUVs.GetName();
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "UV");
AZ_TraceContext("UV Map Name", nodeName);
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
combinedUvMapResults += Events::ProcessingResult::Failure;
continue;
}
const SceneData::GraphData::MeshData* const parentMeshData =
azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap = BuildVertexUVData(fbxVertexUVs, vertexCount, fbxMesh);
AZ_Assert(uvMap, "Failed to allocate UV map data for scene graph.");
if (!uvMap)
{
combinedUvMapResults += Events::ProcessingResult::Failure;
continue;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedUvMapResults += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult uvMapResults;
SceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, nodeName);
uvMapResults = Events::Process(dataPopulated);
if (uvMapResults != Events::ProcessingResult::Failure)
{
uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedUvMapResults += uvMapResults;
}
return combinedUvMapResults.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> FbxUvMapImporter::BuildVertexUVData(const FbxSDKWrapper::FbxUVWrapper& uvs,
size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh)
{
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvData = AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
uvData->ReserveContainerSpace(vertexCount);
uvData->SetCustomName(uvs.GetName());
const int fbxPolygonCount = fbxMesh->GetPolygonCount();
const int* const fbxPolygonVertices = fbxMesh->GetPolygonVertices();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = fbxMesh->GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
const int fbxVertexStartIndex = fbxMesh->GetPolygonVertexIndex(fbxPolygonIndex);
for (int uvIndex = 0; uvIndex < fbxPolygonVertexCount; ++uvIndex)
{
const int fbxPolygonVertexIndex = fbxVertexStartIndex + uvIndex;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
Vector2 uv = uvs.GetElementAt(fbxPolygonIndex, fbxPolygonVertexIndex, fbxControlPointIndex);
uv.SetY(1.0f - uv.GetY());
uvData->AppendUV(uv);
}
}
if (uvData->GetCount() != vertexCount)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Vertex count (%i) doesn't match the number of entries for the uv set %s (%i)",
vertexCount, uvs.GetName(), uvData->GetCount());
return nullptr;
}
return uvData;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,58 @@
/*
* 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/smart_ptr/shared_ptr.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneData
{
namespace GraphData
{
class MeshVertexUVData;
}
}
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
class FbxUVWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class FbxUvMapImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(FbxUvMapImporter, "{B16CD69D-3C0C-4FE2-B481-1084B1C36242}", SceneCore::LoadingComponent);
FbxUvMapImporter();
~FbxUvMapImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportUvMaps(SceneNodeAppendedContext& context);
protected:
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> BuildVertexUVData(const FbxSDKWrapper::FbxUVWrapper& uvs,
size_t vertexCount, const std::shared_ptr<FbxSDKWrapper::FbxMeshWrapper>& fbxMesh);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,311 @@
/*
* 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/Casting/numeric_cast.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/FbxMeshImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxBlendShapeWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
bool BuildSceneMeshFromFbxMesh(const AZStd::shared_ptr<SceneData::GraphData::MeshData>& mesh,
const FbxSDKWrapper::FbxMeshWrapper& sourceMesh, const FbxSceneSystem& sceneSystem)
{
// Save unit sizes of the mesh
mesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
mesh->SetOriginalUnitSizeInMeters(sceneSystem.GetOriginalUnitSizeInMeters());
// Get mesh subset count by scanning material IDs in meshes.
// For negative material ids we will add an additional
// subset at the end, see "++maxMaterialIndex".
// These defines material index range for all polygons in the mesh
// Each polygon has a material index
int minMeshMaterialIndex = INT_MAX;
int maxMeshMaterialIndex = INT_MIN;
FbxLayerElementArrayTemplate<int>* fbxMaterialIndices;
sourceMesh.GetMaterialIndices(&fbxMaterialIndices); // per polygon
int fbxPolygonCount = sourceMesh.GetPolygonCount();
AZ_Error("FbxSceneBuilder", fbxPolygonCount,
"Source mesh %s polygon count is 0. Zero count meshes are not supported, either remove this mesh or add polygons to it.",
sourceMesh.GetName());
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
// if the polygon has less than 3 vertices, it's not a valid polygon and is skipped
const int fbxPolygonVertexCount = sourceMesh.GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
// Get the material index of each polygon
const int meshMaterialIndex = fbxMaterialIndices ? (*fbxMaterialIndices)[fbxPolygonIndex] : -1;
minMeshMaterialIndex = AZ::GetMin<int>(minMeshMaterialIndex, meshMaterialIndex);
maxMeshMaterialIndex = AZ::GetMax<int>(maxMeshMaterialIndex, meshMaterialIndex);
}
if (minMeshMaterialIndex > maxMeshMaterialIndex)
{
return false;
}
if (maxMeshMaterialIndex < 0)
{
minMeshMaterialIndex = maxMeshMaterialIndex = 0;
}
else if (minMeshMaterialIndex < 0)
{
minMeshMaterialIndex = 0;
++maxMeshMaterialIndex;
}
// Fill geometry
// Control points contain positions of vertices
AZStd::vector<Vector3> fbxControlPoints = sourceMesh.GetControlPoints();
const int* const fbxPolygonVertices = sourceMesh.GetPolygonVertices();
fbxMaterialIndices = nullptr;
sourceMesh.GetMaterialIndices(&fbxMaterialIndices); // per polygon
// Iterate through each polygon in the mesh and convert data
fbxPolygonCount = sourceMesh.GetPolygonCount();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = sourceMesh.GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
AZ_TraceContext("Polygon Index", fbxPolygonIndex);
// Ensure the validity of the material index for the polygon
int fbxMaterialIndex = fbxMaterialIndices ? (*fbxMaterialIndices)[fbxPolygonIndex] : -1;
if (fbxMaterialIndex < minMeshMaterialIndex || fbxMaterialIndex > maxMeshMaterialIndex)
{
fbxMaterialIndex = maxMeshMaterialIndex;
}
const int fbxVertexStartIndex = sourceMesh.GetPolygonVertexIndex(fbxPolygonIndex);
// Triangulate polygon as a fan and remember resulting vertices and faces
int firstMeshVertexIndex = -1;
int previousMeshVertexIndex = -1;
AZ::SceneAPI::DataTypes::IMeshData::Face meshFace;
int verticesInMeshFace = 0;
// Iterate through each vertex in the polygon
for (int vertexIndex = 0; vertexIndex < fbxPolygonVertexCount; ++vertexIndex)
{
const int meshVertexIndex = aznumeric_caster(mesh->GetVertexCount());
const int fbxPolygonVertexIndex = fbxVertexStartIndex + vertexIndex;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
Vector3 meshPosition = fbxControlPoints[fbxControlPointIndex];
Vector3 meshVertexNormal;
sourceMesh.GetPolygonVertexNormal(fbxPolygonIndex, vertexIndex, meshVertexNormal);
sceneSystem.SwapVec3ForUpAxis(meshPosition);
sceneSystem.ConvertUnit(meshPosition);
// Add position
mesh->AddPosition(meshPosition);
// Add normal
sceneSystem.SwapVec3ForUpAxis(meshVertexNormal);
meshVertexNormal.NormalizeSafe();
mesh->AddNormal(meshVertexNormal);
mesh->SetVertexIndexToControlPointIndexMap(meshVertexIndex, fbxControlPointIndex);
// Add face
{
if (vertexIndex == 0)
{
firstMeshVertexIndex = meshVertexIndex;
}
int meshVertices[3];
int meshVertexCount = 0;
meshVertices[meshVertexCount++] = meshVertexIndex;
// If we already have generated one triangle before, make a new triangle at a time as we encounter a new vertex.
// The new triangle is composed with the first vertex of the polygon, the last vertex, and the current vertex.
if (vertexIndex >= 3)
{
meshVertices[meshVertexCount++] = firstMeshVertexIndex;
meshVertices[meshVertexCount++] = previousMeshVertexIndex;
}
for (int faceVertexIndex = 0; faceVertexIndex < meshVertexCount; ++faceVertexIndex)
{
meshFace.vertexIndex[verticesInMeshFace++] = meshVertices[faceVertexIndex];
if (verticesInMeshFace == 3)
{
verticesInMeshFace = 0;
mesh->AddFace(meshFace, fbxMaterialIndex);
}
}
}
previousMeshVertexIndex = meshVertexIndex;
}
// Report problem if there are vertices that left for forming a polygon
if (verticesInMeshFace != 0)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Internal error in mesh filler");
return false;
}
}
// Report problem if no vertex or face converted to MeshData
if (mesh->GetVertexCount() <= 0 || mesh->GetFaceCount() <= 0)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Missing geometry data in mesh node");
return false;
}
return true;
}
// Currently doesn't maintain a list of unique control points.
// Normals are associated with each triangle vertex from the face.
bool BuildSceneBlendShapeFromFbxBlendShape(const AZStd::shared_ptr<SceneData::GraphData::BlendShapeData>& blendShape,
const AZStd::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper>& sourceMesh, const FbxSceneSystem& sceneSystem)
{
// Control points contain positions of vertices
const AZStd::vector<Vector3>& fbxControlPoints = sourceMesh->GetControlPoints();
const int* const fbxPolygonVertices = sourceMesh->GetPolygonVertices();
// Iterate through each polygon in the mesh and convert data
const int fbxPolygonCount = sourceMesh->GetPolygonCount();
for (int fbxPolygonIndex = 0; fbxPolygonIndex < fbxPolygonCount; ++fbxPolygonIndex)
{
const int fbxPolygonVertexCount = sourceMesh->GetPolygonSize(fbxPolygonIndex);
if (fbxPolygonVertexCount <= 2)
{
continue;
}
AZ_TraceContext("Polygon Index", fbxPolygonIndex);
const int fbxVertexStartIndex = sourceMesh->GetPolygonVertexIndex(fbxPolygonIndex);
// Triangulate polygon as a fan and remember resulting vertices and faces
int firstMeshVertexIndex = -1;
int previousMeshVertexIndex = -1;
DataTypes::IBlendShapeData::Face face;
int verticesInMeshFace = 0;
// Iterate through each vertex in the polygon
for (int vertexIndex = 0; vertexIndex < fbxPolygonVertexCount; ++vertexIndex)
{
const int meshVertexIndex = aznumeric_caster(blendShape->GetVertexCount());
const int fbxPolygonVertexIndex = fbxVertexStartIndex + vertexIndex;
const int fbxControlPointIndex = fbxPolygonVertices[fbxPolygonVertexIndex];
// This data allows for mapping vertex data to original Control Point index.
blendShape->SetVertexIndexToControlPointIndexMap(meshVertexIndex, fbxControlPointIndex);
Vector3 meshVertexPosition = fbxControlPoints[fbxControlPointIndex];
Vector3 meshVertexNormal;
sourceMesh->GetPolygonVertexNormal(fbxPolygonIndex, vertexIndex, meshVertexNormal);
// position
sceneSystem.SwapVec3ForUpAxis(meshVertexPosition);
sceneSystem.ConvertUnit(meshVertexPosition);
// normal
sceneSystem.SwapVec3ForUpAxis(meshVertexNormal);
meshVertexNormal.Normalize();
blendShape->AddVertex(meshVertexPosition, meshVertexNormal);
// Add face
{
if (vertexIndex == 0)
{
firstMeshVertexIndex = meshVertexIndex;
}
int meshVertices[3];
int meshNormals[3];
int meshVertexCount = 0;
meshVertices[meshVertexCount] = meshVertexIndex;
meshNormals[meshVertexCount++] = meshVertexIndex;
// If we already have generated one triangle before, make a new triangle at a time as we encounter a new vertex.
// The new triangle is composed with the first vertex of the polygon, the last vertex, and the current vertex.
if (vertexIndex >= 3)
{
meshVertices[meshVertexCount++] = firstMeshVertexIndex;
meshVertices[meshVertexCount++] = previousMeshVertexIndex;
}
for (int faceVertexIndex = 0; faceVertexIndex < meshVertexCount; ++faceVertexIndex)
{
face.vertexIndex[verticesInMeshFace++] = meshVertices[faceVertexIndex];
if (verticesInMeshFace == 3)
{
verticesInMeshFace = 0;
blendShape->AddFace(face);
break;
}
}
}
previousMeshVertexIndex = meshVertexIndex;
}
// Report problem if there are vertices that left for forming a polygon
if (verticesInMeshFace != 0)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Internal error in mesh filler. Vertices were left without forming polygon");
return false;
}
}
// Report problem if no vertex or face converted to MeshData
if (blendShape->GetVertexCount() <= 0 || blendShape->GetFaceCount() <= 0)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Missing geometry data in blendshape node");
return false;
}
return true;
}
}
}
}
@@ -0,0 +1,42 @@
/*
* 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
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class MeshData;
class BlendShapeData;
}
}
namespace SceneAPI
{
class FbxSceneSystem;
namespace FbxSceneBuilder
{
bool BuildSceneMeshFromFbxMesh(const AZStd::shared_ptr<SceneData::GraphData::MeshData>& mesh,
const FbxSDKWrapper::FbxMeshWrapper& sourceMesh, const FbxSceneSystem& sceneSystem);
bool BuildSceneBlendShapeFromFbxBlendShape(const AZStd::shared_ptr<SceneData::GraphData::BlendShapeData>& blendShape,
const AZStd::shared_ptr<const FbxSDKWrapper::FbxMeshWrapper>& sourceMesh, const FbxSceneSystem& sceneSystem);
}
}
}
@@ -0,0 +1,162 @@
/*
* 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/Casting/numeric_cast.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
bool RenamedNodesMap::SanitizeNodeName(AZStd::string& name, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName)
{
AZ_TraceContext("Node name", name);
bool isNameUpdated = false;
// Nodes can't have an empty name, except of the root, otherwise nodes can't be referenced.
if (name.empty())
{
name = defaultName;
isNameUpdated = true;
}
// The scene graph uses an arbitrary character (by default dot) to separate the names of the parents
// therefore that character can't be used in the name.
AZStd::replace_if(name.begin(), name.end(),
[&isNameUpdated](char c) -> bool
{
if (c == Containers::SceneGraph::GetNodeSeperationCharacter())
{
isNameUpdated = true;
return true;
}
else
{
return false;
}
}, '_');
// Nodes under a particular parent have to be unique. Multiple nodes can share the same name, but they
// can't reference the same parent in that case. This is to make sure the node can be quickly found as
// the full path will be unique. To fix any issues, an index is appended.
size_t index = 1;
size_t offset = name.length();
while (graph.Find(parentNode, name).IsValid())
{
// Remove the previously tried extension.
name.erase(offset, name.length() - offset);
name += ('_');
name += AZStd::to_string(aznumeric_cast<u64>(index));
index++;
isNameUpdated = true;
}
if (isNameUpdated)
{
AZ_TraceContext("New node name", name);
AZ_TracePrintf(Utilities::WarningWindow, "The name of the node was invalid or conflicting and was updated.");
}
return isNameUpdated;
}
bool RenamedNodesMap::RegisterNode(const std::shared_ptr<SDKNode::NodeWrapper>& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName)
{
return node ? RegisterNode(*node, graph, parentNode, defaultName) : false;
}
bool RenamedNodesMap::RegisterNode(const std::shared_ptr<const SDKNode::NodeWrapper>& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName)
{
return node ? RegisterNode(*node, graph, parentNode, defaultName) : false;
}
bool RenamedNodesMap::RegisterNode(const SDKNode::NodeWrapper& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName)
{
AZStd::string name = node.GetName();
if (SanitizeNodeName(name, graph, parentNode, defaultName))
{
AZ_TraceContext("New node name", name);
// Only register if the name is updated, otherwise the name in the fbx node can be returned.
auto entry = m_idToName.find(node.GetUniqueId());
if (entry == m_idToName.end())
{
m_idToName.insert(AZStd::make_pair(node.GetUniqueId(), AZStd::move(name)));
return true;
}
else
{
AZ_TraceContext("Previous name", entry->second);
if (entry->second == name)
{
return true;
}
else
{
AZ_Assert(false, "Node has already been registered with a different name.");
return false;
}
}
}
else
{
return true;
}
}
const char* RenamedNodesMap::GetNodeName(const std::shared_ptr<SDKNode::NodeWrapper>& node) const
{
return node ? GetNodeName(*node) : "<invalid>";
}
const char* RenamedNodesMap::GetNodeName(const std::shared_ptr<const SDKNode::NodeWrapper>& node) const
{
return node ? GetNodeName(*node) : "<invalid>";
}
const char* RenamedNodesMap::GetNodeName(const AZStd::shared_ptr<SDKNode::NodeWrapper>& node) const
{
return node ? GetNodeName(*node) : "<invalid>";
}
const char* RenamedNodesMap::GetNodeName(const AZStd::shared_ptr<const SDKNode::NodeWrapper>& node) const
{
return node ? GetNodeName(*node) : "<invalid>";
}
const char* RenamedNodesMap::GetNodeName(const SDKNode::NodeWrapper& node) const
{
auto entry = m_idToName.find(node.GetUniqueId());
if (entry != m_idToName.end())
{
return entry->second.c_str();
}
else
{
return node.GetName();
}
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,70 @@
/*
* 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 <memory>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SDKWrapper/NodeWrapper.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxNodeWrapper;
}
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class RenamedNodesMap
{
public:
//! Checks if the provided name is valid for the position in the graph and makes corrections if
//! problems are found.
//! @param name The name of the node in the scene graph.
//! @param graph The scene graph the node will be added to.
//! @param parentNode The node that will be the intended parent for the the node who's name is being checked.
//! @param defaultName If the provided name is empty, the defaultName will be used.
//! @return True if the name was updated otherwise false.
static bool SanitizeNodeName(AZStd::string& name, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName = "unnamed");
//! Register the name for later reference. If the name needs to be sanitized, the sanitized name will be stored.
//! @param node The node that's to be registered.
//! @param graph The scene graph the node will be added to.
//! @param parentNode The node that will be the intended parent for the the node who's name is being checked.
//! @param defaultName If the provided name is empty, the defaultName will be used.
//! @return True if the node was successfully registered.
bool RegisterNode(const std::shared_ptr<SDKNode::NodeWrapper>& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName = "unnamed");
bool RegisterNode(const std::shared_ptr<const SDKNode::NodeWrapper>& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName = "unnamed");
bool RegisterNode(const SDKNode::NodeWrapper& node, const Containers::SceneGraph& graph,
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName = "unnamed");
//! Returns the name of the given node, which may be sanitized if this was needed.
const char* GetNodeName(const std::shared_ptr<SDKNode::NodeWrapper>& node) const;
const char* GetNodeName(const std::shared_ptr<const SDKNode::NodeWrapper>& node) const;
const char* GetNodeName(const AZStd::shared_ptr<SDKNode::NodeWrapper>& node) const;
const char* GetNodeName(const AZStd::shared_ptr<const SDKNode::NodeWrapper>& node) const;
const char* GetNodeName(const SDKNode::NodeWrapper& node) const;
private:
AZStd::unordered_map<u64, AZStd::string> m_idToName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,36 @@
#
# 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.
#
set(FILES
../../../SceneCore/Containers/SceneManifest.h
../../../SceneCore/Containers/SceneManifest.inl
../../../SceneCore/Containers/SceneManifest.cpp
../../../SceneCore/Events/AssetImportRequest.cpp
../../../SceneCore/Events/AssetImportRequest.h
../../../SceneCore/Events/CallProcessorBinder.cpp
../../../SceneCore/Events/CallProcessorBinder.h
../../../SceneData/GraphData/MeshVertexUVData.h
../../../SceneData/GraphData/MeshVertexUVData.cpp
../../../SceneData/GraphData/MeshVertexColorData.h
../../../SceneData/GraphData/MeshVertexColorData.cpp
../../../SceneData/GraphData/BoneData.h
../../../SceneData/GraphData/BoneData.cpp
../../../SceneData/GraphData/MeshData.h
../../../SceneData/GraphData/MeshData.cpp
../../../SceneData/GraphData/SkinWeightData.h
../../../SceneData/GraphData/SkinWeightData.cpp
../../../SceneData/GraphData/MaterialData.h
../../../SceneData/GraphData/MaterialData.cpp
../../../SceneData/GraphData/AnimationData.h
../../../SceneData/GraphData/AnimationData.cpp
../../../SceneData/GraphData/BlendShapeData.h
../../../SceneData/GraphData/BlendShapeData.cpp
)
@@ -0,0 +1,36 @@
#
# 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.
#
set(FILES
../../../SceneCore/Containers/SceneManifest.h
../../../SceneCore/Containers/SceneManifest.inl
../../../SceneCore/Containers/SceneManifest.cpp
../../../SceneCore/Events/AssetImportRequest.cpp
../../../SceneCore/Events/AssetImportRequest.h
../../../SceneCore/Events/CallProcessorBinder.cpp
../../../SceneCore/Events/CallProcessorBinder.h
../../../SceneData/GraphData/MeshVertexUVData.h
../../../SceneData/GraphData/MeshVertexUVData.cpp
../../../SceneData/GraphData/MeshVertexColorData.h
../../../SceneData/GraphData/MeshVertexColorData.cpp
../../../SceneData/GraphData/BoneData.h
../../../SceneData/GraphData/BoneData.cpp
../../../SceneData/GraphData/MeshData.h
../../../SceneData/GraphData/MeshData.cpp
../../../SceneData/GraphData/SkinWeightData.h
../../../SceneData/GraphData/SkinWeightData.cpp
../../../SceneData/GraphData/MaterialData.h
../../../SceneData/GraphData/MaterialData.cpp
../../../SceneData/GraphData/AnimationData.h
../../../SceneData/GraphData/AnimationData.cpp
../../../SceneData/GraphData/BlendShapeData.h
../../../SceneData/GraphData/BlendShapeData.cpp
)
@@ -0,0 +1,25 @@
#
# 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.
#
set(FILES
../../ImportContexts/AssImpImportContexts.h
../../ImportContexts/AssImpImportContexts.cpp
../../Importers/AssImpColorStreamImporter.h
../../Importers/AssImpColorStreamImporter.cpp
../../Importers/AssImpMaterialImporter.h
../../Importers/AssImpMaterialImporter.cpp
../../Importers/AssImpMeshImporter.h
../../Importers/AssImpMeshImporter.cpp
../../Importers/AssImpUvMapImporter.h
../../Importers/AssImpUvMapImporter.cpp
../../Importers/AssImpTransformImporter.h
../../Importers/AssImpTransformImporter.cpp
)
@@ -0,0 +1,137 @@
/*
* 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/smart_ptr/make_shared.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzTest/AzTest.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_EmptySceneGraphs_ReturnsTrue)
{
Containers::SceneGraph lhsGraph;
Containers::SceneGraph rhsGraph;
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_TRUE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SameNameSingleNodeBothNull_ReturnsTrue)
{
Containers::SceneGraph lhsGraph;
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild");
Containers::SceneGraph rhsGraph;
rhsGraph.AddChild(rhsGraph.GetRoot(), "testChild");
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_TRUE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SameNameSingleNodeSameType_ReturnsTrue)
{
Containers::SceneGraph lhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> lhsData = AZStd::make_shared<SceneData::GraphData::MeshData>();
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild", AZStd::move(lhsData));
Containers::SceneGraph rhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> rhsData = AZStd::make_shared<SceneData::GraphData::MeshData>();
rhsGraph.AddChild(rhsGraph.GetRoot(), "testChild", AZStd::move(rhsData));
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_TRUE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SameNameSingleNodeOneNull_ReturnsFalse)
{
Containers::SceneGraph lhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> lhsData = AZStd::make_shared<SceneData::GraphData::MeshData>();
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild", AZStd::move(lhsData));
Containers::SceneGraph rhsGraph;
rhsGraph.AddChild(rhsGraph.GetRoot(), "testChild");
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_FALSE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SameNameSingleNodeDifferentTypes_ReturnsFalse)
{
Containers::SceneGraph lhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> lhsData = AZStd::make_shared<SceneData::GraphData::MeshData>();
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild", AZStd::move(lhsData));
Containers::SceneGraph rhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> rhsData = AZStd::make_shared<SceneData::GraphData::BoneData>();
rhsGraph.AddChild(rhsGraph.GetRoot(), "testChild", AZStd::move(rhsData));
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_FALSE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SameNameOneEmptyOneSingleNode_ReturnsFalse)
{
Containers::SceneGraph lhsGraph;
AZStd::shared_ptr<DataTypes::IGraphObject> lhsData = AZStd::make_shared<SceneData::GraphData::MeshData>();
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild", AZStd::move(lhsData));
Containers::SceneGraph rhsGraph;
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_FALSE(sceneGraphsEqual);
}
TEST(FbxImpoterUtilityTests, AreSceneGraphsEqual_DifferentNamesSingleNodeBothNull_ReturnsFalse)
{
Containers::SceneGraph lhsGraph;
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild");
Containers::SceneGraph rhsGraph;
rhsGraph.AddChild(rhsGraph.GetRoot(), "differentName");
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_FALSE(sceneGraphsEqual);
}
TEST(FbxImporterUtilityTests, AreSceneGraphsEqual_SecondGraphExtraChild_ReturnsFalse)
{
Containers::SceneGraph lhsGraph;
lhsGraph.AddChild(lhsGraph.GetRoot(), "testChild");
lhsGraph.AddChild(lhsGraph.GetRoot(), "extraTestChild");
Containers::SceneGraph rhsGraph;
rhsGraph.AddChild(rhsGraph.GetRoot(), "testChild");
bool sceneGraphsEqual =
(AreSceneGraphsEqual(lhsGraph, rhsGraph) && AreSceneGraphsEqual(rhsGraph, lhsGraph));
EXPECT_FALSE(sceneGraphsEqual);
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,89 @@
/*
* 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/smart_ptr/make_shared.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzTest/AzTest.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
TEST(RenamedNodesMapTests, SanitizeNodeName_ValidNameProvided_ReturnsFalseAndNameUnchanged)
{
Containers::SceneGraph graph;
AZStd::string name = "ValidName";
bool result = RenamedNodesMap::SanitizeNodeName(name, graph, graph.GetRoot());
EXPECT_FALSE(result);
EXPECT_STREQ("ValidName", name.c_str());
}
TEST(RenamedNodesMapTests, SanitizeNodeName_NameWithInvalidCharacter_ReturnsTrueAndNameChanged)
{
Containers::SceneGraph graph;
AZStd::string check = "Valid";
check += Containers::SceneGraph::GetNodeSeperationCharacter();
check += "Name";
AZStd::string name = check;
bool result = RenamedNodesMap::SanitizeNodeName(name, graph, graph.GetRoot());
EXPECT_TRUE(result);
EXPECT_STRNE(check.c_str(), name.c_str());
}
TEST(RenamedNodesMapTests, SanitizeNodeName_BlankName_ReturnsTrueAndNameSetToDefault)
{
Containers::SceneGraph graph;
AZStd::string name;
bool result = RenamedNodesMap::SanitizeNodeName(name, graph, graph.GetRoot(), "Default");
EXPECT_TRUE(result);
EXPECT_STREQ("Default", name.c_str());
}
TEST(RenamedNodesMapTests, SanitizeNodeName_SingleCollision_ReturnsTrueAndNameHasAppendixOf1)
{
Containers::SceneGraph graph;
graph.AddChild(graph.GetRoot(), "Child");
AZStd::string name = "Child";
bool result = RenamedNodesMap::SanitizeNodeName(name, graph, graph.GetRoot());
EXPECT_TRUE(result);
EXPECT_STREQ("Child_1", name.c_str());
}
TEST(RenamedNodesMapTests, SanitizeNodeName_MultipleCollisions_ReturnsTrueAndNameHasAppendixOf2)
{
Containers::SceneGraph graph;
auto child = graph.AddChild(graph.GetRoot(), "Child");
graph.AddSibling(child, "Child_1");
AZStd::string name = "Child";
bool result = RenamedNodesMap::SanitizeNodeName(name, graph, graph.GetRoot());
EXPECT_TRUE(result);
EXPECT_STREQ("Child_2", name.c_str());
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,185 @@
/*
* 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/Casting/numeric_cast.h>
#include <SceneAPI/FbxSceneBuilder/Tests/TestFbxMesh.h>
#include <fbxsdk.h>
#include <AzCore/Casting/lossy_cast.h>
#include <AzCore/Casting/numeric_cast.h>
namespace AZ
{
namespace FbxSDKWrapper
{
TestFbxMesh::TestFbxMesh()
: m_vertexControlPoints(nullptr)
, m_vertexCount(0)
, m_polygonVertexIndices(nullptr)
, m_materialIndices(new FbxLayerElementArrayTemplate<int>(eFbxInt))
, m_uvElements(FbxGeometryElementUV::Create(nullptr, "TestElements_UV"))
, m_vertexColorElements(FbxGeometryElementVertexColor::Create(nullptr, "TestElements_VertexColors"))
, m_expectedVertexCount(0)
{
}
int TestFbxMesh::GetDeformerCount() const
{
// For current test need, only have one skin for the mesh
return m_skin ? 1 : 0;
}
AZStd::shared_ptr<const FbxSkinWrapper> TestFbxMesh::GetSkin(int index) const
{
// For current test need, only have one skin for the mesh
return m_skin;
}
bool TestFbxMesh::GetMaterialIndices(FbxLayerElementArrayTemplate<int>** lockableArray) const
{
*lockableArray = m_materialIndices;
return true;
}
int TestFbxMesh::GetControlPointsCount() const
{
return static_cast<int>(m_vertexCount);
}
AZStd::vector<Vector3> TestFbxMesh::GetControlPoints() const
{
return m_vertexControlPoints;
}
int TestFbxMesh::GetPolygonCount() const
{
return static_cast<int>(m_polygonInfo.size());
}
int TestFbxMesh::GetPolygonSize(int polygonIndex) const
{
if (m_polygonInfo.find(polygonIndex) != m_polygonInfo.end())
{
return aznumeric_caster(m_polygonInfo.find(polygonIndex)->second.m_vertexCount);
}
return -1;
}
int* TestFbxMesh::GetPolygonVertices() const
{
return m_polygonVertexIndices;
}
int TestFbxMesh::GetPolygonVertexIndex(int polygonIndex) const
{
if (m_polygonInfo.find(polygonIndex) != m_polygonInfo.end())
{
return aznumeric_caster(m_polygonInfo.find(polygonIndex)->second.m_startVertexIndex);
}
return -1;
}
FbxUVWrapper TestFbxMesh::GetElementUV(int index)
{
(void)index;
return m_uvElements;
}
int TestFbxMesh::GetElementUVCount() const
{
return 1;
}
FbxVertexColorWrapper TestFbxMesh::GetElementVertexColor(int index)
{
(void)index;
return m_vertexColorElements;
}
int TestFbxMesh::GetElementVertexColorCount() const
{
return 1;
}
bool TestFbxMesh::GetPolygonVertexNormal(int polyIndex, int vertexIndex, Vector3& normal) const
{
normal = Vector3(1.0f, 0.0f, 0.0f);
return true;
}
void TestFbxMesh::CreateMesh(std::vector<AZ::Vector3>& points, std::vector<std::vector<int> >& polygonVertexIndices)
{
m_vertexControlPoints.clear();
m_materialIndices->Clear();
m_polygonInfo.clear();
// Create fbx control point (position) data, and associated material index data
m_vertexCount = aznumeric_caster(points.size());
m_vertexControlPoints.reserve(points.size());
for (unsigned int i = 0; i < points.size(); ++i)
{
m_vertexControlPoints.push_back(Vector3(points[i].GetX(), points[i].GetY(), points[i].GetZ()));
m_materialIndices->Add(i);
}
// Create fbx face data
m_expectedVertexCount = 0;
for (const std::vector<int>& onePolygonIndices : polygonVertexIndices)
{
for (const int& index : onePolygonIndices)
{
m_expectedVertexCount++;
}
}
if (m_polygonVertexIndices)
{
delete m_polygonVertexIndices;
}
m_polygonVertexIndices = new int[m_expectedVertexCount];
size_t i = 0;
for (const std::vector<int>& onePolygonIndices : polygonVertexIndices)
{
m_polygonInfo.insert(std::make_pair<int, TestFbxPolygon>(aznumeric_caster(m_polygonInfo.size()),
TestFbxPolygon(i, aznumeric_caster(onePolygonIndices.size()))));
for (const int& index : onePolygonIndices)
{
m_polygonVertexIndices[i] = index;
i++;
}
}
}
void TestFbxMesh::SetSkin(const AZStd::shared_ptr<FbxSkinWrapper>& skin)
{
m_skin = skin;
}
void TestFbxMesh::CreateExpectMeshInfo(std::vector<std::vector<int> >& expectedFaceVertexIndices)
{
m_expectedFaceVertexIndices = expectedFaceVertexIndices;
}
size_t TestFbxMesh::GetExpectedVetexCount() const
{
return m_expectedVertexCount;
}
size_t TestFbxMesh::GetExpectedFaceCount() const
{
return m_expectedFaceVertexIndices.size();
}
AZ::Vector3 TestFbxMesh::GetExpectedFaceVertexPosition(unsigned int faceIndex, unsigned int vertexIndex) const
{
return m_vertexControlPoints[m_expectedFaceVertexIndices[faceIndex][vertexIndex]];
}
}
}
@@ -0,0 +1,90 @@
#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 <vector>
#include <unordered_map>
#include <AzCore/Math/Vector3.h>
#include <SceneAPI/FbxSDKWrapper/FbxMeshWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSkinWrapper.h>
namespace AZ
{
namespace FbxSDKWrapper
{
struct TestFbxPolygon
{
size_t m_startVertexIndex;
size_t m_vertexCount;
TestFbxPolygon(size_t startVertexIndex, size_t vertexCount)
: m_startVertexIndex(startVertexIndex)
, m_vertexCount(vertexCount)
{
}
};
// TestFbxMesh
// FbxMesh Test Data creation
class TestFbxMesh
: public FbxMeshWrapper
{
public:
TestFbxMesh();
~TestFbxMesh() override = default;
int GetDeformerCount() const override;
AZStd::shared_ptr<const FbxSkinWrapper> GetSkin(int index) const override;
bool GetMaterialIndices(FbxLayerElementArrayTemplate<int>** lockableArray) const override;
int GetControlPointsCount() const;
AZStd::vector<Vector3> GetControlPoints() const override;
int GetPolygonCount() const override;
int GetPolygonSize(int polygonIndex) const override;
int* GetPolygonVertices() const override;
int GetPolygonVertexIndex(int polygonIndex) const;
FbxUVWrapper GetElementUV(int index = 0) override;
int GetElementUVCount() const override;
FbxVertexColorWrapper GetElementVertexColor(int index = 0) override;
int GetElementVertexColorCount() const override;
bool GetPolygonVertexNormal(int polyIndex, int vertexIndex, Vector3& normal) const override;
// Create test data APIs
void CreateMesh(std::vector<AZ::Vector3>& points, std::vector<std::vector<int> >& polygonVertexIndices);
void CreateExpectMeshInfo(std::vector<std::vector<int> >& expectedFaceVertexIndices);
void SetSkin(const AZStd::shared_ptr<FbxSkinWrapper>& skin);
size_t GetExpectedVetexCount() const;
size_t GetExpectedFaceCount() const;
AZ::Vector3 GetExpectedFaceVertexPosition(unsigned int faceIndex, unsigned int vertexIndex) const;
protected:
AZStd::vector<Vector3> m_vertexControlPoints; // vertex positions
size_t m_vertexCount;
int* m_polygonVertexIndices; // store all polygons' vertex indices in sequence. Each index maps to a control point.
FbxLayerElementArrayTemplate<int>* m_materialIndices;
std::unordered_map<int, TestFbxPolygon> m_polygonInfo;
FbxUVWrapper m_uvElements;
FbxVertexColorWrapper m_vertexColorElements;
AZStd::shared_ptr<FbxSkinWrapper> m_skin;
// Expected converted data
unsigned int m_expectedVertexCount;
std::vector<std::vector<int> > m_expectedFaceVertexIndices;
};
}
}
@@ -0,0 +1,38 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/Tests/TestFbxNode.h>
namespace AZ
{
namespace FbxSDKWrapper
{
const std::shared_ptr<FbxMeshWrapper> TestFbxNode::GetMesh() const
{
return m_testFbxMesh;
}
const char* TestFbxNode::GetName() const
{
return m_name.c_str();
}
void TestFbxNode::SetMesh(std::shared_ptr<TestFbxMesh> testFbxMesh)
{
m_testFbxMesh = testFbxMesh;
}
void TestFbxNode::SetName(const char* name)
{
m_name = name;
}
}
}
@@ -0,0 +1,41 @@
#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 <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSceneBuilder/Tests/TestFbxMesh.h>
namespace AZ
{
namespace FbxSDKWrapper
{
// TestFbxNode
// FbxNode Test Data creation
class TestFbxNode
: public FbxNodeWrapper
{
public:
~TestFbxNode() override = default;
const std::shared_ptr<FbxMeshWrapper> GetMesh() const override;
const char* GetName() const override;
void SetMesh(std::shared_ptr<TestFbxMesh> testFbxMesh);
void SetName(const char* name);
protected:
std::shared_ptr<TestFbxMesh> m_testFbxMesh;
AZStd::string m_name;
};
}
}
@@ -0,0 +1,95 @@
/*i
* 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/Casting/numeric_cast.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/Tests/TestFbxSkin.h>
#include <SceneAPI/FbxSceneBuilder/Tests/TestFbxNode.h>
namespace AZ
{
namespace FbxSDKWrapper
{
const char* TestFbxSkin::GetName() const
{
return m_name.c_str();
}
int TestFbxSkin::GetClusterCount() const
{
return aznumeric_caster(m_links.size());
}
int TestFbxSkin::GetClusterControlPointIndicesCount(int index) const
{
return aznumeric_caster(m_controlPointIndices[index].size());
}
int TestFbxSkin::GetClusterControlPointIndex(int clusterIndex, int pointIndex) const
{
return m_controlPointIndices[clusterIndex][pointIndex];
}
double TestFbxSkin::GetClusterControlPointWeight(int clusterIndex, int pointIndex) const
{
return m_weights[clusterIndex][pointIndex];
}
AZStd::shared_ptr<const FbxNodeWrapper> TestFbxSkin::GetClusterLink(int index) const
{
return m_links[index];
}
void TestFbxSkin::SetName(const char* name)
{
m_name = name;
}
void TestFbxSkin::CreateSkinWeightData(AZStd::vector<AZStd::string>& boneNames, AZStd::vector<AZStd::vector<double>>& weights, AZStd::vector<AZStd::vector<int>>& controlPointIndices)
{
m_links.resize(boneNames.size());
for (size_t linkIndex = 0; linkIndex < boneNames.size(); ++linkIndex)
{
m_links[linkIndex] = AZStd::make_shared<FbxSDKWrapper::TestFbxNode>();
m_links[linkIndex]->SetName(boneNames[linkIndex].c_str());
}
m_weights = weights;
m_controlPointIndices = controlPointIndices;
}
void TestFbxSkin::CreateExpectSkinWeightData(AZStd::vector<AZStd::vector<int>>& boneIds, AZStd::vector<AZStd::vector<float>>& weights)
{
m_expectedBoneIds = boneIds;
m_expectedWeights = weights;
}
size_t TestFbxSkin::GetExpectedVertexCount() const
{
return m_expectedBoneIds.size();
}
size_t TestFbxSkin::GetExpectedLinkCount(size_t vertexIndex) const
{
return m_expectedBoneIds[vertexIndex].size();
}
int TestFbxSkin::GetExpectedSkinLinkBoneId(size_t vertexIndex, size_t linkIndex) const
{
return m_expectedBoneIds[vertexIndex][linkIndex];
}
float TestFbxSkin::GetExpectedSkinLinkWeight(size_t vertextIndex, size_t linkIndex) const
{
return m_expectedWeights[vertextIndex][linkIndex];
}
}
}
@@ -0,0 +1,54 @@
#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 <SceneAPI/FbxSDKWrapper/FbxSkinWrapper.h>
#include <SceneAPI/FbxSceneBuilder/Tests/TestFbxNode.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class TestFbxSkin
: public FbxSkinWrapper
{
public:
~TestFbxSkin() override = default;
const char* GetName() const override;
int GetClusterCount() const override;
int GetClusterControlPointIndicesCount(int index) const override;
int GetClusterControlPointIndex(int clusterIndex, int pointIndex) const override;
double GetClusterControlPointWeight(int clusterIndex, int pointIndex) const override;
AZStd::shared_ptr<const FbxNodeWrapper> GetClusterLink(int index) const override;
void SetName(const char* name);
void CreateSkinWeightData(AZStd::vector<AZStd::string>& boneNames, AZStd::vector<AZStd::vector<double>>& weights, AZStd::vector<AZStd::vector<int>>& controlPointIndices);
void CreateExpectSkinWeightData(AZStd::vector<AZStd::vector<int>>& boneIds, AZStd::vector<AZStd::vector<float>>& weights);
size_t GetExpectedVertexCount() const;
size_t GetExpectedLinkCount(size_t vertexIndex) const;
int GetExpectedSkinLinkBoneId(size_t vertexIndex, size_t linkIndex) const;
float GetExpectedSkinLinkWeight(size_t vertexIndex, size_t linkIndex) const;
protected:
AZStd::string m_name;
AZStd::vector<AZStd::shared_ptr<FbxSDKWrapper::TestFbxNode>> m_links;
AZStd::vector<AZStd::vector<double>> m_weights;
AZStd::vector<AZStd::vector<int>> m_controlPointIndices;
AZStd::vector<AZStd::vector<int>> m_expectedBoneIds;
AZStd::vector<AZStd::vector<float>> m_expectedWeights;
};
}
}
@@ -0,0 +1,68 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/Module/DynamicModuleHandle.h>
#include <AzCore/Memory/SystemAllocator.h>
class FbxSceneBuilderTestEnvironment
: public AZ::Test::ITestEnvironment
{
public:
virtual ~FbxSceneBuilderTestEnvironment()
{}
protected:
void SetupEnvironment() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
sceneCoreModule = AZ::DynamicModuleHandle::Create("SceneCore");
AZ_Assert(sceneCoreModule, "FbxSceneBuilder unit tests failed to create SceneCore module.");
bool loaded = sceneCoreModule->Load(false);
AZ_Assert(loaded, "FbxSceneBuilder unit tests failed to load SceneCore module.");
auto init = sceneCoreModule->GetFunction<AZ::InitializeDynamicModuleFunction>(AZ::InitializeDynamicModuleFunctionName);
AZ_Assert(init, "FbxSceneBuilder unit tests failed to find the initialization function the SceneCore module.");
(*init)(AZ::Environment::GetInstance());
sceneDataModule = AZ::DynamicModuleHandle::Create("SceneData");
AZ_Assert(sceneDataModule, "SceneData unit tests failed to create SceneData module.");
loaded = sceneDataModule->Load(false);
AZ_Assert(loaded, "FbxSceneBuilder unit tests failed to load SceneData module.");
init = sceneDataModule->GetFunction<AZ::InitializeDynamicModuleFunction>(AZ::InitializeDynamicModuleFunctionName);
AZ_Assert(init, "FbxSceneBuilder unit tests failed to find the initialization function the SceneData module.");
(*init)(AZ::Environment::GetInstance());
}
void TeardownEnvironment() override
{
auto uninit = sceneDataModule->GetFunction<AZ::UninitializeDynamicModuleFunction>(AZ::UninitializeDynamicModuleFunctionName);
AZ_Assert(uninit, "FbxSceneBuilder unit tests failed to find the uninitialization function the SceneData module.");
(*uninit)();
sceneDataModule.reset();
uninit = sceneCoreModule->GetFunction<AZ::UninitializeDynamicModuleFunction>(AZ::UninitializeDynamicModuleFunctionName);
AZ_Assert(uninit, "FbxSceneBuilder unit tests failed to find the uninitialization function the SceneCore module.");
(*uninit)();
sceneCoreModule.reset();
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
private:
AZStd::unique_ptr<AZ::DynamicModuleHandle> sceneCoreModule;
AZStd::unique_ptr<AZ::DynamicModuleHandle> sceneDataModule;
};
AZ_UNIT_TEST_HOOK(new FbxSceneBuilderTestEnvironment);
@@ -0,0 +1,55 @@
#
# 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.
#
set(FILES
FbxSceneBuilderConfiguration.h
FbxImportRequestHandler.h
FbxImportRequestHandler.cpp
FbxImporter.h
FbxImporter.cpp
FbxSceneSystem.h
FbxSceneSystem.cpp
ImportContexts/ImportContexts.h
ImportContexts/ImportContexts.cpp
ImportContexts/FbxImportContexts.h
ImportContexts/FbxImportContexts.cpp
Importers/FbxAnimationImporter.h
Importers/FbxAnimationImporter.cpp
Importers/FbxBoneImporter.h
Importers/FbxBoneImporter.cpp
Importers/FbxBlendShapeImporter.h
Importers/FbxBlendShapeImporter.cpp
Importers/FbxColorStreamImporter.h
Importers/FbxColorStreamImporter.cpp
Importers/FbxTangentStreamImporter.h
Importers/FbxTangentStreamImporter.cpp
Importers/FbxBitangentStreamImporter.h
Importers/FbxBitangentStreamImporter.cpp
Importers/FbxImporterUtilities.h
Importers/FbxImporterUtilities.inl
Importers/FbxImporterUtilities.cpp
Importers/FbxMaterialImporter.h
Importers/FbxMaterialImporter.cpp
Importers/FbxMeshImporter.h
Importers/FbxMeshImporter.cpp
Importers/FbxSkinImporter.h
Importers/FbxSkinImporter.cpp
Importers/FbxSkinWeightsImporter.h
Importers/FbxSkinWeightsImporter.cpp
Importers/FbxTransformImporter.h
Importers/FbxTransformImporter.cpp
Importers/FbxUvMapImporter.h
Importers/FbxUvMapImporter.cpp
Importers/Utilities/FbxMeshImporterUtilities.h
Importers/Utilities/FbxMeshImporterUtilities.cpp
Importers/Utilities/RenamedNodesMap.h
Importers/Utilities/RenamedNodesMap.cpp
)
@@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
DllMain.cpp
)
@@ -0,0 +1,16 @@
#
# 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.
#
set(FILES
Tests/TestsMain.cpp
Tests/Importers/FbxImporterUtilitiesTests.cpp
Tests/Importers/Utilities/RenamedNodesMapTests.cpp
)