Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -9,9 +9,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
set(sdkwrapper_dir ${CMAKE_CURRENT_LIST_DIR}/../SDKWrapper)
set(sdkwrapper_pal_dir ${sdkwrapper_dir}/Platform/${PAL_PLATFORM_NAME})
if (NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
@@ -23,9 +21,6 @@ ly_add_target(
FILES_CMAKE
fbxsdkwrapper_files.cmake
${sdkwrapper_dir}/sdkwrapper_files.cmake
${sdkwrapper_pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
@@ -37,4 +32,5 @@ ly_add_target(
AZ::AzToolsFramework
PUBLIC
3rdParty::FbxSdk
3rdParty::assimplib
)
@@ -102,7 +102,7 @@ namespace AZ
return 10.f;
}
uint64_t FbxMaterialWrapper::GetUniqueId() const
AZ::u64 FbxMaterialWrapper::GetUniqueId() const
{
return m_fbxMaterial->GetUniqueID();
}
@@ -38,7 +38,7 @@ namespace AZ
AZ::Vector3 GetEmissiveColor() const override;
float GetOpacity() const override;
float GetShininess() const override;
uint64_t GetUniqueId() const override;
AZ::u64 GetUniqueId() const override;
};
} // namespace FbxSDKWrapper
} // namespace AZ
@@ -1,12 +0,0 @@
#
# 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.
#
@@ -1,12 +0,0 @@
#
# 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.
#
@@ -1,16 +0,0 @@
#
# 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(LY_BUILD_DEPENDENCIES
PUBLIC
3rdParty::AssImp
)
set(LY_COMPILE_DEFINITIONS PUBLIC ASSET_IMPORTER_SDK_SUPPORTED_TRAIT)
@@ -19,13 +19,18 @@
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
#include <SceneAPI/FbxSceneBuilder/FbxImporter.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.h>
#endif
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBoneImporter.h>
@@ -39,7 +44,6 @@
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxUvMapImporter.h>
namespace AZ
{
namespace SceneAPI
@@ -86,13 +90,19 @@ namespace AZ
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(AssImpBitangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpColorStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMaterialImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMeshImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpTangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpTransformImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpUvMapImporter::CreateDescriptor());
#endif
g_componentDescriptors.push_back(AssImpSkinImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpSkinWeightsImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpBoneImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpAnimationImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpBlendShapeImporter::CreateDescriptor());
for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors)
{
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Handler::RegisterComponentDescriptor, descriptor);
@@ -21,10 +21,8 @@
#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>
@@ -32,10 +30,8 @@
#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
{
@@ -59,7 +55,7 @@ namespace AZ
FbxImporter::FbxImporter()
: m_sceneSystem(new FbxSceneSystem())
{
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
if (m_useAssetImporterSDK)
{
m_sceneWrapper = AZStd::make_unique<AssImpSDKWrapper::AssImpSceneWrapper>();
@@ -68,9 +64,7 @@ namespace AZ
{
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
}
#else
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
#endif
BindToCall(&FbxImporter::ImportProcessing);
}
@@ -99,12 +93,10 @@ namespace AZ
{
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()))
{
@@ -284,7 +276,7 @@ namespace AZ
return true;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool FbxImporter::ConvertFbxScene(Containers::Scene& scene) const
{
std::shared_ptr<SDKNode::NodeWrapper> fbxRoot = m_sceneWrapper->GetRootNode();
@@ -333,6 +325,8 @@ namespace AZ
continue;
}
AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node);
SanitizeNodeName(nodeName);
AZ_TraceContext("SceneAPI Node Name", nodeName);
Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str());
@@ -431,7 +425,13 @@ namespace AZ
return true;
}
#endif
void FbxImporter::SanitizeNodeName(AZStd::string& nodeName) const
{
// Replace % with something else so it is safe for use in printfs.
AZStd::replace(nodeName.begin(), nodeName.end(), '%', '_');
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -46,15 +46,12 @@ namespace AZ
protected:
bool ConvertFbxSceneContext(Containers::Scene& scene) const;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool ConvertFbxScene(Containers::Scene& scene) const;
#endif
void SanitizeNodeName(AZStd::string& nodeName) const;
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
@@ -13,12 +13,9 @@
#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
@@ -52,7 +49,6 @@ namespace AZ
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);
@@ -135,7 +131,6 @@ namespace AZ
m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
}
}
#endif
}
void FbxSceneSystem::SwapVec3ForUpAxis(Vector3& swapVector) const
@@ -0,0 +1,610 @@
/*
* 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 <AssImpTypeConverter.h>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimCurveWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimLayerWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxTimeSpanWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpAnimationImporter::s_animationNodeName = "animation";
const FbxSDKWrapper::FbxTimeWrapper::TimeMode AssImpAnimationImporter::s_defaultTimeMode =
FbxSDKWrapper::FbxTimeWrapper::frames30;
AssImpAnimationImporter::AssImpAnimationImporter()
{
BindToCall(&AssImpAnimationImporter::ImportAnimation);
}
void AssImpAnimationImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
AZStd::string GetName(const aiMeshAnim* anim)
{
return anim->mName.C_Str();
}
AZStd::string GetName(const aiNodeAnim* anim)
{
return anim->mNodeName.C_Str();
}
AZStd::string GetName(const aiMeshMorphAnim* anim)
{
return anim->mName.C_Str();
}
struct ConsolidatedNodeAnim
{
ConsolidatedNodeAnim() = default;
ConsolidatedNodeAnim(const ConsolidatedNodeAnim& other) = delete;
ConsolidatedNodeAnim(ConsolidatedNodeAnim&& other) noexcept
: mNumPositionKeys{ other.mNumPositionKeys },
mPositionKeys{ other.mPositionKeys },
mNumRotationKeys{ other.mNumRotationKeys },
mRotationKeys{ other.mRotationKeys },
mNumScalingKeys{ other.mNumScalingKeys },
mScalingKeys{ other.mScalingKeys },
m_ownedPositionKeys{ std::move(other.m_ownedPositionKeys) },
m_ownedScalingKeys{ std::move(other.m_ownedScalingKeys) },
m_ownedRotationKeys{ std::move(other.m_ownedRotationKeys) },
mPreState{ other.mPreState },
mPostState{ other.mPostState }
{
}
ConsolidatedNodeAnim& operator=(const ConsolidatedNodeAnim& other) = delete;
ConsolidatedNodeAnim& operator=(ConsolidatedNodeAnim&& other) noexcept
{
if (this == &other)
{
return *this;
}
mNumPositionKeys = other.mNumPositionKeys;
mPositionKeys = other.mPositionKeys;
mNumRotationKeys = other.mNumRotationKeys;
mRotationKeys = other.mRotationKeys;
mNumScalingKeys = other.mNumScalingKeys;
mScalingKeys = other.mScalingKeys;
m_ownedPositionKeys = std::move(other.m_ownedPositionKeys);
m_ownedScalingKeys = std::move(other.m_ownedScalingKeys);
m_ownedRotationKeys = std::move(other.m_ownedRotationKeys);
mPreState = other.mPreState;
mPostState = other.mPostState;
return *this;
}
// These variables are named using AssImp naming convention for consistency
unsigned int mNumPositionKeys{};
aiVectorKey* mPositionKeys{};
unsigned int mNumRotationKeys{};
aiQuatKey* mRotationKeys{};
unsigned int mNumScalingKeys{};
aiVectorKey* mScalingKeys{};
AZStd::vector<aiVectorKey> m_ownedPositionKeys{};
AZStd::vector<aiVectorKey> m_ownedScalingKeys{};
AZStd::vector<aiQuatKey> m_ownedRotationKeys{};
aiAnimBehaviour mPreState{};
aiAnimBehaviour mPostState{};
};
AZStd::pair<const aiAnimation*, ConsolidatedNodeAnim> MakeMyPair(const aiAnimation* animation, const aiNodeAnim* anim)
{
ConsolidatedNodeAnim consolidatedNodeAnim{};
consolidatedNodeAnim.mNumRotationKeys = anim->mNumRotationKeys;
consolidatedNodeAnim.mNumPositionKeys = anim->mNumPositionKeys;
consolidatedNodeAnim.mNumScalingKeys = anim->mNumScalingKeys;
consolidatedNodeAnim.mRotationKeys = anim->mRotationKeys;
consolidatedNodeAnim.mPositionKeys = anim->mPositionKeys;
consolidatedNodeAnim.mScalingKeys = anim->mScalingKeys;
return {animation, AZStd::move(consolidatedNodeAnim)};
}
auto MakeMyPair(const aiAnimation* animation, const aiMeshAnim* anim)
{
return AZStd::make_pair(animation, anim);
}
auto MakeMyPair(const aiAnimation* animation, const aiMeshMorphAnim* anim)
{
return AZStd::make_pair(animation, anim);
}
Events::ProcessingResult AssImpAnimationImporter::ImportAnimation(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Animation");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
// Add check for animation layers at the scene level.
if (!scene->HasAnimations() || IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
AZStd::unordered_multimap<AZStd::string, AZStd::pair<const aiAnimation*, ConsolidatedNodeAnim>> boneAnimations;
typedef AZStd::pair<const aiAnimation*, const aiMeshMorphAnim*> AnimAndMorphAnim;
typedef AZStd::unordered_map<AZStd::string, AnimAndMorphAnim> ChannelToMorphAnim;
typedef AZStd::unordered_map<AZStd::string, ChannelToMorphAnim> NodeToChannelToMorphAnim;
NodeToChannelToMorphAnim meshMorphAnimations;
// Goes through all the animation channels of a given type and adds them to a map so we can easily find
// all the animations for a given node
// In the case of bone animations, the data is copied into a ConsolidatedNodeAnim so we can
// do fix-ups later without affecting the original data
auto mapAnimationsFunc = [](unsigned numChannels, auto** channels, const aiAnimation* animation, auto& map)
{
map.reserve(numChannels);
for (unsigned channelIndex = 0; channelIndex < numChannels; ++channelIndex)
{
auto* nodeAnim = channels[channelIndex];
AZStd::string name = GetName(nodeAnim);
map.emplace(name, MakeMyPair(animation, nodeAnim));
}
};
for (unsigned animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex)
{
const aiAnimation* animation = scene->mAnimations[animIndex];
mapAnimationsFunc(animation->mNumChannels, animation->mChannels, animation, boneAnimations);
for (unsigned channelIndex = 0; channelIndex < animation->mNumMorphMeshChannels; ++channelIndex)
{
auto* nodeAnim = animation->mMorphMeshChannels[channelIndex];
AZStd::string name = GetName(nodeAnim);
AZStd::vector<AZStd::string> meshNodeNameAndChannel;
// Morph target animations include the channel in the name,
// so if a mesh is named Mesh01, the morph target for the first channel
// will be named Mesh01*0
AZ::StringFunc::Tokenize(name, meshNodeNameAndChannel, '*');
if (meshNodeNameAndChannel.size() != 2)
{
AZ_Error(
"AnimationImporter", false,
"Morph animation name %s was not in the expected format of: node name, asterisk, node channel. "
"Example: 'NodeName*0'",
name.c_str());
continue;
}
AZStd::string meshNodeName(meshNodeNameAndChannel[0]);
AZStd::string channel(meshNodeNameAndChannel[1]);
meshMorphAnimations[meshNodeName][channel] = AnimAndMorphAnim(animation, nodeAnim);
}
}
// Go through all the bone animations and find any that reference a pivot node
// We'll make a new node anim and store all the combined animation channels there
// with the name set to the base bone name
decltype(boneAnimations) combinedAnimations;
for (auto&& animation : boneAnimations)
{
size_t pos = AZ::StringFunc::Find(animation.first, PivotNodeMarker, 0);
if (pos != animation.first.npos)
{
AZStd::string_view name, part;
SplitPivotNodeName(aiString(animation.first.c_str()), pos, name, part);
auto&& iterator = combinedAnimations.find(name);
if (iterator == combinedAnimations.end())
{
combinedAnimations.emplace(AZStd::string(name), AZStd::move(animation.second));
iterator = combinedAnimations.find(name);
}
if (iterator != combinedAnimations.end())
{
auto& existingNode = iterator->second.second;
auto&& src = animation.second.second;
if (part == "Translation")
{
existingNode.mNumPositionKeys = src.mNumPositionKeys;
existingNode.mPositionKeys = src.mPositionKeys;
}
else if (part == "Rotation")
{
existingNode.mNumRotationKeys = src.mNumRotationKeys;
existingNode.mRotationKeys = src.mRotationKeys;
}
else if (part == "Scaling")
{
existingNode.mNumScalingKeys = src.mNumScalingKeys;
existingNode.mScalingKeys = src.mScalingKeys;
}
}
}
}
if (!combinedAnimations.empty())
{
boneAnimations.swap(combinedAnimations);
}
Events::ProcessingResultCombiner combinedAnimationResult;
for (unsigned meshIndex = 0; meshIndex < currentNode->mNumMeshes; ++meshIndex)
{
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[meshIndex]];
if (NodeToChannelToMorphAnim::iterator channelsForMeshName = meshMorphAnimations.find(mesh->mName.C_Str());
channelsForMeshName != meshMorphAnimations.end())
{
const auto [nodeIterName, channels] = *channelsForMeshName;
for (const auto& [channel, animAndMorphAnim] : channels)
{
const auto& [animation, morphAnimation] = animAndMorphAnim;
combinedAnimationResult += ImportBlendShapeAnimation(
context, animation, morphAnimation, mesh);
}
}
}
AZStd::string nodeName = s_animationNodeName;
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZ_TraceContext("Animation node name", nodeName);
// If there are no bone animations, but there are mesh animations,
// then a stub animation needs to be created so the exporter can create the exported morph target animation.
if (boneAnimations.empty() && !meshMorphAnimations.empty())
{
const aiAnimation* animation = scene->mAnimations[0];
// Morph animations need a regular animation on the node, as well.
// If there is no bone animation on the current node, then generate one here.
AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::AnimationData>();
createdAnimationData->ReserveKeyFrames(
animation->mDuration +
1); // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1
createdAnimationData->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
// Set every frame of the animation to the start location of the node.
aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
createdAnimationData->AddKeyFrame(localTransform);
}
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 combinedAnimationResult.GetResult();
}
decltype(boneAnimations) parentFillerAnimations;
// Go through all the animations and make sure we create animations for bones who's parents don't have an animation
for (auto&& anim : boneAnimations)
{
aiNode* node = scene->mRootNode->FindNode(anim.first.c_str());
aiNode* parent = node->mParent;
while (parent && parent != scene->mRootNode)
{
if (!IsPivotNode(parent->mName))
{
if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() &&
parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end())
{
// Create 1 key for each type that just copies the current transform
ConsolidatedNodeAnim emptyAnimation;
aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent);
aiVector3D position, scale;
aiQuaternion rotation;
globalTransform.Decompose(scale, rotation, position);
emptyAnimation.mNumRotationKeys = emptyAnimation.mNumPositionKeys = emptyAnimation.mNumScalingKeys = 1;
emptyAnimation.m_ownedPositionKeys.emplace_back(0, position);
emptyAnimation.mPositionKeys = emptyAnimation.m_ownedPositionKeys.data();
emptyAnimation.m_ownedRotationKeys.emplace_back(0, rotation);
emptyAnimation.mRotationKeys = emptyAnimation.m_ownedRotationKeys.data();
emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale);
emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data();
parentFillerAnimations.insert(
AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation))));
}
}
parent = parent->mParent;
}
}
boneAnimations.insert(AZStd::make_move_iterator(parentFillerAnimations.begin()), AZStd::make_move_iterator(parentFillerAnimations.end()));
auto animItr = boneAnimations.equal_range(currentNode->mName.C_Str());
if (animItr.first == animItr.second)
{
return combinedAnimationResult.GetResult();
}
bool onlyOne = false;
for (auto it = animItr.first; it != animItr.second; ++it)
{
if (onlyOne)
{
AZ_Error("AnimationImporter", false, "Bone %s has multiple animations. Only 1 animation per bone is supported", currentNode->mName.C_Str());
break;
}
const aiAnimation* animation = it->second.first;
const ConsolidatedNodeAnim* anim = &it->second.second;
// We don't currently handle having a different number of keys, with 1 exception:
// 1 key is essentially a constant so we do handle that case
if ((anim->mNumPositionKeys != anim->mNumRotationKeys && anim->mNumPositionKeys > 1 && anim->mNumRotationKeys > 1) ||
(anim->mNumPositionKeys != anim->mNumScalingKeys && anim->mNumPositionKeys > 1 && anim->mNumScalingKeys > 1) ||
(anim->mNumRotationKeys != anim->mNumScalingKeys && anim->mNumRotationKeys > 1 && anim->mNumScalingKeys > 1))
{
AZ_Error("AnimationImporter", false, "Bone Animation with different number of position (%d)/rotation (%d)/scaling (%d) keys not supported",
anim->mNumPositionKeys, anim->mNumRotationKeys, anim->mNumScalingKeys);
return Events::ProcessingResult::Failure;
}
unsigned numAnimationKeys = anim->mNumPositionKeys;
if (numAnimationKeys <= 1)
{
numAnimationKeys = AZStd::GetMax(anim->mNumRotationKeys, anim->mNumScalingKeys);
}
auto sampleKeyFrame = [](const auto& keys, unsigned numKeys, double time)
{
AZ_Error("AnimationImporter", numKeys > 0, "Animation key set must have at least 1 key");
if (numKeys == 1)
{
return keys[0].mValue;
}
auto returnValue = keys[0].mValue;
for (unsigned keyIndex = 0; keyIndex < numKeys; ++keyIndex)
{
const auto& key = keys[keyIndex];
// We want to return the key that exactly matches the time if possible, otherwise we'll keep track of the previous time
// If we don't find an exact match and end up going past the desired time (or run out of keyframes) then we return the previous key
if (key.mTime < time)
{
returnValue = key.mValue;
}
else if (key.mTime == time)
{
return key.mValue;
}
else
{
return returnValue;
}
}
return returnValue;
};
AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::AnimationData>();
createdAnimationData->ReserveKeyFrames(animation->mDuration + 1); // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1
createdAnimationData->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
auto scale = sampleKeyFrame(anim->mScalingKeys, anim->mNumScalingKeys, time);
auto position = sampleKeyFrame(anim->mPositionKeys, anim->mNumPositionKeys, time);
auto rotation = sampleKeyFrame(anim->mRotationKeys, anim->mNumRotationKeys, time);
aiMatrix4x4 transform(scale, rotation, position);
DataTypes::MatrixType animTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(animTransform);
context.m_sourceSceneSystem.ConvertBoneUnit(animTransform);
createdAnimationData->AddKeyFrame(animTransform);
}
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, nodeName.c_str(), AZStd::move(createdAnimationData));
context.m_scene.GetGraph().MakeEndPoint(addNode);
onlyOne = true;
}
combinedAnimationResult += Events::ProcessingResult::Success;
return combinedAnimationResult.GetResult();
}
Events::ProcessingResult AssImpAnimationImporter::ImportBlendShapeAnimation(
AssImpSceneNodeAppendedContext& context,
const aiAnimation* animation,
const aiMeshMorphAnim* meshMorphAnim,
const aiMesh* mesh)
{
if (meshMorphAnim->mNumKeys == 0)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedAnimationResult;
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
// In:
// Key index
// Time
// Values in AssImp, Channel in FBX SDK
// Weights in AssImp, Values in FBX SDK
// Num values & weights
// Out:
// One BlendShapeAnimationData per value (Channel in FBX SDK) index
// SetTimeStepBetweenFrames set on the animation data
// Keyframes. Weights (Values in FBX SDK) per key time.
// Keyframes generated for every single frame of the animation.
// Helper class to store key data, when translating from AssImp layout to the engine's scene format.
struct KeyData
{
KeyData(float weight, float time) :
m_weight(weight),
m_time(time)
{
}
bool operator<(const KeyData& other) const
{
return m_time < other.m_time;
}
// Naming in the previous SDK (FBX SDK) and in the engine's scene format
// doesn't match AssImp's naming convention.
// weight here is the AssImp's name for the data, it was named value in FBX SDK.
float m_weight = 0;
float m_time = 0;
};
typedef AZStd::map<int, AZStd::vector<KeyData>> ValueToKeyDataMap;
ValueToKeyDataMap valueToKeyDataMap;
for (int keyIdx = 0; keyIdx < meshMorphAnim->mNumKeys; keyIdx++)
{
aiMeshMorphKey& key = meshMorphAnim->mKeys[keyIdx];
for (int valIdx = 0; valIdx < key.mNumValuesAndWeights; ++valIdx)
{
int currentValue = key.mValues[valIdx];
KeyData thisKey(key.mWeights[valIdx], key.mTime);
valueToKeyDataMap[currentValue].insert(
AZStd::upper_bound(valueToKeyDataMap[currentValue].begin(), valueToKeyDataMap[currentValue].end(),thisKey),
thisKey);
}
}
for (const auto& [meshIdx, keys] : valueToKeyDataMap)
{
AZStd::shared_ptr<SceneData::GraphData::BlendShapeAnimationData> morphAnimNode =
AZStd::make_shared<SceneData::GraphData::BlendShapeAnimationData>();
morphAnimNode->ReserveKeyFrames(animation->mDuration + 1);
morphAnimNode->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
aiAnimMesh* aiAnimMesh = mesh->mAnimMeshes[meshIdx];
AZStd::string_view nodeName(aiAnimMesh->mName.C_Str());
const unsigned maxKeys = keys.size();
unsigned keyIdx = 0;
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
if (keyIdx < maxKeys - 1 && time >= keys[keyIdx+1].m_time)
{
++keyIdx;
}
float weight_value = keys[keyIdx].m_weight;
if (keyIdx < maxKeys - 1)
{
float nextWeight = keys[keyIdx+1].m_weight;
float normalizedTimeBetweenFrames = 0;
if (keys[keyIdx + 1].m_time != keys[keyIdx].m_time)
{
normalizedTimeBetweenFrames =
(time - keys[keyIdx].m_time) / (keys[keyIdx + 1].m_time - keys[keyIdx].m_time);
}
else
{
AZ_Warning("AnimationImporter", false,
"Morph target mesh %s has keys with duplicate time, at indices %d and %d. The second will be ignored.",
nodeName.data(),
keyIdx,
keyIdx+1);
}
// AssImp and FBX both only support linear interpolation for blend shapes.
weight_value = AZ::Lerp(weight_value, nextWeight, normalizedTimeBetweenFrames);
}
morphAnimNode->AddKeyFrame(weight_value);
}
const size_t dotIndex = nodeName.find_last_of('.');
nodeName = nodeName.substr(dotIndex + 1);
morphAnimNode->SetBlendShapeName(nodeName.data());
AZStd::string animNodeName(AZStd::string::format("%s_%s", s_animationNodeName, nodeName.data()));
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, animNodeName.c_str(), AZStd::move(morphAnimNode));
context.m_scene.GetGraph().MakeEndPoint(addNode);
}
return Events::ProcessingResult::Success;
}
} // 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/FbxSDKWrapper/FbxTimeWrapper.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
struct aiAnimation;
struct aiMesh;
struct aiMeshMorphAnim;
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpAnimationImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpAnimationImporter, "{93b3f4e3-6fcd-42b9-a74e-5923f76d25c7}", SceneCore::LoadingComponent);
AssImpAnimationImporter();
~AssImpAnimationImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportAnimation(AssImpSceneNodeAppendedContext& context);
Events::ProcessingResult ImportBlendShapeAnimation(
AssImpSceneNodeAppendedContext& context,
const aiAnimation* animation,
const aiMeshMorphAnim* meshMorphAnim,
const aiMesh* mesh);
protected:
static const char* s_animationNodeName;
static const FbxSDKWrapper::FbxTimeWrapper::TimeMode s_defaultTimeMode;
};
} // 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/AssImpBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpBitangentStreamImporter::m_defaultNodeName = "Bitangent";
AssImpBitangentStreamImporter::AssImpBitangentStreamImporter()
{
BindToCall(&AssImpBitangentStreamImporter::ImportBitangentStreams);
}
void AssImpBitangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpBitangentStreamImporter::ImportBitangentStreams(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);
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct bitangent stream attribute for invalid or non-mesh parent data");
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 || sdkMeshIndex >= currentNode->mNumMeshes)
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct bitangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
return Events::ProcessingResult::Failure;
}
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->HasTangentsAndBitangents())
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> bitangentStream =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexBitangentData>();
// AssImp only has one bitangentStream per mesh.
bitangentStream->SetBitangentSetIndex(0);
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
bitangentStream->ReserveContainerSpace(vertexCount);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
const Vector3 bitangent(
AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
bitangentStream->AppendBitangent(bitangent);
}
AZStd::string nodeName(AZStd::string::format("%s",m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult bitangentResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, nodeName.c_str());
bitangentResults = Events::Process(dataPopulated);
if (bitangentResults != Events::ProcessingResult::Failure)
{
bitangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
return bitangentResults;
}
} // 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 AssImpBitangentStreamImporter : public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBitangentStreamImporter, "{49FC818A-956F-43DA-BBAC-73198E0C5A1F}", SceneCore::LoadingComponent);
AssImpBitangentStreamImporter();
~AssImpBitangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBitangentStreams(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,172 @@
/*
* 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/AssImpBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.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>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpBlendShapeImporter::AssImpBlendShapeImporter()
{
BindToCall(&AssImpBlendShapeImporter::ImportBlendShapes);
}
void AssImpBlendShapeImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBlendShapeImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpBlendShapeImporter::ImportBlendShapes(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Blend Shapes");
int numMesh = context.m_sourceNode.GetAssImpNode()->mNumMeshes;
bool animMeshExists = false;
for (int idx = 0; idx < numMesh; idx++)
{
int meshId = context.m_sourceNode.GetAssImpNode()->mMeshes[idx];
aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshId];
if (aiMesh->mNumAnimMeshes)
{
animMeshExists = true;
break;
}
}
if (!animMeshExists)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedBlendShapeResult;
for (int meshIdx = 0; meshIdx < numMesh; meshIdx++)
{
int meshId = context.m_sourceNode.GetAssImpNode()->mMeshes[meshIdx];
aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshId];
if (!aiMesh->mNumAnimMeshes)
{
continue;
}
for (int animIdx = 0; animIdx < aiMesh->mNumAnimMeshes; animIdx++)
{
AZStd::shared_ptr<SceneData::GraphData::BlendShapeData> blendShapeData =
AZStd::make_shared<SceneData::GraphData::BlendShapeData>();
aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[animIdx];
AZStd::string nodeName(aiAnimMesh->mName.C_Str());
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);
int firstMeshVertexIndex = -1;
int previousMeshVertexIndex = -1;
int verticesInMeshFace = 0;
for (int vertIdx = 0; vertIdx < aiAnimMesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mVertices[vertIdx]));
context.m_sourceSceneSystem.SwapVec3ForUpAxis(vertex);
context.m_sourceSceneSystem.ConvertUnit(vertex);
AZ::Vector3 normal;
if (aiAnimMesh->HasNormals())
{
normal = AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mNormals[vertIdx]);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(normal);
normal.NormalizeSafe();
}
blendShapeData->AddVertex(vertex, normal);
blendShapeData->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
}
// aiAnimMesh just has a list of positions for vertices. The face indices are on the original mesh.
for (int faceIdx = 0; faceIdx < aiMesh->mNumFaces; ++faceIdx)
{
aiFace face = aiMesh->mFaces[faceIdx];
DataTypes::IBlendShapeData::Face blendFace;
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 for node %s has a face with %d vertices, only 3 vertices are supported per face.",
nodeName.c_str(),
face.mNumIndices);
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
blendFace.vertexIndex[idx] = face.mIndices[idx];
}
blendShapeData->AddFace(blendFace);
}
// Report problem if no vertex or face converted to MeshData
if (blendShapeData->GetVertexCount() <= 0 || blendShapeData->GetFaceCount() <= 0)
{
AZ_Error(Utilities::ErrorWindow, false, "Missing geometry data in blendshape node %s.", nodeName.c_str());
return Events::ProcessingResult::Failure;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult blendShapeResult;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, blendShapeData, newIndex, nodeName);
blendShapeResult = Events::Process(dataPopulated);
if (blendShapeResult != Events::ProcessingResult::Failure)
{
blendShapeResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedBlendShapeResult += blendShapeResult;
}
}
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/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpBlendShapeImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBlendShapeImporter, "{B0F7174B-9863-4C03-BFB2-83BF29B1A2DD}", SceneCore::LoadingComponent);
AssImpBlendShapeImporter();
~AssImpBlendShapeImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBlendShapes(AssImpSceneNodeAppendedContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,197 @@
/*
* 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/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/RootBoneData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpBoneImporter::AssImpBoneImporter()
{
BindToCall(&AssImpBoneImporter::ImportBone);
}
void AssImpBoneImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBoneImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
void EnumBonesInNode(
const aiScene* scene, const aiNode* node, AZStd::unordered_map<AZStd::string, aiNode*>& mainBoneList,
AZStd::unordered_map<AZStd::string, aiBone*>& boneLookup)
{
/* From AssImp Documentation
a) Create a map or a similar container to store which nodes are necessary for the skeleton. Pre-initialise it for all nodes with a "no".
b) For each bone in the mesh:
b1) Find the corresponding node in the scene's hierarchy by comparing their names.
b2) Mark this node as "yes" in the necessityMap.
b3) Mark all of its parents the same way until you 1) find the mesh's node or 2) the parent of the mesh's node.
c) Recursively iterate over the node hierarchy
c1) If the node is marked as necessary, copy it into the skeleton and check its children
c2) If the node is marked as not necessary, skip it and do not iterate over its children.
*/
for (unsigned meshIndex = 0; meshIndex < node->mNumMeshes; ++meshIndex)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[meshIndex]];
for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
{
aiBone* bone = mesh->mBones[boneIndex];
aiNode* boneNode = scene->mRootNode->FindNode(bone->mName);
aiNode* boneParent = boneNode->mParent;
mainBoneList[bone->mName.C_Str()] = boneNode;
boneLookup[bone->mName.C_Str()] = bone;
while (boneParent && boneParent != node && boneParent != node->mParent && boneParent != scene->mRootNode)
{
mainBoneList[boneParent->mName.C_Str()] = boneParent;
boneParent = boneParent->mParent;
}
}
}
}
void EnumChildren(
const aiScene* scene, const aiNode* node, AZStd::unordered_map<AZStd::string, aiNode*>& mainBoneList,
AZStd::unordered_map<AZStd::string, aiBone*>& boneLookup)
{
EnumBonesInNode(scene, node, mainBoneList, boneLookup);
for (unsigned childIndex = 0; childIndex < node->mNumChildren; ++childIndex)
{
const aiNode* child = node->mChildren[childIndex];
EnumChildren(scene, child, mainBoneList, boneLookup);
}
}
Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Bone");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
bool isBone = false;
if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid()))
{
isBone = true;
}
else
{
AZStd::unordered_map<AZStd::string, aiNode*> mainBoneList;
AZStd::unordered_map<AZStd::string, aiBone*> boneLookup;
EnumChildren(scene, scene->mRootNode, mainBoneList, boneLookup);
if (mainBoneList.find(currentNode->mName.C_Str()) != mainBoneList.end())
{
isBone = true;
}
// If we have an animation, the bones will be listed in there
if (!isBone)
{
for(unsigned animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex)
{
aiAnimation* animation = scene->mAnimations[animIndex];
for (unsigned channelIndex = 0; channelIndex < animation->mNumChannels; ++channelIndex)
{
aiNodeAnim* nodeAnim = animation->mChannels[channelIndex];
if (nodeAnim->mNodeName == currentNode->mName)
{
isBone = true;
break;
}
}
if (isBone)
{
break;
}
}
}
}
if(!isBone)
{
return Events::ProcessingResult::Ignored;
}
// 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>();
}
aiMatrix4x4 transform = currentNode->mTransformation;
aiNode* parent = currentNode->mParent;
while (parent)
{
transform = parent->mTransformation * transform;
parent = parent->mParent;
}
SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform);
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/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpBoneImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBoneImporter, "{E7A62DE7-B660-4920-BF91-32738175D5A7}", SceneCore::LoadingComponent);
AssImpBoneImporter();
~AssImpBoneImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -58,11 +58,10 @@ namespace AZ
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()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct color stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
@@ -71,9 +70,7 @@ namespace AZ
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
if (sdkMeshIndex < 0)
{
AZ_Error(
Utilities::ErrorWindow,
false,
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;
}
@@ -0,0 +1,94 @@
/*
* 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/AssImpImporterUtilities.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
bool IsSkinnedMesh(const aiNode& node, const aiScene& scene)
{
unsigned boneCount = 0;
for (unsigned mesh = 0; mesh < node.mNumMeshes; ++mesh)
{
if (scene.mMeshes[node.mMeshes[mesh]]->HasBones())
{
++boneCount;
}
}
if (boneCount > 1 && boneCount != node.mNumMeshes)
{
AZ_Error("AssImpImporterUtilities", false, "Node has %d meshes but only %d are skinned. "
"This is unexpected and may result in errors", node.mNumMeshes, boneCount);
}
return boneCount > 0;
}
bool IsPivotNode(const aiString& nodeName, size_t* pos)
{
AZStd::string_view name(nodeName.C_Str(), nodeName.length);
size_t myPos;
if (!pos)
{
pos = &myPos;
}
*pos = AZ::StringFunc::Find(name, PivotNodeMarker);
return *pos != name.npos;
}
void SplitPivotNodeName(const aiString& nodeName, size_t pivotPos, AZStd::string_view& baseNodeName, AZStd::string_view& pivotType)
{
AZStd::string_view nodeNameView(nodeName.data, nodeName.length);
baseNodeName = AZStd::string_view(nodeNameView.substr(0, pivotPos));
pivotType = AZStd::string_view(nodeNameView.substr(pivotPos + sizeof PivotNodeMarker - 1));
}
aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode)
{
aiNode* parent = currentNode->mParent;
aiMatrix4x4 combinedTransform = currentNode->mTransformation;
while (parent)
{
size_t pos;
if (IsPivotNode(parent->mName, &pos))
{
combinedTransform = parent->mTransformation * combinedTransform;
parent = parent->mParent;
}
else
{
break;
}
}
return combinedTransform;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -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.
*
*/
#pragma once
#include <assimp/matrix4x4.h>
#include <AzCore/std/string/string.h>
struct aiNode;
struct aiScene;
struct aiString;
namespace AZ::SceneAPI::FbxSceneBuilder
{
inline constexpr char PivotNodeMarker[] = "_$AssimpFbx$_";
bool IsSkinnedMesh(const aiNode& node, const aiScene& scene);
// Checks if a node name is a pivot node and optionally returns the position in the name of the pivot marker (for splitting out the parts later)
bool IsPivotNode(const aiString& nodeName, size_t* pos = nullptr);
// Returns the bone name and type of a pivot node
void SplitPivotNodeName(const aiString& nodeName, size_t pivotPos, AZStd::string_view& baseNodeName, AZStd::string_view& pivotType);
// Gets the entire, combined local transform for a node taking pivot nodes into account. When pivot nodes are not used, this just returns the node's transform
aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode);
} // namespace AZ
@@ -11,9 +11,11 @@
*/
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
@@ -54,6 +56,8 @@ namespace AZ
}
Events::ProcessingResultCombiner combinedMaterialImportResults;
AZStd::unordered_map<int, AZStd::shared_ptr<SceneData::GraphData::MaterialData>> materialMap;
for (int idx = 0; idx < context.m_sourceNode.m_assImpNode->mNumMeshes; ++idx)
{
int meshIndex = context.m_sourceNode.m_assImpNode->mMeshes[idx];
@@ -62,8 +66,6 @@ namespace AZ
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;
@@ -82,19 +84,58 @@ namespace AZ
material->SetMaterialName(assImpMaterial->GetName());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Diffuse).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Diffuse)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Specular,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Specular).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Specular)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Bump,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Bump).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Bump)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Normal,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Normal).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
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());
material->SetUseColorMap(assImpMaterial->GetUseColorMap());
material->SetBaseColor(assImpMaterial->GetBaseColor());
material->SetUseMetallicMap(assImpMaterial->GetUseMetallicMap());
material->SetMetallicFactor(assImpMaterial->GetMetallicFactor());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Metallic,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Metallic).c_str()));
material->SetUseRoughnessMap(assImpMaterial->GetUseRoughnessMap());
material->SetRoughnessFactor(assImpMaterial->GetRoughnessFactor());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Roughness,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Roughness).c_str()));
material->SetUseEmissiveMap(assImpMaterial->GetUseEmissiveMap());
material->SetEmissiveIntensity(assImpMaterial->GetEmissiveIntensity());
material->SetUseAOMap(assImpMaterial->GetUseAOMap());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::AmbientOcclusion,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::AmbientOcclusion).c_str()));
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Emissive,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Emissive).c_str()));
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::BaseColor,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::BaseColor).c_str()));
AZ_Assert(material, "Failed to allocate scene material data.");
if (!material)
@@ -135,6 +176,39 @@ namespace AZ
return combinedMaterialImportResults.GetResult();
}
AZStd::string AssImpMaterialImporter::ResolveTexturePath(const AZStd::string& sceneFilePath, const AZStd::string& textureFilePath) const
{
if (textureFilePath.empty())
{
return textureFilePath;
}
AZStd::string texturePathRelativeToScene;
AZStd::string cleanedUpSceneFilePath(sceneFilePath);
AZ::StringFunc::Path::StripFullName(cleanedUpSceneFilePath);
AZ::StringFunc::Path::Join(cleanedUpSceneFilePath.c_str(), textureFilePath.c_str(), texturePathRelativeToScene);
// If the texture did start with marker to change directories upward, then it's relative to the FBX file,
// and that path needs to be resolved. It can't be resolved later. This was handled internally by FBX SDK,
// but is not handled by AssImp.
if (textureFilePath.starts_with(".."))
{
// Not checking for the file existing because it may not be there yet.
return texturePathRelativeToScene;
}
// The engine only supports relative paths to scan folders.
// FBX files may have paths to textures, relative to the FBX file. Check for those, first.
if (AZ::IO::FileIOBase::GetInstance()->Exists(texturePathRelativeToScene.c_str()))
{
return texturePathRelativeToScene;
}
return textureFilePath;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -33,6 +33,9 @@ namespace AZ
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMaterials(AssImpSceneNodeAppendedContext& context);
private:
AZStd::string ResolveTexturePath(const AZStd::string& sceneFilePath, const AZStd::string& textureFilePath) const;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -9,19 +9,17 @@
* 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 <assimp/scene.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/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
@@ -46,80 +44,23 @@ namespace AZ
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)
if (!context.m_sourceNode.ContainsMesh() || IsSkinnedMesh(*currentNode, *scene))
{
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::Ignored;
}
return Events::ProcessingResult::Success;
if (BuildSceneMeshFromAssImpMesh(currentNode, scene, context.m_sourceSceneSystem, context.m_createdData, [] {
return AZStd::make_shared<SceneData::GraphData::MeshData>();
}))
{
return Events::ProcessingResult::Success;
}
return Events::ProcessingResult::Failure;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -0,0 +1,67 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpSkinImporter::AssImpSkinImporter()
{
BindToCall(&AssImpSkinImporter::ImportSkin);
}
void AssImpSkinImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpSkinImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpSkinImporter::ImportSkin(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Skin");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (!context.m_sourceNode.ContainsMesh() || !IsSkinnedMesh(*currentNode, *scene))
{
return Events::ProcessingResult::Ignored;
}
if (BuildSceneMeshFromAssImpMesh(currentNode, scene, context.m_sourceSceneSystem, context.m_createdData, [] {
return AZStd::make_shared<SceneData::GraphData::SkinMeshData>();
}))
{
return Events::ProcessingResult::Success;
}
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/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpSkinImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpSkinImporter, "{8FBCA725-C04E-42B7-9669-82DB3BB0901F}", SceneCore::LoadingComponent);
AssImpSkinImporter();
~AssImpSkinImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkin(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,149 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <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/AssImpSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const AZStd::string AssImpSkinWeightsImporter::s_skinWeightName = "SkinWeight_";
AssImpSkinWeightsImporter::AssImpSkinWeightsImporter()
{
BindToCall(&AssImpSkinWeightsImporter::ImportSkinWeights);
BindToCall(&AssImpSkinWeightsImporter::SetupNamedBoneLinks);
}
void AssImpSkinWeightsImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpSkinWeightsImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpSkinWeightsImporter::ImportSkinWeights(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Skin Weights");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if(currentNode->mNumMeshes <= 0)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedSkinWeightsResult;
for(unsigned m = 0; m < currentNode->mNumMeshes; ++m)
{
auto mesh = scene->mMeshes[currentNode->mMeshes[m]];
for(unsigned b = 0; b < mesh->mNumBones; ++b)
{
auto bone = mesh->mBones[b];
if(bone->mNumWeights <= 0)
{
continue;
}
AZStd::string skinWeightName = s_skinWeightName;
skinWeightName += AZStd::to_string(b);
RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> skinDeformer = BuildSkinWeightData(bone, mesh->mNumVertices);
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, skinWeightName.c_str());
AZ_Error("SkinWeightsImporter", newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedSkinWeightsResult += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult skinWeightsResult;
AssImpSceneAttributeDataPopulatedContext 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> AssImpSkinWeightsImporter::BuildSkinWeightData(aiBone* bone, unsigned numVertices)
{
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_bone = bone;
pending.m_numVertices = numVertices;
pending.m_skinWeightData = skinWeightData;
m_pendingSkinWeights.push_back(pending);
return skinWeightData;
}
Events::ProcessingResult AssImpSkinWeightsImporter::SetupNamedBoneLinks(AssImpFinalizeSceneContext& /*context*/)
{
AZ_TraceContext("Importer", "Skin Weights");
for (auto& it : m_pendingSkinWeights)
{
it.m_skinWeightData->ResizeContainerSpace(it.m_numVertices);
AZStd::string boneName = it.m_bone->mName.C_Str();
int boneId = it.m_skinWeightData->GetBoneId(boneName);
for(unsigned weight = 0; weight < it.m_bone->mNumWeights; ++weight)
{
DataTypes::ISkinWeightData::Link link;
link.boneId = boneId;
link.weight = it.m_bone->mWeights[weight].mWeight;
it.m_skinWeightData->AppendLink(it.m_bone->mWeights[weight].mVertexId, 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,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.
*
*/
#pragma once
#include <assimp/scene.h>
#include <AzCore/std/containers/vector.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.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 AssImpSkinWeightsImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpSkinWeightsImporter, "{79B5E863-C155-473A-BC0D-B85F8D8303EB}", SceneCore::LoadingComponent);
AssImpSkinWeightsImporter();
~AssImpSkinWeightsImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkinWeights(AssImpSceneNodeAppendedContext& context);
Events::ProcessingResult SetupNamedBoneLinks(AssImpFinalizeSceneContext& context);
protected:
struct Pending
{
aiBone* m_bone = nullptr;
unsigned m_numVertices = 0;
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> m_skinWeightData;
};
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> BuildSkinWeightData(aiBone* bone, unsigned numVertices);
//! 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,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/AssImpTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpTangentStreamImporter::m_defaultNodeName = "Tangent";
AssImpTangentStreamImporter::AssImpTangentStreamImporter()
{
BindToCall(&AssImpTangentStreamImporter::ImportTangentStreams);
}
void AssImpTangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpTangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpTangentStreamImporter::ImportTangentStreams(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);
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct tangent stream attribute for invalid or non-mesh parent data");
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 || sdkMeshIndex >= currentNode->mNumMeshes)
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct tangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
return Events::ProcessingResult::Failure;
}
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->HasTangentsAndBitangents())
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> tangentStream =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexTangentData>();
// AssImp only has one tangentStream per mesh.
tangentStream->SetTangentSetIndex(0);
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
tangentStream->ReserveContainerSpace(vertexCount);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
// Vector4's constructor that takes in a vector3 sets w to 1.0f automatically.
const Vector4 tangent(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mTangents[v]));
tangentStream->AppendTangent(tangent);
}
AZStd::string nodeName(AZStd::string::format("%s", m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult tangentResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, tangentStream, newIndex, nodeName.c_str());
tangentResults = Events::Process(dataPopulated);
if (tangentResults != Events::ProcessingResult::Failure)
{
tangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
return tangentResults;
}
} // 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 AssImpTangentStreamImporter : public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpTangentStreamImporter, "{AB2D1D1E-5A19-40AF-B4F4-C652DD578F43}", SceneCore::LoadingComponent);
AssImpTangentStreamImporter();
~AssImpTangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportTangentStreams(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -23,6 +23,7 @@
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <assimp/scene.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
namespace AZ
{
@@ -45,16 +46,25 @@ namespace AZ
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();
if (currentNode == scene->mRootNode || IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(context.m_sourceNode.GetAssImpNode()->mTransformation);
aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
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.");
@@ -63,7 +73,6 @@ namespace AZ
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))
{
@@ -59,10 +59,10 @@ namespace AZ
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()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData =
@@ -75,40 +75,44 @@ namespace AZ
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)
for (int texCoordIndex = 0; texCoordIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++texCoordIndex)
{
AZ::Vector2 vertexUV(
mesh->mTextureCoords[0][v].x,
mesh->mTextureCoords[0][v].y);
uvMap->AppendUV(vertexUV);
if (!mesh->mTextureCoords[texCoordIndex])
{
continue;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
uvMap->ReserveContainerSpace(vertexCount);
AZStd::string name(AZStd::string::format("%s%d", m_defaultNodeName, texCoordIndex));
uvMap->SetCustomName(name.c_str());
for (int v = 0; v < mesh->mNumVertices; ++v)
{
AZ::Vector2 vertexUV(
mesh->mTextureCoords[texCoordIndex][v].x,
// The engine's V coordinate is reverse of how it's stored in the FBX file.
1.0f - mesh->mTextureCoords[texCoordIndex][v].y);
uvMap->AppendUV(vertexUV);
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, name.c_str());
Events::ProcessingResult uvMapResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, name);
uvMapResults = Events::Process(dataPopulated);
if (uvMapResults != Events::ProcessingResult::Failure)
{
uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedUvMapResults += uvMapResults;
}
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();
}
@@ -62,7 +62,6 @@ namespace AZ
SceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
AssImpSceneDataPopulatedContext* dataPopulatedContext = azrtti_cast<AssImpSceneDataPopulatedContext*>(&dataPopulated);
@@ -75,7 +74,6 @@ namespace AZ
AssImpSceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#endif
return nodeResults.GetResult();
}
@@ -99,14 +97,12 @@ namespace AZ
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();
}
@@ -16,7 +16,6 @@
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
namespace AZ
{
struct Uuid;
@@ -79,4 +79,4 @@ namespace AZ
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
} // namespace AZ
@@ -0,0 +1,98 @@
/*
* 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 <assimp/mesh.h>
#include <assimp/scene.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
namespace AZ::SceneAPI::FbxSceneBuilder
{
bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc)
{
AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
int lyMeshIndex = 0;
if(!currentNode || !scene)
{
return false;
}
for (int m = 0; m < currentNode->mNumMeshes; ++m)
{
auto newMesh = makeMeshFunc();
newMesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
newMesh->SetOriginalUnitSizeInMeters(sceneSystem.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);
sceneSystem.SwapVec3ForUpAxis(vertex);
sceneSystem.ConvertUnit(vertex);
newMesh->AddPosition(vertex);
newMesh->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
if (mesh->HasNormals())
{
AZ::Vector3 normal(mesh->mNormals[vertIdx].x, mesh->mNormals[vertIdx].y, mesh->mNormals[vertIdx].z);
sceneSystem.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 on node %s has a face with %d vertices, only 3 vertices are supported per face.",
currentNode->mName.C_Str(),
face.mNumIndices);
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
meshFace.vertexIndex[idx] = face.mIndices[idx];
}
newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
}
meshes.push_back(newMesh);
}
return true;
}
}
@@ -0,0 +1,48 @@
/*
* 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
struct aiNode;
struct aiScene;
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class MeshData;
class BlendShapeData;
}
}
namespace SceneAPI
{
namespace DataTypes
{
class IGraphObject;
}
class FbxSceneSystem;
namespace FbxSceneBuilder
{
bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc);
}
}
}
@@ -10,16 +10,4 @@
#
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
)
@@ -21,6 +21,8 @@ set(FILES
ImportContexts/ImportContexts.cpp
ImportContexts/FbxImportContexts.h
ImportContexts/FbxImportContexts.cpp
ImportContexts/AssImpImportContexts.h
ImportContexts/AssImpImportContexts.cpp
Importers/FbxAnimationImporter.h
Importers/FbxAnimationImporter.cpp
Importers/FbxBoneImporter.h
@@ -50,6 +52,36 @@ set(FILES
Importers/FbxUvMapImporter.cpp
Importers/Utilities/FbxMeshImporterUtilities.h
Importers/Utilities/FbxMeshImporterUtilities.cpp
Importers/Utilities/AssImpMeshImporterUtilities.h
Importers/Utilities/AssImpMeshImporterUtilities.cpp
Importers/Utilities/RenamedNodesMap.h
Importers/Utilities/RenamedNodesMap.cpp
Importers/AssImpAnimationImporter.h
Importers/AssImpAnimationImporter.cpp
Importers/AssImpBitangentStreamImporter.h
Importers/AssImpBitangentStreamImporter.cpp
Importers/AssImpBlendShapeImporter.h
Importers/AssImpBlendShapeImporter.cpp
Importers/AssImpBoneImporter.h
Importers/AssImpBoneImporter.cpp
Importers/AssImpColorStreamImporter.h
Importers/AssImpColorStreamImporter.cpp
Importers/AssImpImporterUtilities.h
Importers/AssImpImporterUtilities.cpp
Importers/AssImpMaterialImporter.h
Importers/AssImpMaterialImporter.cpp
Importers/AssImpMeshImporter.h
Importers/AssImpMeshImporter.cpp
Importers/AssImpSkinImporter.h
Importers/AssImpSkinImporter.cpp
Importers/AssImpSkinWeightsImporter.h
Importers/AssImpSkinWeightsImporter.cpp
Importers/AssImpTangentStreamImporter.h
Importers/AssImpTangentStreamImporter.cpp
Importers/AssImpTransformImporter.h
Importers/AssImpTransformImporter.cpp
Importers/AssImpUvMapImporter.h
Importers/AssImpUvMapImporter.cpp
Importers/AssImpAnimationImporter.h
Importers/AssImpAnimationImporter.cpp
)
@@ -11,6 +11,7 @@
*/
#include <assimp/scene.h>
#include <assimp/material.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/Math/Sha1.h>
#include <AzCore/Debug/Trace.h>
@@ -99,6 +100,105 @@ namespace AZ
return shininess;
}
bool AssImpMaterialWrapper::GetUseColorMap() const
{
// AssImp stores values as floats, so load as float and convert to bool.
float useMap = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_USE_COLOR_MAP, useMap) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useColorMap from the material. Using default.");
}
return useMap != 0.0f;
}
AZ::Vector3 AssImpMaterialWrapper::GetBaseColor() const
{
aiColor3D color(1.f, 1.f, 1.f);
if (m_assImpMaterial->Get(AI_MATKEY_BASE_COLOR, color) == aiReturn::aiReturn_FAILURE)
{
// If a base color is not set, fall back to the diffuse color.
// Before PBR support was added, the base color was set to the diffuse color, so
// this will match that behavior.
return GetDiffuseColor();
}
return AZ::Vector3(color.r, color.g, color.b);
}
bool AssImpMaterialWrapper::GetUseMetallicMap() const
{
// AssImp stores values as floats, so load as float and convert to bool.
float useMap = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_USE_METALLIC_MAP, useMap) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useMetallicMap from the material. Using default.");
}
return useMap != 0.0f;
}
float AssImpMaterialWrapper::GetMetallicFactor() const
{
float metallic = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_METALLIC_FACTOR, metallic) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get metallic from the material. Using default.");
}
return metallic;
}
bool AssImpMaterialWrapper::GetUseRoughnessMap() const
{
// AssImp stores values as floats, so load as float and convert to bool.
float useMap = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_USE_ROUGHNESS_MAP, useMap) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useRoughnessMap from the material. Using default.");
}
return useMap != 0.0f;
}
float AssImpMaterialWrapper::GetRoughnessFactor() const
{
float roughness = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get roughness from the material. Using default.");
}
return roughness;
}
bool AssImpMaterialWrapper::GetUseEmissiveMap() const
{
// AssImp stores values as floats, so load as float and convert to bool.
float useMap = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_USE_EMISSIVE_MAP, useMap) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(
AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useEmissiveMap from the material. Using default.");
}
return useMap != 0.0f;
}
float AssImpMaterialWrapper::GetEmissiveIntensity() const
{
float emissiveIntensity = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveIntensity) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get emissive intensity from the material. Using default.");
}
return emissiveIntensity;
}
bool AssImpMaterialWrapper::GetUseAOMap() const
{
// AssImp stores values as floats, so load as float and convert to bool.
float useMap = 0.0f;
if (m_assImpMaterial->Get(AI_MATKEY_USE_AO_MAP, useMap) == aiReturn::aiReturn_FAILURE)
{
AZ_Warning(AZ::SceneAPI::Utilities::WarningWindow, false, "Unable to get useAOMap from the material. Using default.");
}
return useMap != 0.0f;
}
AZStd::string AssImpMaterialWrapper::GetTextureFileName(MaterialMapType textureType) const
{
/// Engine currently doesn't support multiple textures. Right now we only use first texture.
@@ -130,6 +230,43 @@ namespace AZ
m_assImpMaterial->GetTexture(aiTextureType_NORMALS, textureIndex, &absTexturePath);
}
break;
case MaterialMapType::Metallic:
if (m_assImpMaterial->GetTextureCount(aiTextureType_METALNESS) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_METALNESS, textureIndex, &absTexturePath);
}
break;
case MaterialMapType::Roughness:
if (m_assImpMaterial->GetTextureCount(aiTextureType_DIFFUSE_ROUGHNESS) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_DIFFUSE_ROUGHNESS, textureIndex, &absTexturePath);
}
break;
case MaterialMapType::AmbientOcclusion:
if (m_assImpMaterial->GetTextureCount(aiTextureType_AMBIENT_OCCLUSION) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_AMBIENT_OCCLUSION, textureIndex, &absTexturePath);
}
break;
case MaterialMapType::Emissive:
if (m_assImpMaterial->GetTextureCount(aiTextureType_EMISSION_COLOR) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_EMISSION_COLOR, textureIndex, &absTexturePath);
}
break;
case MaterialMapType::BaseColor:
if (m_assImpMaterial->GetTextureCount(aiTextureType_BASE_COLOR) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_BASE_COLOR, textureIndex, &absTexturePath);
}
// If the base color texture isn't available, fall back to using the diffuse texture.
// Before PBR support was added, the renderer just defaulted to using the diffuse texture
// in the base color texture property of the material.
else if (m_assImpMaterial->GetTextureCount(aiTextureType_DIFFUSE) > textureIndex)
{
m_assImpMaterial->GetTexture(aiTextureType_DIFFUSE, textureIndex, &absTexturePath);
}
break;
default:
AZ_TraceContext("Unknown value", aznumeric_cast<int>(textureType));
AZ_TracePrintf(SceneAPI::Utilities::WarningWindow, "Unrecognized MaterialMapType retrieved");
@@ -32,6 +32,16 @@ namespace AZ
float GetOpacity() const override;
float GetShininess() const override;
AZStd::string GetTextureFileName(MaterialMapType textureType) const override;
bool GetUseColorMap() const;
AZ::Vector3 GetBaseColor() const;
bool GetUseMetallicMap() const;
float GetMetallicFactor() const;
bool GetUseRoughnessMap() const;
float GetRoughnessFactor() const;
bool GetUseEmissiveMap() const;
float GetEmissiveIntensity() const;
bool GetUseAOMap() const;
};
} // namespace AssImpSDKWrapper
}// namespace AZ
@@ -65,6 +65,19 @@ namespace AZ
return m_assImpNode->mNumMeshes != 0;
}
bool AssImpNodeWrapper::ContainsBones(const aiScene& scene) const
{
for (unsigned meshIndex = 0; meshIndex < m_assImpNode->mNumMeshes; ++meshIndex)
{
if (scene.mMeshes[m_assImpNode->mMeshes[meshIndex]]->HasBones())
{
return true;
}
}
return false;
}
int AssImpNodeWrapper::GetMaterialCount() const
{
// one mesh uses only a single material
@@ -12,6 +12,9 @@
#pragma once
#include <SceneAPI/SDKWrapper/NodeWrapper.h>
struct aiScene;
namespace AZ
{
namespace AssImpSDKWrapper
@@ -27,6 +30,7 @@ namespace AZ
int GetChildCount() const override;
const std::shared_ptr<NodeWrapper> GetChild(int childIndex) const override;
const bool ContainsMesh();
bool ContainsBones(const aiScene& scene) const;
int GetMaterialCount() const override;
};
} // namespace AssImpSDKWrapper
@@ -38,12 +38,11 @@ namespace AZ
{
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName);
AZ_TraceContext("Filename", fileName);
m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
m_sceneFileName = fileName;
m_assImpScene = m_importer.ReadFile(fileName,
aiProcess_CalcTangentSpace //Calculates the tangents and bitangents for the imported meshes
| aiProcess_Triangulate //Triangulates all faces of all meshes
aiProcess_Triangulate //Triangulates all faces of all meshes
| aiProcess_JoinIdenticalVertices //Identifies and joins identical vertex data sets for the imported meshes
| aiProcess_SortByPType //Splits meshes with more than one primitive type into homogeneous sub - meshes
| aiProcess_FixInfacingNormals //Fixes inward facing normals, AssImp documentation recommends setting this
| aiProcess_GenNormals); //Generate normals for meshes
if (!m_assImpScene)
{
@@ -44,9 +44,15 @@ namespace AZ
AZStd::pair<AxisVector, int32_t> GetUpVectorAndSign() const;
AZStd::pair<AxisVector, int32_t> GetFrontVectorAndSign() const;
AZStd::string GetSceneFileName() const { return m_sceneFileName; }
protected:
Assimp::Importer m_importer;
// FBX SDK automatically resolved relative paths to textures based on the current file location.
// AssImp does not, so it needs to be specifically handled.
AZStd::string m_sceneFileName;
};
} // namespace AssImpSDKWrapper
@@ -56,5 +56,10 @@ namespace AZ
{
return AZ::SceneAPI::DataTypes::Color(color.r, color.g, color.b, color.a);
}
AZ::Vector3 AssImpTypeConverter::ToVector3(const aiVector3D& vector3)
{
return AZ::Vector3(vector3.x, vector3.y, vector3.z);
}
} //AssImpSDKWrapper
} // namespace AZ
@@ -33,6 +33,7 @@ namespace AZ
static SceneAPI::DataTypes::MatrixType ToTransform(const aiMatrix4x4& matrix);
static SceneAPI::DataTypes::MatrixType ToTransform(const AZ::Matrix4x4& matrix);
static SceneAPI::DataTypes::Color ToColor(const aiColor4D& color);
static AZ::Vector3 ToVector3(const aiVector3D& vector3);
};
} // namespace AssImpSDKWrapper
} // namespace AZ
@@ -18,43 +18,38 @@ namespace AZ
{
MaterialWrapper::MaterialWrapper(fbxsdk::FbxSurfaceMaterial* fbxMaterial)
:m_fbxMaterial(fbxMaterial)
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
, m_assImpMaterial(nullptr)
#endif
{
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
MaterialWrapper::MaterialWrapper(aiMaterial* assImpMaterial)
:m_fbxMaterial(nullptr)
, m_assImpMaterial(assImpMaterial)
{
}
#endif
MaterialWrapper::~MaterialWrapper()
{
m_fbxMaterial = nullptr;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
m_assImpMaterial = nullptr;
#endif
}
fbxsdk::FbxSurfaceMaterial* MaterialWrapper::GetFbxMaterial()
{
return m_fbxMaterial;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiMaterial* MaterialWrapper::GetAssImpMaterial()
{
return m_assImpMaterial;
}
#endif
AZStd::string MaterialWrapper::GetName() const
{
return AZStd::string();
}
uint64_t MaterialWrapper::GetUniqueId() const
AZ::u64 MaterialWrapper::GetUniqueId() const
{
return uint64_t();
}
@@ -20,9 +20,8 @@ namespace fbxsdk
class FbxSurfaceMaterial;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
struct aiMaterial;
#endif
namespace AZ
{
@@ -37,22 +36,23 @@ namespace AZ
Diffuse,
Specular,
Bump,
Normal
Normal,
Metallic,
Roughness,
AmbientOcclusion,
Emissive,
BaseColor
};
MaterialWrapper(fbxsdk::FbxSurfaceMaterial* fbxMaterial);
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
MaterialWrapper(aiMaterial* assImpmaterial);
#endif
virtual ~MaterialWrapper();
fbxsdk::FbxSurfaceMaterial* GetFbxMaterial();
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiMaterial* GetAssImpMaterial();
#endif
virtual AZStd::string GetName() const;
virtual uint64_t GetUniqueId() const;
virtual AZ::u64 GetUniqueId() const;
virtual AZStd::string GetTextureFileName(MaterialMapType textureType) const;
virtual AZ::Vector3 GetDiffuseColor() const;
virtual AZ::Vector3 GetSpecularColor() const;
@@ -62,9 +62,7 @@ namespace AZ
protected:
fbxsdk::FbxSurfaceMaterial* m_fbxMaterial = nullptr;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiMaterial* m_assImpMaterial = nullptr;
#endif
};
} // namespace SDKMaterial
} // namespace AZ
@@ -18,37 +18,31 @@ namespace AZ
{
NodeWrapper::NodeWrapper(fbxsdk::FbxNode* fbxNode)
:m_fbxNode(fbxNode)
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
, m_assImpNode(nullptr)
#endif
{
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
NodeWrapper::NodeWrapper(aiNode* aiNode)
:m_fbxNode(nullptr)
, m_assImpNode(aiNode)
{
}
#endif
NodeWrapper::~NodeWrapper()
{
m_fbxNode = nullptr;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
m_assImpNode = nullptr;
#endif
}
fbxsdk::FbxNode* NodeWrapper::GetFbxNode()
{
return m_fbxNode;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiNode* NodeWrapper::GetAssImpNode()
{
return m_assImpNode;
}
#endif
const char* NodeWrapper::GetName() const
{
+2 -8
View File
@@ -15,9 +15,9 @@ namespace fbxsdk
{
class FbxNode;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
struct aiNode;
#endif
namespace AZ
{
namespace SDKNode
@@ -29,9 +29,7 @@ namespace AZ
NodeWrapper() = default;
NodeWrapper(fbxsdk::FbxNode* fbxNode);
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
NodeWrapper(aiNode* aiNode);
#endif
virtual ~NodeWrapper();
enum CurveNodeComponent
@@ -42,9 +40,7 @@ namespace AZ
};
fbxsdk::FbxNode* GetFbxNode();
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiNode* GetAssImpNode();
#endif
virtual const char* GetName() const;
virtual AZ::u64 GetUniqueId() const;
@@ -55,9 +51,7 @@ namespace AZ
fbxsdk::FbxNode* m_fbxNode = nullptr;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
aiNode* m_assImpNode = nullptr;
#endif
};
} //namespace Node
} //namespace AZ
@@ -1,11 +0,0 @@
#
# 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.
#
@@ -1,11 +0,0 @@
#
# 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.
#
@@ -1,21 +0,0 @@
#
# 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
../../AssImpSceneWrapper.cpp
../../AssImpNodeWrapper.cpp
../../AssImpSceneWrapper.h
../../AssImpNodeWrapper.h
../../AssImpMaterialWrapper.h
../../AssImpMaterialWrapper.cpp
../../AssImpTypeConverter.cpp
../../AssImpTypeConverter.h
)
@@ -19,18 +19,16 @@ namespace AZ
SceneWrapperBase::SceneWrapperBase(fbxsdk::FbxScene* fbxScene)
:m_fbxScene(fbxScene)
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
, m_assImpScene(nullptr)
#endif
{
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
SceneWrapperBase::SceneWrapperBase(aiScene* aiScene)
:m_fbxScene(nullptr)
, m_assImpScene(aiScene)
{
}
#endif
bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const char* fileName)
{
@@ -59,12 +57,10 @@ namespace AZ
return m_fbxScene;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
const aiScene* SceneWrapperBase::GetAssImpScene() const
{
return m_assImpScene;
}
#endif
} //namespace Scene
@@ -17,9 +17,9 @@ namespace fbxsdk
{
class FbxScene;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
struct aiScene;
#endif
namespace AZ
{
@@ -32,9 +32,7 @@ namespace AZ
SceneWrapperBase() = default;
SceneWrapperBase(fbxsdk::FbxScene* fbxScene);
virtual ~SceneWrapperBase() = default;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
SceneWrapperBase(aiScene* aiScene);
#endif
virtual bool LoadSceneFromFile(const char* fileName);
virtual bool LoadSceneFromFile(const AZStd::string& fileName);
@@ -45,14 +43,10 @@ namespace AZ
virtual void Clear();
virtual fbxsdk::FbxScene* GetFbxScene() const;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
virtual const aiScene* GetAssImpScene() const;
#endif
fbxsdk::FbxScene* m_fbxScene = nullptr;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
const aiScene* m_assImpScene = nullptr;
#endif
static const char* s_defaultSceneName;
};
@@ -16,4 +16,12 @@ set(FILES
NodeWrapper.cpp
MaterialWrapper.h
MaterialWrapper.cpp
AssImpSceneWrapper.cpp
AssImpNodeWrapper.cpp
AssImpSceneWrapper.h
AssImpNodeWrapper.h
AssImpMaterialWrapper.h
AssImpMaterialWrapper.cpp
AssImpTypeConverter.cpp
AssImpTypeConverter.h
)
@@ -23,7 +23,6 @@ namespace AZ
{
namespace Containers
{
size_t RuleContainer::GetRuleCount() const
{
return m_rules.size();
@@ -57,6 +56,13 @@ namespace AZ
}
void RuleContainer::InsertRule(const AZStd::shared_ptr<DataTypes::IRule>& rule, size_t position)
{
AZ_Assert(AZStd::find(m_rules.begin(), m_rules.end(), rule) == m_rules.end(), "Unable to insert rule as it has already been added.");
m_rules.insert(m_rules.begin() + position, rule);
}
void RuleContainer::RemoveRule(size_t index)
{
if (index < m_rules.size())
@@ -76,7 +82,6 @@ namespace AZ
}
}
void RuleContainer::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
@@ -156,4 +161,4 @@ namespace AZ
} // Containers
} // SceneAPI
} // AZ
} // AZ
@@ -27,7 +27,6 @@ namespace AZ
{
namespace Containers
{
class RuleContainer
{
public:
@@ -54,6 +53,8 @@ namespace AZ
SCENE_CORE_API void AddRule(const AZStd::shared_ptr<DataTypes::IRule>& rule);
SCENE_CORE_API void AddRule(AZStd::shared_ptr<DataTypes::IRule>&& rule);
SCENE_CORE_API void InsertRule(const AZStd::shared_ptr<DataTypes::IRule>& rule, size_t position);
SCENE_CORE_API void RemoveRule(size_t index);
SCENE_CORE_API void RemoveRule(const AZStd::shared_ptr<DataTypes::IRule>& rule);
@@ -43,6 +43,30 @@ namespace AZ
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneGraph::NodeIndex>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Constructor<>()
->Constructor<const SceneGraph::NodeIndex&>()
->Method("AsNumber", &SceneGraph::NodeIndex::AsNumber)
->Method("Distance", &SceneGraph::NodeIndex::Distance)
->Method("IsValid", &SceneGraph::NodeIndex::IsValid)
->Method("Equal", &SceneGraph::NodeIndex::operator==)
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
->Method("ToString", [](const SceneGraph::NodeIndex& node) { return AZStd::string::format("%u", node.m_value); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
;
behaviorContext->Class<SceneGraph::Name>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Constructor()
->Method("GetPath", &SceneGraph::Name::GetPath)
->Method("GetName", &SceneGraph::Name::GetName)
->Method("ToString", [](const SceneGraph::Name& self){ return self.GetName(); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
;
behaviorContext->Class<SceneGraph>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
@@ -62,41 +86,23 @@ namespace AZ
->Method("GetNodeChild", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeChild(node); })
->Method("GetNodeCount", &SceneGraph::GetNodeCount)
->Method("FindWithPath", [](const SceneGraph& self, const AZStd::string& path)
{
return self.Find(path);
})
{
return self.Find(path);
})
->Method("FindWithRootAndPath", [](const SceneGraph& self, NodeIndex root, const AZStd::string& path)
{
return self.Find(root, path);
})
{
return self.Find(root, path);
})
->Method("GetNodeContent", [](const SceneGraph& self, NodeIndex node) -> GraphObjectProxy*
{
auto graphObject = self.GetNodeContent(node);
if (graphObject)
{
auto graphObject = self.GetNodeContent(node);
if (graphObject)
{
GraphObjectProxy* proxy = aznew GraphObjectProxy(graphObject);
return proxy;
}
return nullptr;
})
;
behaviorContext->Class<SceneGraph::NodeIndex>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Method("AsNumber", &SceneGraph::NodeIndex::AsNumber)
->Method("Distance", &SceneGraph::NodeIndex::Distance)
->Method("IsValid", &SceneGraph::NodeIndex::IsValid)
->Method("Equal", &SceneGraph::NodeIndex::operator==)
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
;
behaviorContext->Class<SceneGraph::Name>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Method("GetPath", &SceneGraph::Name::GetPath)
->Method("GetName", &SceneGraph::Name::GetName)
;
GraphObjectProxy* proxy = aznew GraphObjectProxy(graphObject);
return proxy;
}
return nullptr;
});
}
}
@@ -69,6 +69,7 @@ namespace AZ
// Type needs to be able to store an index in a NodeHeader (currently 21-bits).
using IndexType = uint32_t;
NodeIndex() = default;
NodeIndex(const NodeIndex& rhs) = default;
NodeIndex& operator=(const NodeIndex& rhs) = default;
@@ -87,10 +88,9 @@ namespace AZ
private:
static const IndexType INVALID_INDEX = static_cast<IndexType>(-1);
inline NodeIndex();
inline explicit NodeIndex(IndexType value);
IndexType m_value;
IndexType m_value = NodeIndex::INVALID_INDEX;
};
// NodeHeader contains the relationship a node has with its surrounding nodes and additional information about a node.
@@ -22,11 +22,6 @@ namespace AZ
//
// NodeIndex
//
SceneGraph::NodeIndex::NodeIndex()
: m_value(NodeIndex::INVALID_INDEX)
{
}
bool SceneGraph::NodeIndex::IsValid() const
{
return m_value != NodeIndex::INVALID_INDEX;
@@ -104,7 +104,7 @@ namespace AZ
RootIterator& operator++();
RootIterator operator++(int);
const Iterator& GetBaseIterator();
const Iterator& GetBaseIterator() const;
protected:
Iterator m_iterator;
Function m_converter;
@@ -46,7 +46,7 @@ namespace AZ
}
template<typename Iterator, typename ReturnType>
const Iterator& ConvertIterator<Iterator, ReturnType, void>::GetBaseIterator()
const Iterator& ConvertIterator<Iterator, ReturnType, void>::GetBaseIterator() const
{
return m_iterator;
}
@@ -85,7 +85,7 @@ namespace AZ
RootIterator& operator++();
RootIterator operator++(int);
const Iterator& GetBaseIterator();
const Iterator& GetBaseIterator() const;
protected:
// Pseudo default constructor.
@@ -59,7 +59,7 @@ namespace AZ
}
template<typename Iterator>
auto FilterIterator<Iterator, void>::GetBaseIterator()->const Iterator&
auto FilterIterator<Iterator, void>::GetBaseIterator() const -> const Iterator&
{
return m_iterator;
}
@@ -44,6 +44,8 @@ namespace AZ
Iterator cbegin() const;
Iterator cend() const;
[[nodiscard]] bool empty() const;
private:
Iterator m_begin;
Iterator m_end;
@@ -59,4 +61,4 @@ namespace AZ
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/View.inl>
#include <SceneAPI/SceneCore/Containers/Views/View.inl>
@@ -62,6 +62,12 @@ namespace AZ
{
return m_end;
}
template<typename Iterator>
[[nodiscard]] bool View<Iterator>::empty() const
{
return m_begin == m_end;
}
}; // Views
} // Containers
} // SceneAPI
@@ -37,7 +37,12 @@ namespace AZ
Diffuse,
Specular,
Bump,
Normal
Normal,
Metallic,
Roughness,
AmbientOcclusion,
Emissive,
BaseColor
};
~IMaterialData() override = default;
@@ -52,6 +57,24 @@ namespace AZ
output.Write("EmissiveColor", GetEmissiveColor());
output.Write("Opacity", GetOpacity());
output.Write("Shininess", GetShininess());
output.Write("UseColorMap", GetUseColorMap());
output.Write("BaseColor", GetBaseColor());
output.Write("UseMetallicMap", GetUseMetallicMap());
output.Write("MetallicFactor", GetMetallicFactor());
output.Write("UseRoughnessMap", GetUseRoughnessMap());
output.Write("RoughnessFactor", GetRoughnessFactor());
output.Write("UseEmissiveMap", GetUseEmissiveMap());
output.Write("EmissiveIntensity", GetEmissiveIntensity());
output.Write("UseAOMap", GetUseAOMap());
output.Write("DiffuseTexture", GetTexture(TextureMapType::Diffuse).c_str());
output.Write("SpecularTexture", GetTexture(TextureMapType::Specular).c_str());
output.Write("BumpTexture", GetTexture(TextureMapType::Bump).c_str());
output.Write("NormalTexture", GetTexture(TextureMapType::Normal).c_str());
output.Write("MetallicTexture", GetTexture(TextureMapType::Metallic).c_str());
output.Write("RoughnessTexture", GetTexture(TextureMapType::Roughness).c_str());
output.Write("AmbientOcclusionTexture", GetTexture(TextureMapType::AmbientOcclusion).c_str());
output.Write("EmissiveTexture", GetTexture(TextureMapType::Emissive).c_str());
output.Write("BaseColorTexture", GetTexture(TextureMapType::BaseColor).c_str());
}
virtual const AZStd::string& GetMaterialName() const = 0;
@@ -63,6 +86,16 @@ namespace AZ
virtual const AZ::Vector3& GetEmissiveColor() const = 0;
virtual float GetOpacity() const = 0;
virtual float GetShininess() const = 0;
virtual bool GetUseColorMap() const = 0;
virtual const AZ::Vector3& GetBaseColor() const = 0;
virtual bool GetUseMetallicMap() const = 0;
virtual float GetMetallicFactor() const = 0;
virtual bool GetUseRoughnessMap() const = 0;
virtual float GetRoughnessFactor() const = 0;
virtual bool GetUseEmissiveMap() const = 0;
virtual float GetEmissiveIntensity() const = 0;
virtual bool GetUseAOMap() const = 0;
virtual uint64_t GetUniqueId() const = 0;
};
@@ -44,6 +44,7 @@ namespace AZ
float m_channels[4];
};
Color() = default;
Color(float r, float g, float b, float a)
: red(r), green(g), blue(b), alpha(a)
{
@@ -53,6 +54,30 @@ namespace AZ
{
return m_channels[static_cast<AZ::u8>(channel)];
}
bool IsClose(const Color& c, float tolerance = AZ::Constants::Tolerance) const
{
return (c - (*this)).Abs().IsLessEqualThan(tolerance);
}
bool IsLessEqualThan(float tolerance) const
{
return AZStd::all_of(AZStd::begin(m_channels), AZStd::end(m_channels), [tolerance] (float channel) { return channel <= tolerance; } );
}
Color& Abs()
{
for (float& channel : m_channels)
{
channel = std::abs(channel);
}
return *this;
}
Color operator-(const Color& rhs) const
{
return Color(red - rhs.red, green - rhs.green, blue - rhs.blue, alpha - rhs.alpha);
}
};
class IMeshVertexColorData
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
#include <SceneAPI/SceneCore/Utilities/CoordinateSystemConverter.h>
namespace AZ
{
class ReflectContext;
}
namespace AZ::SceneAPI::DataTypes
{
class ICoordinateSystemRule
: public IRule
{
public:
AZ_RTTI(ICoordinateSystemRule, "{78136748-AC4B-4FC6-B9D8-C5820D67D29F}", IRule);
enum CoordinateSystem : int
{
ZUpPositiveYForward = 0,
ZUpNegativeYForward = 1
};
virtual ~ICoordinateSystemRule() override = default;
virtual void UpdateCoordinateSystemConverter() = 0;
virtual void SetTargetCoordinateSystem(CoordinateSystem targetCoordinateSystem) = 0;
virtual CoordinateSystem GetTargetCoordinateSystem() const = 0;
virtual const CoordinateSystemConverter& GetCoordinateSystemConverter() const = 0;
};
} // namespace AZ::SceneAPI::DataTypes
@@ -12,33 +12,26 @@
*
*/
#include <AzCore/std/string/string.h>
#include <AzCore/RTTI/RTTI.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
namespace AZ
{
class Quaternion;
class Vector3;
namespace SceneAPI
{
namespace DataTypes
{
class IOriginRule
class ISkinRule
: public IRule
{
public:
AZ_RTTI(IOriginRule, "{9FB042DF-1C7F-4815-BC83-BF8D94F907C5}", IRule);
AZ_RTTI(ISkinRule, "{5496ECAF-B096-4455-AE72-D55C5B675443}", IRule);
~ISkinRule() override = default;
virtual ~IOriginRule() override = default;
virtual const AZStd::string& GetOriginNodeName() const = 0;
virtual bool UseRootAsOrigin() const = 0;
virtual const AZ::Quaternion& GetRotation() const = 0;
virtual const AZ::Vector3& GetTranslation() const = 0;
virtual float GetScale() const = 0;
virtual AZ::u32 GetMaxWeightsPerVertex() const = 0;
virtual float GetWeightThreshold() const = 0;
};
} // DataTypes
} // SceneAPI
} // AZ
}
}
}
@@ -1,92 +0,0 @@
/*
* 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 <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
#include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
/*!
The author of the touch bendable asset will be able to define stiffness, damping and thickness
as attributes per bone. Adding those kind of attributes to a node is supported
by DCC tools and the FBX API (FbxProperty), but SceneAPI doesn't support parsing those attributes into the
Scene Nodes or IGraphObjects. In the meantime, and while parsing Extra Atrributes is not supported by SceneAPI, the
content author should manually set the values in this Modifier. The values will be applied to all bones.
The ShouldOverride*() methods are put in place so in the future the content author can override
all the attributes at once without re-exporting assets from the DCC tools.
This is more of a convenience.
If the original asset doesn't have any of these attributes in the bones, then the values
of this rule will be applied to the root bone. Children bones will copy the parents attributes
for all unspecified attributes.
*/
class ITouchBendingRule
: public IRule
{
public:
AZ_RTTI(ITouchBendingRule, "{2FE2B499-DB71-4D69-8944-6DE2396D6E78}", IRule);
~ITouchBendingRule() override = default;
virtual const AZStd::string& GetRootBoneName() const = 0;
/*!
The returned list contains only one mesh in 99.99% of the cases.
The mesh is supposed to be the proximity trigger mesh.
Most of the time the content author would want the proximity trigger mesh
to be as simple as possible for performance reasons. So, something like a simple
cube that covers the main render mesh is the ideal thing to do for collision detection.
The selected proximity mesh is stored in a list, because there can be extreme cases
where several meshes can define the proximity trigger volume. They will all be combined
into a single submesh into the exported CGF file, at the expense of performance when the
engine calculates if a vegetation mesh is being touched or not.
*/
virtual ISceneNodeSelectionList& GetSceneNodeSelectionList() = 0;
virtual const ISceneNodeSelectionList& GetSceneNodeSelectionList() const = 0;
///If true, The stifness parameter for all the bones
///in the tree will be set to GetOverrideStiffness(), replacing
///the value set by the Author of the asset.
virtual bool ShouldOverrideStiffness() const = 0;
///A value from 0.0f to 1.0f.
///0.0 means no stiffness, the tree will look like a sad willow.
///Segments (bones) of the tree would never return to its original pose
///after being pushed by a Collider.
virtual float GetOverrideStiffness() const = 0;
///If true, The Damping parameter for all the bones
///in the tree will be set to GetOverrideDamping(), replacing
///the value set by the Author of the asset.
virtual bool ShouldOverrideDamping() const = 0;
///A value from 0.0 to 1.0. 0.0 means no damping, lots of back and forth movement around its original pose.
///1.0 means maximum damping, the segment will quickly converge back to its original pose.
virtual float GetOverrideDamping() const = 0;
///If true, The thickness parameter for all the bones
///in the tree will be set to GetOverrideThickness(), replacing
///the value set by the Author of the asset.
virtual bool ShouldOverrideThickness() const = 0;
///If you imagine the Segment (or Bone) to be a cylinder, this is its radius in meters.
virtual float GetOverrideThickness() const = 0;
}; //class ITouchBendingRule
} //namespace DataTypes
} // namespace SceneAPI
} // namespace AZ
@@ -40,7 +40,6 @@
#include <SceneAPI/SceneCore/DataTypes/Rules/ICommentRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMaterialRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMeshAdvancedRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IOriginRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ILodRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ISkeletonProxyRule.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IAnimationData.h>
@@ -166,7 +165,6 @@ namespace AZ
context->Class<AZ::SceneAPI::DataTypes::ICommentRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
context->Class<AZ::SceneAPI::DataTypes::IMaterialRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
context->Class<AZ::SceneAPI::DataTypes::IMeshAdvancedRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
context->Class<AZ::SceneAPI::DataTypes::IOriginRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
context->Class<AZ::SceneAPI::DataTypes::ILodRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
context->Class<AZ::SceneAPI::DataTypes::ISkeletonProxyRule, AZ::SceneAPI::DataTypes::IRule>()->Version(1);
// Register graph data interfaces
@@ -18,58 +18,18 @@ namespace AZ::SceneAPI::Events
// PreGenerateEventContext
/////////////
PreGenerateEventContext::PreGenerateEventContext(Containers::Scene& scene, const char* platformIdentifier)
GenerateEventBaseContext::GenerateEventBaseContext(Containers::Scene& scene, const char* platformIdentifier)
: m_scene(scene)
, m_platformIdentifier(platformIdentifier)
{
}
Containers::Scene& PreGenerateEventContext::GetScene() const
Containers::Scene& GenerateEventBaseContext::GetScene() const
{
return m_scene;
}
const char* PreGenerateEventContext::GetPlatformIdentifier() const
{
return m_platformIdentifier;
}
/////////////
// GenerateEventContext
/////////////
GenerateEventContext::GenerateEventContext(Containers::Scene& scene, const char* platformIdentifier)
: m_scene(scene)
, m_platformIdentifier(platformIdentifier)
{
}
Containers::Scene& GenerateEventContext::GetScene() const
{
return m_scene;
}
const char* GenerateEventContext::GetPlatformIdentifier() const
{
return m_platformIdentifier;
}
/////////////
// PostGenerateEventContext
/////////////
PostGenerateEventContext::PostGenerateEventContext(Containers::Scene& scene, const char* platformIdentifier)
: m_scene(scene)
, m_platformIdentifier(platformIdentifier)
{
}
Containers::Scene& PostGenerateEventContext::GetScene() const
{
return m_scene;
}
const char* PostGenerateEventContext::GetPlatformIdentifier() const
const char* GenerateEventBaseContext::GetPlatformIdentifier() const
{
return m_platformIdentifier;
}
@@ -24,13 +24,13 @@ namespace AZ::SceneAPI::Events
{
class ExportProductList;
// Signals the scene generation step is about to happen
class PreGenerateEventContext
class GenerateEventBaseContext
: public ICallContext
{
public:
AZ_RTTI(PreGenerateEventContext, "{0D1AB113-D35E-4C35-9820-E7B22F37D90C}", ICallContext)
SCENE_CORE_API PreGenerateEventContext(Containers::Scene& scene, const char* platformIdentifier);
AZ_RTTI(GenerateEventBaseContext, "{1717EB67-33A1-4516-8167-746093F7AEB6}", ICallContext)
SCENE_CORE_API GenerateEventBaseContext(Containers::Scene& scene, const char* platformIdentifier);
SCENE_CORE_API Containers::Scene& GetScene() const;
SCENE_CORE_API const char* GetPlatformIdentifier() const;
@@ -46,49 +46,57 @@ namespace AZ::SceneAPI::Events
const char* m_platformIdentifier = nullptr;
};
// Signals that all appropriate objects should be generated into the Scene
class GenerateEventContext
: public ICallContext
// Signals the scene generation step is about to happen
class PreGenerateEventContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(GenerateEventContext, "{B53CCBBF-965A-4709-AD33-AFD5F3AE8580}", ICallContext)
AZ_RTTI(PreGenerateEventContext, "{0D1AB113-D35E-4C35-9820-E7B22F37D90C}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
SCENE_CORE_API GenerateEventContext(Containers::Scene& scene, const char* platformIdentifier);
// Signals that new data such as procedurally generated objects should be added to the Scene
class GenerateEventContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(GenerateEventContext, "{B53CCBBF-965A-4709-AD33-AFD5F3AE8580}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
SCENE_CORE_API Containers::Scene& GetScene() const;
SCENE_CORE_API const char* GetPlatformIdentifier() const;
// Signals that new LODs should be added to the Scene
class GenerateLODEventContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(GenerateLODEventContext, "{2E3A6B98-1409-4895-8092-B7F8A410EF0D}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
private:
Containers::Scene& m_scene;
/**
* The platform identifier is configured in the AssetProcessorPlatformConfig.ini and is data driven
* it is generally a value like "pc" or "ios" or such.
* this const char* points at memory owned by the caller but it will always survive for the duration of the call.
*/
const char* m_platformIdentifier = nullptr;
// Signals that any new data, such as tangents and bitangents, should be added to the Scene
class GenerateAdditionEventContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(GenerateAdditionEventContext, "{105106FE-9ED7-48E6-9EA8-C7268BE8C625}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
// Signals that data simplification / complexity reduction should be run
class GenerateSimplificationEventContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(GenerateSimplificationEventContext, "{77F44B7F-C5BC-4411-B53F-E4307691841B}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
// Signals that the generation step is complete
class PostGenerateEventContext
: public ICallContext
: public GenerateEventBaseContext
{
public:
AZ_RTTI(PostGenerateEventContext, "{3EE65CBF-6C0E-425A-9ECC-3CC8FC4372F7}", ICallContext)
SCENE_CORE_API PostGenerateEventContext(Containers::Scene& scene, const char* platformIdentifier);
SCENE_CORE_API Containers::Scene& GetScene() const;
SCENE_CORE_API const char* GetPlatformIdentifier() const;
private:
Containers::Scene& m_scene;
/**
* The platform identifier is configured in the AssetProcessorPlatformConfig.ini and is data driven
* it is generally a value like "pc" or "ios" or such.
* this const char* points at memory owned by the caller but it will always survive for the duration of the call.
*/
const char* m_platformIdentifier = nullptr;
AZ_RTTI(PostGenerateEventContext, "{3EE65CBF-6C0E-425A-9ECC-3CC8FC4372F7}", GenerateEventBaseContext)
using GenerateEventBaseContext::GenerateEventBaseContext;
};
} // namespace AZ::SceneAPI::Events
@@ -36,7 +36,6 @@
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexColorData.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/ISceneNodeGroup.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMeshAdvancedRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ITouchBendingRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IMaterialRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ILodRule.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
@@ -284,13 +283,6 @@ namespace AZ
int physicsMaterialFlags = 0;
AZStd::vector<AZStd::string> targetNodes;
AZStd::shared_ptr<const DataTypes::ITouchBendingRule> touchBendingRule = rules.FindFirstByType<DataTypes::ITouchBendingRule>();
if (touchBendingRule)
{
targetNodes = Utilities::SceneGraphSelector::GenerateTargetNodes(sceneGraph,
touchBendingRule->GetSceneNodeSelectionList(), Utilities::SceneGraphSelector::IsMesh);
physicsMaterialFlags = AZ::GFxFramework::EMaterialFlags::MTL_FLAG_NODRAW_TOUCHBENDING;
}
for (auto& nodeName : targetNodes)
{
auto index = sceneGraph.Find(nodeName);
@@ -0,0 +1,34 @@
/*
* 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 <gmock/gmock.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBlendShapeData.h>
namespace AZ::SceneAPI::DataTypes
{
class MockIBlendShapeData
: public IBlendShapeData
{
public:
MOCK_CONST_METHOD0(GetUsedControlPointCount, size_t());
MOCK_CONST_METHOD1(GetControlPointIndex, int(int));
MOCK_CONST_METHOD1(GetUsedPointIndexForControlPoint, int(int));
MOCK_CONST_METHOD0(GetVertexCount, unsigned int());
MOCK_CONST_METHOD0(GetFaceCount, unsigned int());
MOCK_CONST_METHOD1(GetPosition, const AZ::Vector3&(unsigned int index));
MOCK_CONST_METHOD1(GetNormal, const AZ::Vector3&(unsigned int index));
MOCK_CONST_METHOD2(GetFaceVertexIndex, unsigned int(unsigned int face, unsigned int vertexIndex));
};
} // namespace AZ::SceneAPI::DataTypes
@@ -0,0 +1,34 @@
/*
* 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 <gmock/gmock.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IBlendShapeRule.h>
namespace AZ::SceneAPI::DataTypes { class IMockSceneNodeSelectionList; }
namespace AZ::SceneAPI::DataTypes
{
class MockIBlendShapeRule
: public IBlendShapeRule
{
public:
ISceneNodeSelectionList& GetSceneNodeSelectionList() override
{
return const_cast<ISceneNodeSelectionList&>(static_cast<const MockIBlendShapeRule*>(this)->GetSceneNodeSelectionList());
}
MOCK_CONST_METHOD0(GetSceneNodeSelectionList, const ISceneNodeSelectionList&());
};
} // namespace AZ::SceneAPI::DataTypes
@@ -0,0 +1,204 @@
/*
* 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/SceneCore/Utilities/CoordinateSystemConverter.h>
#include <AzCore/Math/Matrix3x3.h>
namespace AZ::SceneAPI
{
// Default constructor, initializes so that it basically does no conversion.
CoordinateSystemConverter::CoordinateSystemConverter()
: m_sourceTransform(AZ::Transform::CreateIdentity())
, m_targetTransform(AZ::Transform::CreateIdentity())
, m_conversionTransform(AZ::Transform::CreateIdentity())
, m_conversionTransformInversed(AZ::Transform::CreateIdentity())
, m_needsConversion(false)
, m_sourceRightHanded(CheckIfIsRightHanded(m_sourceTransform))
, m_targetRightHanded(CheckIfIsRightHanded(m_targetTransform))
{
m_targetBasisIndices[0] = 0;
m_targetBasisIndices[1] = 1;
m_targetBasisIndices[2] = 2;
}
CoordinateSystemConverter::CoordinateSystemConverter(const AZ::Vector3 sourceBasisVectors[3], const AZ::Vector3 targetBasisVectors[3], const AZ::u32 targetBasisIndices[3])
{
const AZ::Matrix3x3 sourceMatrix3x3 = AZ::Matrix3x3::CreateFromColumns(sourceBasisVectors[0], sourceBasisVectors[1], sourceBasisVectors[2]);
m_sourceTransform = AZ::Transform::CreateFromMatrix3x3(sourceMatrix3x3);
AZ_Assert(m_sourceTransform.IsOrthogonal(), "Invalid source transformation, basis vectors have to be orthogonal.");
const AZ::Matrix3x3 targetMatrix3x3 = AZ::Matrix3x3::CreateFromColumns(targetBasisVectors[0], targetBasisVectors[1], targetBasisVectors[2]);
m_targetTransform = AZ::Transform::CreateFromMatrix3x3(targetMatrix3x3);
AZ_Assert(m_targetTransform.IsOrthogonal(), "Invalid target transformation, basis vectors have to be orthogonal.");
m_conversionTransform = m_targetTransform * m_sourceTransform.GetInverse();
m_conversionTransformInversed = m_conversionTransform.GetInverse();
m_targetBasisIndices[0] = targetBasisIndices[0];
m_targetBasisIndices[1] = targetBasisIndices[1];
m_targetBasisIndices[2] = targetBasisIndices[2];
m_needsConversion = (m_sourceTransform != m_targetTransform);
m_sourceRightHanded = CheckIfIsRightHanded(m_sourceTransform);
m_targetRightHanded = CheckIfIsRightHanded(m_targetTransform);
}
const CoordinateSystemConverter CoordinateSystemConverter::CreateFromBasisVectors(const AZ::Vector3 sourceBasisVectors[3], const AZ::Vector3 targetBasisVectors[3], const AZ::u32 targetBasisIndices[3])
{
return CoordinateSystemConverter(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
const CoordinateSystemConverter CoordinateSystemConverter::CreateFromTransforms(const AZ::Transform& sourceTransform, const AZ::Transform& targetTransform, const AZ::u32 targetBasisIndices[3])
{
AZ::Vector3 sourceBasisVectors[3];
sourceBasisVectors[0] = sourceTransform.GetBasisX();
sourceBasisVectors[1] = sourceTransform.GetBasisY();
sourceBasisVectors[2] = sourceTransform.GetBasisZ();
AZ::Vector3 targetBasisVectors[3];
targetBasisVectors[0] = targetTransform.GetBasisX();
targetBasisVectors[1] = targetTransform.GetBasisY();
targetBasisVectors[2] = targetTransform.GetBasisZ();
return CoordinateSystemConverter(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
bool CoordinateSystemConverter::CheckIfIsRightHanded(const AZ::Transform& transform) const
{
const AZ::Vector3 right = transform.GetBasisX();
const AZ::Vector3 up = transform.GetBasisY();
const AZ::Vector3 forward = transform.GetBasisZ();
return ((right.Cross(up)).Dot(forward) <= 0.0f);
}
//-------------------------------------------------------------------------
// Conversions
//-------------------------------------------------------------------------
AZ::Quaternion CoordinateSystemConverter::ConvertQuaternion(const AZ::Quaternion& input) const
{
if (!m_needsConversion)
{
return input;
}
const AZ::Vector3 vec = ConvertVector3( input.GetImaginary() );
float w = input.GetW();
if (m_sourceRightHanded != m_targetRightHanded)
{
w = -w;
}
return AZ::Quaternion(vec.GetX(), vec.GetY(), vec.GetZ(), w);
}
AZ::Vector3 CoordinateSystemConverter::ConvertVector3(const AZ::Vector3& input) const
{
if (!m_needsConversion)
{
return input;
}
return m_conversionTransform.TransformPoint(input);
}
AZ::Transform CoordinateSystemConverter::ConvertTransform(const AZ::Transform& input) const
{
if (!m_needsConversion)
{
return input;
}
return input * m_conversionTransform;
}
AZ::Matrix3x4 CoordinateSystemConverter::ConvertMatrix3x4(const AZ::Matrix3x4 & input) const
{
if (!m_needsConversion)
{
return input;
}
return input * AZ::Matrix3x4::CreateFromTransform(m_conversionTransform);
}
// Convert a scale value, which never flips some axis or so, just switches them.
// Think of two coordinate systems, where for example the Z axis is inverted in one of them, the scale will remain the same, in both systems.
// However, if we swap Y and Z, the scale Y and Z still have to be swapped.
AZ::Vector3 CoordinateSystemConverter::ConvertScale(const AZ::Vector3& input) const
{
if (!m_needsConversion)
{
return input;
}
return AZ::Vector3( input.GetElement(m_targetBasisIndices[0]),
input.GetElement(m_targetBasisIndices[1]),
input.GetElement(m_targetBasisIndices[2]) );
}
//-------------------------------------------------------------------------
// Inverse Conversions
//-------------------------------------------------------------------------
AZ::Quaternion CoordinateSystemConverter::InverseConvertQuaternion(const AZ::Quaternion& input) const
{
if (!m_needsConversion)
{
return input;
}
const AZ::Vector3 vec = InverseConvertVector3( input.GetImaginary() );
float w = input.GetW();
if (m_sourceRightHanded != m_targetRightHanded)
{
w = -w;
}
return AZ::Quaternion(vec.GetX(), vec.GetY(), vec.GetZ(), w);
}
AZ::Vector3 CoordinateSystemConverter::InverseConvertVector3(const AZ::Vector3& input) const
{
if (!m_needsConversion)
{
return input;
}
return m_conversionTransformInversed.TransformPoint(input);
}
AZ::Transform CoordinateSystemConverter::InverseConvertTransform(const AZ::Transform& input) const
{
if (!m_needsConversion)
{
return input;
}
return input * m_conversionTransformInversed;
}
AZ::Vector3 CoordinateSystemConverter::InverseConvertScale(const AZ::Vector3& input) const
{
return ConvertScale(input);
}
} // namespace AZ::SceneAPI
@@ -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.
*
*/
#pragma once
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Quaternion.h>
#include <SceneAPI/SceneCore/SceneCoreConfiguration.h>
namespace AZ::SceneAPI
{
class SCENE_CORE_API CoordinateSystemConverter
{
public:
CoordinateSystemConverter();
static const CoordinateSystemConverter CreateFromBasisVectors(const AZ::Vector3 sourceBasisVectors[3], const AZ::Vector3 targetBasisVectors[3], const AZ::u32 targetBasisIndices[3]);
static const CoordinateSystemConverter CreateFromTransforms(const AZ::Transform& sourceTransform, const AZ::Transform& targetTransform, const AZ::u32 targetBasisIndices[3]);
// Inline get data.
bool IsConversionNeeded() const { return m_needsConversion; }
bool IsSourceRightHanded() const { return m_sourceRightHanded; }
bool IsTargetRightHanded() const { return m_targetRightHanded; }
const AZ::Transform GetSourceTransform() const { return m_sourceTransform; }
const AZ::Transform GetTargetTransform() const { return m_targetTransform; }
const AZ::Transform GetConversionTransform() const { return m_conversionTransform; }
const AZ::Transform GetInverseConversionTransform() const { return m_conversionTransformInversed; }
// Conversion methods.
AZ::Quaternion ConvertQuaternion(const AZ::Quaternion& input) const;
AZ::Vector3 ConvertVector3(const AZ::Vector3& input) const;
AZ::Vector3 ConvertScale(const AZ::Vector3& input) const;
AZ::Transform ConvertTransform(const AZ::Transform& input) const;
AZ::Matrix3x4 ConvertMatrix3x4(const AZ::Matrix3x4 & input) const;
// Inverse conversion methods.
AZ::Quaternion InverseConvertQuaternion(const AZ::Quaternion& input) const;
AZ::Vector3 InverseConvertVector3(const AZ::Vector3& input) const;
AZ::Vector3 InverseConvertScale(const AZ::Vector3& input) const;
AZ::Transform InverseConvertTransform(const AZ::Transform& input) const;
// Helper methods.
bool CheckIfIsRightHanded(const AZ::Transform& transform) const;
private:
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
AZ::Transform m_sourceTransform;
AZ::Transform m_targetTransform;
AZ::Transform m_conversionTransform;
AZ::Transform m_conversionTransformInversed;
AZ_POP_DISABLE_OVERRIDE_WARNING
AZ::u32 m_targetBasisIndices[3];
bool m_needsConversion;
bool m_sourceRightHanded;
bool m_targetRightHanded;
CoordinateSystemConverter(const AZ::Vector3 sourceBasisVectors[3], const AZ::Vector3 targetBasisVectors[3], const AZ::u32 targetBasisIndices[3]);
};
} // namespace AZ::SceneAPI
@@ -44,7 +44,18 @@ namespace AZ
return object && object->RTTI_IsTypeOf(DataTypes::IMeshData::TYPEINFO_Uuid());
}
AZStd::vector<AZStd::string> SceneGraphSelector::GenerateTargetNodes(const Containers::SceneGraph& graph, const DataTypes::ISceneNodeSelectionList& list, NodeFilterFunction nodeFilter)
Containers::SceneGraph::NodeIndex SceneGraphSelector::RemapToOptimizedMesh(const Containers::SceneGraph& graph, const Containers::SceneGraph::NodeIndex& index)
{
const auto& nodeName = graph.GetNodeName(index);
const AZStd::string optimizedName = AZStd::string(nodeName.GetPath(), nodeName.GetPathLength()) + "_optimized";
if (auto optimizedIndex = graph.Find(optimizedName); optimizedIndex.IsValid())
{
return optimizedIndex;
}
return index;
}
AZStd::vector<AZStd::string> SceneGraphSelector::GenerateTargetNodes(const Containers::SceneGraph& graph, const DataTypes::ISceneNodeSelectionList& list, NodeFilterFunction nodeFilter, NodeRemapFunction nodeRemap)
{
AZStd::vector<AZStd::string> targetNodes;
AZStd::set<AZStd::string> selectedNodesSet;
@@ -52,8 +63,8 @@ namespace AZ
CopySelectionToSet(selectedNodesSet, unselectedNodesSet, list);
CorrectRootNode(graph, selectedNodesSet, unselectedNodesSet);
auto nodeIterator = graph.ConvertToHierarchyIterator(graph.GetRoot());
auto view = Containers::Views::MakeSceneGraphDownwardsView<Containers::Views::BreadthFirst>(graph, nodeIterator, graph.GetContentStorage().cbegin(), true);
const auto nodeIterator = graph.ConvertToHierarchyIterator(graph.GetRoot());
const auto view = Containers::Views::MakeSceneGraphDownwardsView<Containers::Views::BreadthFirst>(graph, nodeIterator, graph.GetContentStorage().cbegin(), true);
if (view.begin() == view.end())
{
return targetNodes;
@@ -62,15 +73,24 @@ namespace AZ
{
Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(it.GetHierarchyIterator());
AZStd::string currentNodeName = graph.GetNodeName(index).GetPath();
if (unselectedNodesSet.find(currentNodeName) != unselectedNodesSet.end())
if (unselectedNodesSet.contains(currentNodeName))
{
continue;
}
if (selectedNodesSet.find(currentNodeName) != selectedNodesSet.end())
if (selectedNodesSet.contains(currentNodeName))
{
if (nodeFilter(graph, index))
{
targetNodes.push_back(currentNodeName);
Containers::SceneGraph::NodeIndex remappedIndex = nodeRemap(graph, index);
if (remappedIndex == index)
{
targetNodes.emplace_back(AZStd::move(currentNodeName));
}
else
{
const Containers::SceneGraph::Name& nodeName = graph.GetNodeName(remappedIndex);
targetNodes.emplace_back(nodeName.GetPath(), nodeName.GetPathLength());
}
}
continue;
}
@@ -79,16 +99,25 @@ namespace AZ
if (parentIndex.IsValid())
{
AZStd::string parentNodeName = graph.GetNodeName(parentIndex).GetPath();
if (unselectedNodesSet.find(parentNodeName) != unselectedNodesSet.end())
if (unselectedNodesSet.contains(parentNodeName))
{
unselectedNodesSet.insert(currentNodeName);
}
else if (selectedNodesSet.find(parentNodeName) != selectedNodesSet.end())
else if (selectedNodesSet.contains(parentNodeName))
{
selectedNodesSet.insert(currentNodeName);
if (nodeFilter(graph, index))
{
targetNodes.push_back(currentNodeName);
Containers::SceneGraph::NodeIndex remappedIndex = nodeRemap(graph, index);
if (remappedIndex == index)
{
targetNodes.emplace_back(AZStd::move(currentNodeName));
}
else
{
const Containers::SceneGraph::Name& nodeName = graph.GetNodeName(remappedIndex);
targetNodes.emplace_back(nodeName.GetPath(), nodeName.GetPathLength());
}
}
}
else
@@ -159,12 +188,12 @@ namespace AZ
Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(it.GetHierarchyIterator());
AZStd::string currentNodeName = it->first.GetPath();
// Check if item is already registered and if so add it to the appropriate list.
if (unselectedNodesSet.find(currentNodeName) != unselectedNodesSet.end())
if (unselectedNodesSet.contains(currentNodeName))
{
list.RemoveSelectedNode(AZStd::move(currentNodeName));
continue;
}
if (selectedNodesSet.find(currentNodeName) != selectedNodesSet.end())
if (selectedNodesSet.contains(currentNodeName))
{
list.AddSelectedNode(AZStd::move(currentNodeName));
continue;
@@ -176,7 +205,7 @@ namespace AZ
if (parentIndex.IsValid())
{
AZStd::string parentNodeName = graph.GetNodeName(parentIndex).GetPath();
if (unselectedNodesSet.find(parentNodeName) != unselectedNodesSet.end())
if (unselectedNodesSet.contains(parentNodeName))
{
unselectedNodesSet.insert(currentNodeName);
list.RemoveSelectedNode(AZStd::move(currentNodeName));
@@ -208,7 +237,7 @@ namespace AZ
AZStd::string currentNodeName = it->first.GetPath();
if (nodeFilter(graph, index))
{
if (targetNodes.find(currentNodeName) != targetNodes.end())
if (targetNodes.contains(currentNodeName))
{
list.AddSelectedNode(currentNodeName);
}
@@ -18,39 +18,38 @@
#include <AzCore/std/containers/unordered_set.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
namespace AZ
namespace AZ::SceneAPI::DataTypes { class ISceneNodeSelectionList; }
namespace AZ::SceneAPI::Utilities
{
namespace SceneAPI
// SceneGraphSelector provides utilities including converting selected and unselected node lists
// in the MeshGroup into the final target node list.
class SceneGraphSelector
{
namespace DataTypes
public:
using NodeFilterFunction = bool(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index);
using NodeRemapFunction = Containers::SceneGraph::NodeIndex(const Containers::SceneGraph& graph, const Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static AZStd::vector<AZStd::string> GenerateTargetNodes(const Containers::SceneGraph& graph, const DataTypes::ISceneNodeSelectionList& list,
NodeFilterFunction nodeFilter, NodeRemapFunction nodeRemap = NoRemap);
SCENE_CORE_API static void SelectAll(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UnselectAll(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UpdateNodeSelection(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UpdateTargetNodes(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list,
const AZStd::unordered_set<AZStd::string>& targetNodes, NodeFilterFunction nodeFilter);
SCENE_CORE_API static bool IsTreeViewType(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static bool IsMesh(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static bool IsMeshObject(const AZStd::shared_ptr<const DataTypes::IGraphObject>& object);
SCENE_CORE_API static Containers::SceneGraph::NodeIndex NoRemap(const Containers::SceneGraph& /*graph*/, const Containers::SceneGraph::NodeIndex& index)
{
class ISceneNodeSelectionList;
return index;
}
namespace Utilities
{
// SceneGraphSelector provides utilities including converting selected and unselected node lists
// in the MeshGroup into the final target node list.
class SceneGraphSelector
{
public:
using NodeFilterFunction = AZStd::function<bool(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index)>;
SCENE_CORE_API static Containers::SceneGraph::NodeIndex RemapToOptimizedMesh(const Containers::SceneGraph& graph, const Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static AZStd::vector<AZStd::string> GenerateTargetNodes(const Containers::SceneGraph& graph, const DataTypes::ISceneNodeSelectionList& list,
NodeFilterFunction nodeFilter);
SCENE_CORE_API static void SelectAll(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UnselectAll(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UpdateNodeSelection(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list);
SCENE_CORE_API static void UpdateTargetNodes(const Containers::SceneGraph& graph, DataTypes::ISceneNodeSelectionList& list,
const AZStd::unordered_set<AZStd::string>& targetNodes, NodeFilterFunction nodeFilter);
SCENE_CORE_API static bool IsTreeViewType(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static bool IsMesh(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index);
SCENE_CORE_API static bool IsMeshObject(const AZStd::shared_ptr<const DataTypes::IGraphObject>& object);
private:
static void CopySelectionToSet(AZStd::set<AZStd::string>& selected, AZStd::set<AZStd::string>& unselected, const DataTypes::ISceneNodeSelectionList& list);
static void CorrectRootNode(const Containers::SceneGraph& graph, AZStd::set<AZStd::string>& selected, AZStd::set<AZStd::string>& unselected);
};
}
}
}
private:
static void CopySelectionToSet(AZStd::set<AZStd::string>& selected, AZStd::set<AZStd::string>& unselected, const DataTypes::ISceneNodeSelectionList& list);
static void CorrectRootNode(const Containers::SceneGraph& graph, AZStd::set<AZStd::string>& selected, AZStd::set<AZStd::string>& unselected);
};
}
@@ -43,12 +43,12 @@ set(FILES
DataTypes/Rules/ICommentRule.h
DataTypes/Rules/ILodRule.h
DataTypes/Rules/IMeshAdvancedRule.h
DataTypes/Rules/IOriginRule.h
DataTypes/Rules/IMaterialRule.h
DataTypes/Rules/IScriptProcessorRule.h
DataTypes/Rules/ISkeletonProxyRule.h
DataTypes/Rules/ITouchBendingRule.h
DataTypes/Rules/ICoordinateSystemRule.h
DataTypes/Rules/IClothRule.h
DataTypes/Rules/ISkinRule.h
Components/BehaviorComponent.h
Components/BehaviorComponent.cpp
Components/ExportingComponent.h
@@ -123,6 +123,8 @@ set(FILES
Import/ManifestImportRequestHandler.cpp
Export/MtlMaterialExporter.h
Export/MtlMaterialExporter.cpp
Utilities/CoordinateSystemConverter.h
Utilities/CoordinateSystemConverter.cpp
Utilities/SceneGraphSelector.h
Utilities/SceneGraphSelector.cpp
Utilities/FileUtilities.h
@@ -115,7 +115,8 @@ namespace AZ
Events::ProcessingResult MeshGroup::BuildDefault(Containers::Scene& scene) const
{
if (SceneHasMeshGroup(scene) || !Utilities::DoesSceneGraphContainDataLike<DataTypes::IMeshData>(scene, true) || Utilities::DoesSceneGraphContainDataLike<DataTypes::IBoneData>(scene, true))
if (SceneHasMeshGroup(scene) ||
!Utilities::DoesSceneGraphContainDataLike<DataTypes::IMeshData>(scene, true))
{
return Events::ProcessingResult::Ignored;
}
@@ -21,6 +21,7 @@
#include <SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h>
#include <SceneAPI/SceneData/Behaviors/SkeletonGroup.h>
#include <SceneAPI/SceneData/Behaviors/SkinGroup.h>
#include <SceneAPI/SceneData/Behaviors/SkinRuleBehavior.h>
namespace AZ
{
@@ -40,7 +41,8 @@ namespace AZ
Behaviors::MeshGroup::CreateDescriptor(),
Behaviors::ScriptProcessorRuleBehavior::CreateDescriptor(),
Behaviors::SkeletonGroup::CreateDescriptor(),
Behaviors::SkinGroup::CreateDescriptor()
Behaviors::SkinGroup::CreateDescriptor(),
SkinRuleBehavior::CreateDescriptor()
});
}
} // SceneData
@@ -29,6 +29,7 @@
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneData/Rules/ScriptProcessorRule.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
@@ -36,6 +37,41 @@ namespace AZ
{
namespace Behaviors
{
class EditorPythonConsoleNotificationHandler final
: protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
{
public:
EditorPythonConsoleNotificationHandler()
{
BusConnect();
}
~EditorPythonConsoleNotificationHandler()
{
BusDisconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorPythonConsoleNotifications
void OnTraceMessage(AZStd::string_view message) override
{
using namespace AZ::SceneAPI::Utilities;
AZ_TracePrintf(LogWindow, "%.*s \n", AZ_STRING_ARG(message));
}
void OnErrorMessage(AZStd::string_view message) override
{
using namespace AZ::SceneAPI::Utilities;
AZ_TracePrintf(ErrorWindow, "[ERROR] %.*s \n", AZ_STRING_ARG(message));
}
void OnExceptionMessage(AZStd::string_view message) override
{
using namespace AZ::SceneAPI::Utilities;
AZ_TracePrintf(ErrorWindow, "[EXCEPTION] %.*s \n", AZ_STRING_ARG(message));
}
};
// a event bus to signal during scene building
struct ScriptBuildingNotifications
: public AZ::EBusTraits
@@ -182,6 +218,7 @@ namespace AZ
&ScriptBuildingNotificationBus::Events::OnUpdateManifest,
scene);
};
EditorPythonConsoleNotificationHandler logger;
m_editorPythonEventsInterface->ExecuteWithLock(executeCallback);
// attempt to load the manifest string back to a JSON-scene-manifest
@@ -0,0 +1,65 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
#include <SceneAPI/SceneData/Rules/SkinRule.h>
#include <SceneAPI/SceneData/Behaviors/SkinRuleBehavior.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneData
{
void SkinRuleBehavior::Reflect(AZ::ReflectContext* context)
{
SkinRule::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SkinRuleBehavior, SceneCore::BehaviorComponent>()->Version(1);
}
}
void SkinRuleBehavior::Activate()
{
AZ::SceneAPI::Events::ManifestMetaInfoBus::Handler::BusConnect();
}
void SkinRuleBehavior::Deactivate()
{
AZ::SceneAPI::Events::ManifestMetaInfoBus::Handler::BusDisconnect();
}
void SkinRuleBehavior::InitializeObject([[maybe_unused]] const Containers::Scene& scene, DataTypes::IManifestObject& target)
{
if (azrtti_istypeof<DataTypes::IMeshGroup>(target))
{
DataTypes::IMeshGroup* meshGroup = azrtti_cast<DataTypes::IMeshGroup*>(&target);
AZ::SceneAPI::Containers::RuleContainer& rules = meshGroup->GetRuleContainer();
// Only add the skin rule if the scene contain any skinning data.
if (!rules.ContainsRuleOfType<SkinRule>() && Utilities::DoesSceneGraphContainDataLike<DataTypes::ISkinWeightData>(scene, true))
{
rules.AddRule(AZStd::make_shared<SkinRule>());
}
}
}
}
}
}
@@ -0,0 +1,43 @@
#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/Memory/Memory.h>
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
#include <SceneAPI/SceneCore/Components/BehaviorComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneData
{
class SkinRuleBehavior
: public SceneCore::BehaviorComponent
, public Events::ManifestMetaInfoBus::Handler
{
public:
AZ_COMPONENT(SkinRuleBehavior, "{B212A863-32DD-4F92-948C-FC0ADAEEAB4A}", SceneCore::BehaviorComponent);
~SkinRuleBehavior() override = default;
// From BehaviorComponent
void Activate() override;
void Deactivate() override;
static void Reflect(AZ::ReflectContext* context);
void InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) override;
};
}
}
}
@@ -144,6 +144,96 @@ namespace AZ
return m_shininess;
}
void MaterialData::SetUseColorMap(bool useColorMap)
{
m_useColorMap = useColorMap;
}
bool MaterialData::GetUseColorMap() const
{
return m_useColorMap;
}
void MaterialData::SetBaseColor(const AZ::Vector3& baseColor)
{
m_baseColor = baseColor;
}
const AZ::Vector3& MaterialData::GetBaseColor() const
{
return m_baseColor;
}
void MaterialData::SetUseMetallicMap(bool useMetallicMap)
{
m_useMetallicMap = useMetallicMap;
}
bool MaterialData::GetUseMetallicMap() const
{
return m_useMetallicMap;
}
void MaterialData::SetMetallicFactor(float metallicFactor)
{
m_metallicFactor = metallicFactor;
}
float MaterialData::GetMetallicFactor() const
{
return m_metallicFactor;
}
void MaterialData::SetUseRoughnessMap(bool useRoughnessMap)
{
m_useRoughnessMap = useRoughnessMap;
}
bool MaterialData::GetUseRoughnessMap() const
{
return m_useRoughnessMap;
}
void MaterialData::SetRoughnessFactor(float roughnessFactor)
{
m_roughnessFactor = roughnessFactor;
}
float MaterialData::GetRoughnessFactor() const
{
return m_roughnessFactor;
}
void MaterialData::SetUseEmissiveMap(bool useEmissiveMap)
{
m_useEmissiveMap = useEmissiveMap;
}
bool MaterialData::GetUseEmissiveMap() const
{
return m_useEmissiveMap;
}
void MaterialData::SetEmissiveIntensity(float emissiveIntensity)
{
m_emissiveIntensity = emissiveIntensity;
}
float MaterialData::GetEmissiveIntensity() const
{
return m_emissiveIntensity;
}
void MaterialData::SetUseAOMap(bool useAOMap)
{
m_useAOMap = useAOMap;
}
bool MaterialData::GetUseAOMap() const
{
return m_useAOMap;
}
uint64_t MaterialData::GetUniqueId() const
{
return m_uniqueId;
@@ -154,7 +244,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MaterialData>()->Version(2)
serializeContext->Class<MaterialData>()->Version(4)
->Field("textureMap", &MaterialData::m_textureMap)
->Field("diffuseColor", &MaterialData::m_diffuseColor)
->Field("specularColor", &MaterialData::m_specularColor)
@@ -162,7 +252,16 @@ namespace AZ
->Field("opacity", &MaterialData::m_opacity)
->Field("shininess", &MaterialData::m_shininess)
->Field("noDraw", &MaterialData::m_isNoDraw)
->Field("uniqueId", &MaterialData::m_uniqueId);
->Field("uniqueId", &MaterialData::m_uniqueId)
->Field("useColorMap", &MaterialData::m_useColorMap)
->Field("baseColor", &MaterialData::m_baseColor)
->Field("useMetallicMap", &MaterialData::m_useMetallicMap)
->Field("metallicFactor", &MaterialData::m_metallicFactor)
->Field("useRoughnessMap", &MaterialData::m_useRoughnessMap)
->Field("roughnessFactor", &MaterialData::m_roughnessFactor)
->Field("useEmissiveMap", &MaterialData::m_useEmissiveMap)
->Field("emissiveIntensity", &MaterialData::m_emissiveIntensity)
->Field("useAOMap", &MaterialData::m_useAOMap);
EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
@@ -183,7 +282,16 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_opacity, "Opacity", "Opacity strength of the material, with 0 fully transparent and 1 fully opaque.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_shininess, "Shininess", "The shininess strength of the material.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_isNoDraw, "No draw", "If enabled the mesh with material will not be drawn.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_textureMap, "Texture map", "List of assigned texture slots.");
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_textureMap, "Texture map", "List of assigned texture slots.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_useColorMap, "Use Color Map", "True to use a color map, false to ignore it.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_baseColor, "Base Color", "The base color of the material.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_useMetallicMap, "Use Metallic Map", "True to use a metallic map, false to ignore it.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_metallicFactor, "Metallic Factor", "How metallic the material is.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_useRoughnessMap, "Use Roughness Map", "True to use a roughness map, false to ignore it.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_roughnessFactor, "Roughness Factor", "How rough the material is.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_useEmissiveMap, "Use Emissive Map", "True to use an emissive map, false to ignore it.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_emissiveIntensity, "Emissive Intensity", "The intensity of the emissiveness of the material.")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialData::m_useAOMap, "Use Ambient Occlusion Map", "True to use an ambient occlusion map, false to ignore it.");
}
}
}
@@ -47,6 +47,16 @@ namespace AZ
SCENE_DATA_API virtual void SetOpacity(float opacity);
SCENE_DATA_API virtual void SetShininess(float shininess);
SCENE_DATA_API virtual void SetUniqueId(uint64_t uid);
SCENE_DATA_API virtual void SetUseColorMap(bool useColorMap);
SCENE_DATA_API virtual void SetBaseColor(const AZ::Vector3& baseColor);
SCENE_DATA_API virtual void SetUseMetallicMap(bool useMetallicMap);
SCENE_DATA_API virtual void SetMetallicFactor(float metallicFactor);
SCENE_DATA_API virtual void SetUseRoughnessMap(bool useRoughnessMap);
SCENE_DATA_API virtual void SetRoughnessFactor(float roughnessFactor);
SCENE_DATA_API virtual void SetUseEmissiveMap(bool useEmissiveMap);
SCENE_DATA_API virtual void SetEmissiveIntensity(float emissiveIntensity);
SCENE_DATA_API virtual void SetUseAOMap(bool useAOMap);
SCENE_DATA_API const AZStd::string& GetTexture(TextureMapType mapType) const override;
SCENE_DATA_API bool IsNoDraw() const override;
@@ -57,6 +67,15 @@ namespace AZ
SCENE_DATA_API float GetOpacity() const override;
SCENE_DATA_API float GetShininess() const override;
SCENE_DATA_API uint64_t GetUniqueId() const override;
SCENE_DATA_API bool GetUseColorMap() const override;
SCENE_DATA_API const AZ::Vector3& GetBaseColor() const override;
SCENE_DATA_API bool GetUseMetallicMap() const override;
SCENE_DATA_API float GetMetallicFactor() const override;
SCENE_DATA_API bool GetUseRoughnessMap() const override;
SCENE_DATA_API float GetRoughnessFactor() const override;
SCENE_DATA_API bool GetUseEmissiveMap() const override;
SCENE_DATA_API float GetEmissiveIntensity() const override;
SCENE_DATA_API bool GetUseAOMap() const override;
static void Reflect(ReflectContext* context);
@@ -66,8 +85,18 @@ namespace AZ
AZ::Vector3 m_diffuseColor;
AZ::Vector3 m_specularColor;
AZ::Vector3 m_emissiveColor;
AZ::Vector3 m_baseColor;
float m_opacity;
float m_shininess;
float m_metallicFactor = 0.0f;
float m_roughnessFactor = 0.0f;
float m_emissiveIntensity = 0.0f;
bool m_useColorMap = false;
bool m_useMetallicMap = false;
bool m_useRoughnessMap = false;
bool m_useEmissiveMap = false;
bool m_useAOMap = false;
bool m_isNoDraw;
@@ -12,15 +12,65 @@
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(AZ::SceneAPI::DataTypes::IMeshData::Face, "{F9F49C1A-014F-46F5-A46F-B56D8CB46C2B}");
namespace SceneData
{
namespace GraphData
{
namespace DataTypes = AZ::SceneAPI::DataTypes;
void MeshData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshData>()->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneAPI::DataTypes::IMeshData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetUnitSizeInMeters", &MeshData::GetUnitSizeInMeters)
->Method("GetOriginalUnitSizeInMeters", &MeshData::GetOriginalUnitSizeInMeters);
behaviorContext->Class<MeshData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetSdkMeshIndex", &MeshData::GetSdkMeshIndex)
->Method("GetControlPointIndex", &MeshData::GetControlPointIndex)
->Method("GetUsedControlPointCount", &MeshData::GetUsedControlPointCount)
->Method("GetUsedPointIndexForControlPoint", &MeshData::GetUsedPointIndexForControlPoint)
->Method("GetVertexCount", &MeshData::GetVertexCount)
->Method("HasNormalData", &MeshData::HasNormalData)
->Method("GetPosition", &MeshData::GetPosition)
->Method("GetNormal", &MeshData::GetNormal)
->Method("GetFaceCount", &MeshData::GetFaceCount)
->Method("GetFaceInfo", &MeshData::GetFaceInfo)
->Method("GetFaceMaterialId", &MeshData::GetFaceMaterialId)
->Method("GetVertexIndex", &MeshData::GetVertexIndex);
behaviorContext->Class<SceneAPI::DataTypes::IMeshData::Face>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetVertexIndex", [](const SceneAPI::DataTypes::IMeshData::Face& self, int index)
{
if (index >= 0 && index < 3)
{
return self.vertexIndex[index];
}
return aznumeric_cast<unsigned int>(0);
});
}
}
MeshData::~MeshData() = default;
@@ -32,6 +32,8 @@ namespace AZ
public:
AZ_RTTI(MeshData, "{a2589bd4-42fb-40ba-a38d-cfcd6e9ea169}", AZ::SceneAPI::DataTypes::IMeshData)
static void Reflect(ReflectContext* context);
SCENE_DATA_API ~MeshData() override;
//assumes 1 to 1 mapping for these position, normal, color, uv
//positions with more than one normal or uv (seam) will duplicate shared values in multiple verts
@@ -11,6 +11,8 @@
*/
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
@@ -18,6 +20,29 @@ namespace AZ
{
namespace GraphData
{
void MeshVertexBitangentData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshVertexBitangentData>()->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MeshVertexBitangentData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetCount", &MeshVertexBitangentData::GetCount)
->Method("GetBitangent", &MeshVertexBitangentData::GetBitangent)
->Method("GetBitangentSetIndex", &MeshVertexBitangentData::GetBitangentSetIndex)
->Method("GetTangentSpace", &MeshVertexBitangentData::GetTangentSpace)
->Enum<(int)SceneAPI::DataTypes::TangentSpace::EMotionFX>("EMotionFX")
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromFbx>("FromFbx")
->Enum<(int)SceneAPI::DataTypes::TangentSpace::MikkT>("MikkT");
}
}
size_t MeshVertexBitangentData::GetCount() const
{
@@ -32,6 +32,8 @@ namespace AZ
public:
AZ_RTTI(MeshVertexBitangentData, "{F56FB088-4C92-4453-AFE9-4E820F03FA90}", AZ::SceneAPI::DataTypes::IMeshVertexBitangentData);
static void Reflect(ReflectContext* context);
SCENE_DATA_API ~MeshVertexBitangentData() override = default;
SCENE_DATA_API size_t GetCount() const override;
@@ -11,13 +11,45 @@
*/
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::DataTypes::Color, "{937E3BF8-5204-4D40-A8DA-C8F083C89F9F}");
namespace SceneData
{
namespace GraphData
{
void MeshVertexColorData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshVertexColorData>()->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MeshVertexColorData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetCustomName", [](const MeshVertexColorData& self) { return self.GetCustomName().GetCStr(); })
->Method("GetCount", &MeshVertexColorData::GetCount )
->Method("GetColor", &MeshVertexColorData::GetColor);
behaviorContext->Class<AZ::SceneAPI::DataTypes::Color>("MeshVertexColor")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Property("red", BehaviorValueGetter(&AZ::SceneAPI::DataTypes::Color::red), nullptr)
->Property("green", BehaviorValueGetter(&AZ::SceneAPI::DataTypes::Color::green), nullptr)
->Property("blue", BehaviorValueGetter(&AZ::SceneAPI::DataTypes::Color::blue), nullptr)
->Property("alpha", BehaviorValueGetter(&AZ::SceneAPI::DataTypes::Color::alpha), nullptr);
}
}
const AZ::Name& MeshVertexColorData::GetCustomName() const
{
return m_customName;
@@ -28,6 +28,8 @@ namespace AZ
public:
AZ_RTTI(MeshVertexColorData, "{17477B86-B163-4574-8FB2-4916BC218B3D}", AZ::SceneAPI::DataTypes::IMeshVertexColorData);
static void Reflect(ReflectContext* context);
SCENE_DATA_API ~MeshVertexColorData() override = default;
SCENE_DATA_API const AZ::Name& GetCustomName() const override;
@@ -11,6 +11,8 @@
*/
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
@@ -18,6 +20,29 @@ namespace AZ
{
namespace GraphData
{
void MeshVertexTangentData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshVertexTangentData>()->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MeshVertexTangentData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetCount", &MeshVertexTangentData::GetCount)
->Method("GetTangent", &MeshVertexTangentData::GetTangent)
->Method("GetTangentSetIndex", &MeshVertexTangentData::GetTangentSetIndex)
->Method("GetTangentSpace", &MeshVertexTangentData::GetTangentSpace)
->Enum<(int)SceneAPI::DataTypes::TangentSpace::EMotionFX>("EMotionFX")
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromFbx>("FromFbx")
->Enum<(int)SceneAPI::DataTypes::TangentSpace::MikkT>("MikkT");
}
}
size_t MeshVertexTangentData::GetCount() const
{
@@ -31,6 +31,8 @@ namespace AZ
public:
AZ_RTTI(MeshVertexTangentData, "{C16F0F38-8F8F-45A2-A33B-F2758922A7C4}", AZ::SceneAPI::DataTypes::IMeshVertexTangentData);
static void Reflect(ReflectContext* context);
SCENE_DATA_API ~MeshVertexTangentData() override = default;
SCENE_DATA_API size_t GetCount() const override;
@@ -11,6 +11,8 @@
*/
#include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
@@ -18,6 +20,26 @@ namespace AZ
{
namespace GraphData
{
void MeshVertexUVData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MeshVertexUVData>()->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MeshVertexUVData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetCustomName",[](const MeshVertexUVData& self) { return self.GetCustomName().GetCStr(); })
->Method("GetCount", &MeshVertexUVData::GetCount)
->Method("GetUV", &MeshVertexUVData::GetUV);
}
}
const AZ::Name& MeshVertexUVData::GetCustomName() const
{
return m_customName;
@@ -49,7 +71,6 @@ namespace AZ
m_uvs.push_back(uv);
}
void MeshVertexUVData::GetDebugOutput(AZ::SceneAPI::Utilities::DebugOutput& output) const
{
output.Write("UVs", m_uvs);

Some files were not shown because too many files have changed in this diff Show More