Integrating up through commit 90f050496

This commit is contained in:
alexpete
2021-04-07 14:03:29 -07:00
parent 8f2ed080a9
commit c2cbd430fe
2694 changed files with 285622 additions and 176874 deletions
@@ -13,6 +13,7 @@
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
@@ -38,8 +39,10 @@ namespace AZ
namespace FbxSceneBuilder
{
const char* AssImpAnimationImporter::s_animationNodeName = "animation";
const FbxSDKWrapper::FbxTimeWrapper::TimeMode AssImpAnimationImporter::s_defaultTimeMode =
FbxSDKWrapper::FbxTimeWrapper::frames30;
// Downstream only supports 30 frames per second sample rate. Adjusting to 60 doubles the
// length of the animations, they still play back at 30 frames per second.
const double AssImpAnimationImporter::s_defaultTimeStepSampleRate = 1.0 / 30.0;
AssImpAnimationImporter::AssImpAnimationImporter()
{
@@ -51,7 +54,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(2); // [LYN-2281] Skinned mesh loading fixes
}
}
@@ -115,13 +118,13 @@ namespace AZ
}
// These variables are named using AssImp naming convention for consistency
unsigned int mNumPositionKeys{};
AZ::u32 mNumPositionKeys{};
aiVectorKey* mPositionKeys{};
unsigned int mNumRotationKeys{};
AZ::u32 mNumRotationKeys{};
aiQuatKey* mRotationKeys{};
unsigned int mNumScalingKeys{};
AZ::u32 mNumScalingKeys{};
aiVectorKey* mScalingKeys{};
AZStd::vector<aiVectorKey> m_ownedPositionKeys{};
@@ -156,7 +159,6 @@ namespace AZ
return AZStd::make_pair(animation, anim);
}
Events::ProcessingResult AssImpAnimationImporter::ImportAnimation(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Animation");
@@ -181,11 +183,11 @@ namespace AZ
// 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)
auto mapAnimationsFunc = [](AZ::u32 numChannels, auto** channels, const aiAnimation* animation, auto& map)
{
map.reserve(numChannels);
for (unsigned channelIndex = 0; channelIndex < numChannels; ++channelIndex)
for (AZ::u32 channelIndex = 0; channelIndex < numChannels; ++channelIndex)
{
auto* nodeAnim = channels[channelIndex];
AZStd::string name = GetName(nodeAnim);
@@ -194,13 +196,13 @@ namespace AZ
}
};
for (unsigned animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex)
for (AZ::u32 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)
for (AZ::u32 channelIndex = 0; channelIndex < animation->mNumMorphMeshChannels; ++channelIndex)
{
auto* nodeAnim = animation->mMorphMeshChannels[channelIndex];
AZStd::string name = GetName(nodeAnim);
@@ -280,7 +282,7 @@ namespace AZ
}
Events::ProcessingResultCombiner combinedAnimationResult;
for (unsigned meshIndex = 0; meshIndex < currentNode->mNumMeshes; ++meshIndex)
for (AZ::u32 meshIndex = 0; meshIndex < currentNode->mNumMeshes; ++meshIndex)
{
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[meshIndex]];
@@ -321,7 +323,7 @@ namespace AZ
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)
for (AZ::u32 time = 0; time <= animation->mDuration; ++time)
{
createdAnimationData->AddKeyFrame(localTransform);
}
@@ -408,15 +410,8 @@ namespace AZ
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)
auto sampleKeyFrame = [](const auto& keys, AZ::u32 numKeys, double time, AZ::u32& lastIndex)
{
AZ_Error("AnimationImporter", numKeys > 0, "Animation key set must have at least 1 key");
@@ -427,9 +422,10 @@ namespace AZ
auto returnValue = keys[0].mValue;
for (unsigned keyIndex = 0; keyIndex < numKeys; ++keyIndex)
for (AZ::u32 keyIndex = lastIndex; keyIndex < numKeys; ++keyIndex)
{
const auto& key = keys[keyIndex];
lastIndex = 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
@@ -437,7 +433,7 @@ namespace AZ
{
returnValue = key.mValue;
}
else if (key.mTime == time)
else if (AZ::IsClose(key.mTime, time))
{
return key.mValue;
}
@@ -450,16 +446,34 @@ namespace AZ
return returnValue;
};
// Resample the animations at a fixed time step. This matches the behaviour of
// the previous SDK used. Longer term, this could be data driven, or based on the
// smallest time step between key frames.
// AssImp has an animation->mTicksPerSecond and animation->mDuration, but those
// are less predictable than just using a fixed time step.
const double duration = animation->mDuration / animation->mTicksPerSecond;
AZ::u32 numKeyFrames = AZStd::max(AZStd::max(anim->mNumScalingKeys, anim->mNumPositionKeys), anim->mNumRotationKeys);
if (!AZ::IsClose(duration / s_defaultTimeStepSampleRate, numKeyFrames, 1))
{
double dT = duration / s_defaultTimeStepSampleRate;
numKeyFrames = AZStd::ceilf(dT) + 1; // +1 because the animation is from [0, duration] - we have a keyframe at the end of the duration which needs to be included
}
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)
createdAnimationData->ReserveKeyFrames(numKeyFrames);
createdAnimationData->SetTimeStepBetweenFrames(s_defaultTimeStepSampleRate);
AZ::u32 lastScaleIndex = 0;
AZ::u32 lastPositionIndex = 0;
AZ::u32 lastRotationIndex = 0;
for (AZ::u32 frame = 0; frame < numKeyFrames; ++frame)
{
auto scale = sampleKeyFrame(anim->mScalingKeys, anim->mNumScalingKeys, time);
auto position = sampleKeyFrame(anim->mPositionKeys, anim->mNumPositionKeys, time);
auto rotation = sampleKeyFrame(anim->mRotationKeys, anim->mNumRotationKeys, time);
double time = frame * s_defaultTimeStepSampleRate * animation->mTicksPerSecond;
aiVector3D scale = sampleKeyFrame(anim->mScalingKeys, anim->mNumScalingKeys, time, lastScaleIndex);
aiVector3D position = sampleKeyFrame(anim->mPositionKeys, anim->mNumPositionKeys, time, lastPositionIndex);
aiQuaternion rotation = sampleKeyFrame(anim->mRotationKeys, anim->mNumRotationKeys, time, lastRotationIndex);
aiMatrix4x4 transform(scale, rotation, position);
@@ -555,9 +569,9 @@ namespace AZ
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)
const AZ::u32 maxKeys = keys.size();
AZ::u32 keyIdx = 0;
for (AZ::u32 time = 0; time <= animation->mDuration; ++time)
{
if (keyIdx < maxKeys - 1 && time >= keys[keyIdx+1].m_time)
{
@@ -45,9 +45,10 @@ namespace AZ
const aiMeshMorphAnim* meshMorphAnim,
const aiMesh* mesh);
static const double s_defaultTimeStepSampleRate;
protected:
static const char* s_animationNodeName;
static const FbxSDKWrapper::FbxTimeWrapper::TimeMode s_defaultTimeMode;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -15,6 +15,7 @@
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
@@ -42,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(2); // LYN-2576
}
}
@@ -56,15 +57,13 @@ namespace AZ
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()))
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct bitangent stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
@@ -15,6 +15,7 @@
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
@@ -43,7 +44,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBlendShapeImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpBlendShapeImporter, SceneCore::LoadingComponent>()->Version(3); // LYN-2576
}
}
@@ -68,13 +69,24 @@ namespace AZ
return Events::ProcessingResult::Ignored;
}
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
int parentMeshIndex = parentMeshData->GetSdkMeshIndex();
Events::ProcessingResultCombiner combinedBlendShapeResult;
for (int meshIdx = 0; meshIdx < numMesh; meshIdx++)
for (int nodeMeshIdx = 0; nodeMeshIdx < numMesh; nodeMeshIdx++)
{
int meshId = context.m_sourceNode.GetAssImpNode()->mMeshes[meshIdx];
aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshId];
if (!aiMesh->mNumAnimMeshes)
int sceneMeshIdx = context.m_sourceNode.GetAssImpNode()->mMeshes[nodeMeshIdx];
const aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[sceneMeshIdx];
// Each mesh gets its own node in the scene graph, so only generate
// morph targets for the current mesh.
if (parentMeshIndex != nodeMeshIdx || !aiMesh->mNumAnimMeshes)
{
continue;
}
@@ -96,9 +108,22 @@ namespace AZ
int firstMeshVertexIndex = -1;
int previousMeshVertexIndex = -1;
int verticesInMeshFace = 0;
AZStd::bitset<SceneData::GraphData::BlendShapeData::MaxNumUVSets> uvSetUsedFlags;
for (AZ::u8 uvSetIndex = 0; uvSetIndex < SceneData::GraphData::BlendShapeData::MaxNumUVSets; ++uvSetIndex)
{
uvSetUsedFlags.set(uvSetIndex, aiAnimMesh->HasTextureCoords(uvSetIndex));
}
AZStd::bitset<SceneData::GraphData::BlendShapeData::MaxNumColorSets> colorSetUsedFlags;
for (AZ::u8 colorSetIndex = 0; colorSetIndex < SceneData::GraphData::BlendShapeData::MaxNumColorSets;
++colorSetIndex)
{
colorSetUsedFlags.set(colorSetIndex, aiAnimMesh->HasVertexColors(colorSetIndex));
}
blendShapeData->ReserveData(
aiAnimMesh->mNumVertices, aiAnimMesh->HasTangentsAndBitangents(), uvSetUsedFlags, colorSetUsedFlags);
for (int vertIdx = 0; vertIdx < aiAnimMesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mVertices[vertIdx]));
@@ -106,7 +131,7 @@ namespace AZ
context.m_sourceSceneSystem.SwapVec3ForUpAxis(vertex);
context.m_sourceSceneSystem.ConvertUnit(vertex);
// Add normals
AZ::Vector3 normal;
if (aiAnimMesh->HasNormals())
{
@@ -116,6 +141,39 @@ namespace AZ
}
blendShapeData->AddVertex(vertex, normal);
blendShapeData->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
// Add tangents and bitangents
if (aiAnimMesh->HasTangentsAndBitangents())
{
// Vector4's constructor that takes in a vector3 sets w to 1.0f automatically.
const AZ::Vector4 tangent(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mTangents[vertIdx]));
const AZ::Vector3 bitangent = AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mBitangents[vertIdx]);
blendShapeData->AddTangentAndBitangent(tangent, bitangent);
}
// Add UVs
for (AZ::u8 uvSetIdx = 0; uvSetIdx < SceneData::GraphData::BlendShapeData::MaxNumUVSets; ++uvSetIdx)
{
if (aiAnimMesh->HasTextureCoords(uvSetIdx))
{
const AZ::Vector2 vertexUV(
aiAnimMesh->mTextureCoords[uvSetIdx][vertIdx].x,
// The engine's V coordinate is reverse of how it's stored in assImp.
1.0f - aiAnimMesh->mTextureCoords[uvSetIdx][vertIdx].y);
blendShapeData->AddUV(vertexUV, uvSetIdx);
}
}
// Add colors
for (AZ::u8 colorSetIdx = 0; colorSetIdx < SceneData::GraphData::BlendShapeData::MaxNumColorSets; ++colorSetIdx)
{
if (aiAnimMesh->HasVertexColors(colorSetIdx))
{
SceneAPI::DataTypes::Color color =
AssImpSDKWrapper::AssImpTypeConverter::ToColor(aiAnimMesh->mColors[colorSetIdx][vertIdx]);
blendShapeData->AddColor(color, colorSetIdx);
}
}
}
// aiAnimMesh just has a list of positions for vertices. The face indices are on the original mesh.
@@ -15,6 +15,7 @@
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
@@ -42,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpColorStreamImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpColorStreamImporter, SceneCore::LoadingComponent>()->Version(2); // LYN-2576
}
}
@@ -56,15 +57,13 @@ namespace AZ
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()))
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct color stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
@@ -18,6 +18,7 @@
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
@@ -16,8 +16,10 @@
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
@@ -41,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpSkinWeightsImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpSkinWeightsImporter, SceneCore::LoadingComponent>()->Version(3); // LYN-2576
}
}
@@ -57,11 +59,29 @@ namespace AZ
return Events::ProcessingResult::Ignored;
}
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
int parentMeshIndex = parentMeshData->GetSdkMeshIndex();
Events::ProcessingResultCombiner combinedSkinWeightsResult;
for(unsigned m = 0; m < currentNode->mNumMeshes; ++m)
for(unsigned nodeMeshIndex = 0; nodeMeshIndex < currentNode->mNumMeshes; ++nodeMeshIndex)
{
auto mesh = scene->mMeshes[currentNode->mMeshes[m]];
if (nodeMeshIndex != parentMeshIndex)
{
// Only generate skinning data for the parent mesh.
// Each AssImp mesh is assigned to a unique node,
// so the skinning data should be generated as a child node
// for the associated parent mesh.
continue;
}
int sceneMeshIndex = currentNode->mMeshes[nodeMeshIndex];
const aiMesh* mesh = scene->mMeshes[sceneMeshIndex];
// Don't create this until a bone with weights is encountered
Containers::SceneGraph::NodeIndex weightsIndexForMesh;
@@ -80,7 +100,7 @@ namespace AZ
if (!weightsIndexForMesh.IsValid())
{
skinWeightName = s_skinWeightName;
skinWeightName += AZStd::to_string(m);
skinWeightName += AZStd::to_string(nodeMeshIndex);
RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
weightsIndexForMesh =
@@ -15,6 +15,7 @@
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
@@ -42,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpTangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpTangentStreamImporter, SceneCore::LoadingComponent>()->Version(2); // LYN-2576
}
}
@@ -56,15 +57,13 @@ namespace AZ
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()))
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct tangent stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
@@ -17,6 +17,7 @@
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
@@ -43,7 +44,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpUvMapImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpUvMapImporter, SceneCore::LoadingComponent>()->Version(2); // LYN-2576
}
}
@@ -57,16 +58,14 @@ namespace AZ
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()))
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData =
azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
int parentMeshIndex = parentMeshData->GetSdkMeshIndex();
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
@@ -15,9 +15,11 @@
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
namespace AZ::SceneAPI::FbxSceneBuilder
@@ -95,4 +97,34 @@ namespace AZ::SceneAPI::FbxSceneBuilder
return true;
}
GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context)
{
const DataTypes::IGraphObject* const parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition).get();
if (!parentData)
{
AZ_Error(Utilities::ErrorWindow, false,
"GetMeshDataFromParent failed because the parent was null, it should only be called with a valid parent node");
return AZ::Failure(Events::ProcessingResult::Failure);
}
if (!parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
// The parent node may contain bone information and not mesh information, skip it.
if (parentData->RTTI_IsTypeOf(SceneData::GraphData::BoneData::TYPEINFO_Uuid()))
{
// Return the ignore processing result in the failure.
return AZ::Failure(Events::ProcessingResult::Ignored);
}
AZ_Error(Utilities::ErrorWindow, false,
"Tried to get mesh data from parent for non-mesh parent data");
return AZ::Failure(Events::ProcessingResult::Failure);
}
const SceneData::GraphData::MeshData* const parentMeshData =
azrtti_cast<const SceneData::GraphData::MeshData* const>(parentData);
return AZ::Success(parentMeshData);
}
}
@@ -12,6 +12,8 @@
#pragma once
#include <SceneAPI/SceneCore/Events/ProcessingResult.h>
struct aiNode;
struct aiScene;
@@ -37,12 +39,16 @@ namespace AZ
{
class IGraphObject;
}
struct AssImpSceneNodeAppendedContext;
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);
typedef AZ::Outcome<const SceneData::GraphData::MeshData* const, Events::ProcessingResult> GetMeshDataFromParentResult;
GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context);
}
}
}
@@ -0,0 +1,100 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Math/Matrix3x4.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ICoordinateSystemRule.h>
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Utilities
{
DataTypes::MatrixType ConcatenateMatricesUpwards(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex nodeIndex)
{
DataTypes::MatrixType outTransform = DataTypes::MatrixType::Identity();
while (nodeIndex.IsValid())
{
auto view = Containers::Views::MakeSceneGraphChildView<Containers::Views::AcceptEndPointsOnly>(graph, nodeIndex, graph.GetContentStorage().begin(), true);
auto result = AZStd::find_if(view.begin(), view.end(), Containers::DerivedTypeFilter<DataTypes::ITransform>());
if (result != view.end())
{
// Check if the node has any child transform node
const DataTypes::MatrixType& azTransform = azrtti_cast<const DataTypes::ITransform*>(result->get())->GetMatrix();
outTransform = azTransform * outTransform;
}
else
{
// Check if the node itself is a transform node.
AZStd::shared_ptr<const DataTypes::ITransform> transformData = azrtti_cast<const DataTypes::ITransform*>(graph.GetNodeContent(nodeIndex));
if (transformData)
{
outTransform = transformData->GetMatrix() * outTransform;
}
}
if (graph.HasNodeParent(nodeIndex))
{
nodeIndex = graph.GetNodeParent(nodeIndex);
}
else
{
break;
}
}
return outTransform;
}
SCENE_CORE_API DataTypes::MatrixType DetermineWorldTransform(const Containers::Scene& scene, const Containers::SceneGraph::NodeIndex nodeIndex, const Containers::RuleContainer& ruleContainer)
{
auto coordinateSystemRule = ruleContainer.FindFirstByType<DataTypes::ICoordinateSystemRule>();
if (coordinateSystemRule && coordinateSystemRule->GetUseAdvancedData())
{
SceneAPI::DataTypes::MatrixType matrix = SceneAPI::DataTypes::MatrixType::CreateIdentity();
if (coordinateSystemRule->GetTranslation() != Vector3(0.0f, 0.0f, 0.0f) || !coordinateSystemRule->GetRotation().IsIdentity())
{
matrix = DataTypes::MatrixType::CreateFromQuaternionAndTranslation(coordinateSystemRule->GetRotation(), coordinateSystemRule->GetTranslation());
}
if (coordinateSystemRule->GetScale() != 1.0f)
{
float scale = coordinateSystemRule->GetScale();
matrix.MultiplyByScale(Vector3(scale, scale, scale));
}
if (!coordinateSystemRule->GetOriginNodeName().empty())
{
auto rootIndex = scene.GetGraph().Find(coordinateSystemRule->GetOriginNodeName());
if (rootIndex.IsValid())
{
auto worldMatrix = ConcatenateMatricesUpwards(scene.GetGraph(), rootIndex);
worldMatrix.InvertFull();
matrix *= worldMatrix;
}
}
return matrix;
}
return ConcatenateMatricesUpwards(scene.GetGraph(), nodeIndex);
}
} // Utilities
} // SceneAPI
} // AZ
@@ -0,0 +1,35 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class Scene;
class RuleContainer;
}
namespace Utilities
{
SCENE_CORE_API DataTypes::MatrixType DetermineWorldTransform(
const Containers::Scene& scene,
const Containers::SceneGraph::NodeIndex nodeIndex,
const Containers::RuleContainer& ruleContainer);
} // Utilities
} // SceneAPI
} // AZ
@@ -125,7 +125,7 @@ namespace AZ
template<typename Iterator, typename Traversal>
void SceneGraphDownwardsIterator<Iterator, Traversal>::IgnoreNodeDescendants()
{
m_ignoreDescendants = true;
m_ignoreDescendants = -1;
}
template<typename Iterator, typename Traversal>
@@ -43,5 +43,12 @@ namespace AZ::SceneAPI::DataTypes
virtual CoordinateSystem GetTargetCoordinateSystem() const = 0;
virtual const CoordinateSystemConverter& GetCoordinateSystemConverter() const = 0;
// advanced coordinate settings
virtual bool GetUseAdvancedData() const = 0;
virtual const AZStd::string& GetOriginNodeName() const = 0;
virtual const Quaternion& GetRotation() const = 0;
virtual const Vector3& GetTranslation() const = 0;
virtual float GetScale() const = 0;
};
} // namespace AZ::SceneAPI::DataTypes
@@ -144,6 +144,7 @@ namespace AZ
if (context && (context->IsRemovingReflection() || !context->FindClassData(AZ::SceneAPI::DataTypes::IGroup::TYPEINFO_Uuid())))
{
AZ::SceneAPI::DataTypes::IManifestObject::Reflect(context);
AZ::SceneAPI::Events::CallProcessorBinder::Reflect(context);
// Register components
AZ::SceneAPI::SceneCore::BehaviorComponent::Reflect(context);
AZ::SceneAPI::SceneCore::LoadingComponent::Reflect(context);
@@ -10,6 +10,7 @@
*
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBinder.h>
namespace AZ
@@ -48,6 +49,14 @@ namespace AZ
m_bindings.clear();
}
void CallProcessorBinder::Reflect(AZ::ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<CallProcessorBinder>()->Version(1);
}
}
} // namespace Events
} // namespace SceneAPI
} // namespace AZ
@@ -20,6 +20,8 @@
namespace AZ
{
class ReflectContext;
namespace SceneAPI
{
namespace Events
@@ -55,6 +57,8 @@ namespace AZ
CallProcessorBinder() = default;
SCENE_CORE_API virtual ~CallProcessorBinder();
static void Reflect(AZ::ReflectContext* context);
protected:
CallProcessorBinder(const CallProcessorBinder&) = delete;
@@ -133,4 +137,4 @@ namespace AZ
} // namespace SceneAPI
} // namespace AZ
#include <SceneAPI/SceneCore/Events/CallProcessorBinder.inl>
#include <SceneAPI/SceneCore/Events/CallProcessorBinder.inl>
@@ -94,6 +94,8 @@ set(FILES
Containers/Utilities/ProxyPointer.inl
Containers/Utilities/Filters.h
Containers/Utilities/Filters.inl
Containers/Utilities/SceneUtilities.h
Containers/Utilities/SceneUtilities.cpp
Containers/Utilities/SceneGraphUtilities.h
Containers/Utilities/SceneGraphUtilities.inl
Containers/Utilities/SceneGraphUtilities.cpp
@@ -53,19 +53,19 @@ namespace AZ
////////////////////////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorPythonConsoleNotifications
void OnTraceMessage(AZStd::string_view message) override
void OnTraceMessage([[maybe_unused]] 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
void OnErrorMessage([[maybe_unused]] 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
void OnExceptionMessage([[maybe_unused]] AZStd::string_view message) override
{
using namespace AZ::SceneAPI::Utilities;
AZ_TracePrintf(ErrorWindow, "[EXCEPTION] %.*s \n", AZ_STRING_ARG(message));
@@ -30,6 +30,61 @@ namespace AZ
return static_cast<unsigned int>(m_positions.size()-1);
}
void BlendShapeData::AddTangentAndBitangent(const Vector4& tangent, const Vector3& bitangent)
{
m_tangents.push_back(tangent);
m_bitangents.push_back(bitangent);
}
void BlendShapeData::AddUV(const Vector2& uv, AZ::u8 uvSetIndex)
{
if (uvSetIndex >= MaxNumUVSets)
{
AZ_ErrorOnce("SceneGraphData", false, "uvSetIndex %zu is greater or equal than the maximum uv sets %zu.", uvSetIndex, MaxNumUVSets);
return;
}
m_uvs[uvSetIndex].push_back(uv);
}
void BlendShapeData::AddColor(const SceneAPI::DataTypes::Color& color, AZ::u8 colorSetIndex)
{
if (colorSetIndex >= MaxNumColorSets)
{
AZ_ErrorOnce("SceneGraphData", false, "colorSetIndex %zu is greater or equal than the maximum color sets %zu.", colorSetIndex, MaxNumColorSets);
return;
}
m_colors[colorSetIndex].push_back(color);
}
void BlendShapeData::ReserveData(
unsigned int numVertices, bool reserveTangents, const AZStd::bitset<MaxNumUVSets>& uvSetUsedFlags,
const AZStd::bitset<MaxNumColorSets>& colorSetUsedFlags)
{
m_positions.reserve(numVertices);
m_normals.reserve(numVertices);
if (reserveTangents)
{
m_tangents.reserve(numVertices);
m_bitangents.reserve(numVertices);
}
for (AZ::u8 uvSetIndex = 0; uvSetIndex < MaxNumUVSets; ++uvSetIndex)
{
if (uvSetUsedFlags[uvSetIndex])
{
m_uvs[uvSetIndex].reserve(numVertices);
}
}
for (AZ::u8 colorSetIndex = 0; colorSetIndex < MaxNumColorSets; ++colorSetIndex)
{
if (colorSetUsedFlags[colorSetIndex])
{
m_colors[colorSetIndex].reserve(numVertices);
}
}
}
void BlendShapeData::AddFace(const Face& face)
{
m_faces.push_back(face);
@@ -47,7 +102,7 @@ namespace AZ
int BlendShapeData::GetControlPointIndex(int vertexIndex) const
{
auto iter = m_vertexIndexToControlPointIndexMap.find(vertexIndex);
AZ_Assert(iter != m_vertexIndexToControlPointIndexMap.end(), "Vertex index %i doesn't exist", vertexIndex);
AZ_Assert(iter != m_vertexIndexToControlPointIndexMap.end(), "Vertex index %i doesn't exist.", vertexIndex);
// Note: AZStd::unordered_map's operator [] doesn't have const version...
return iter->second;
}
@@ -92,6 +147,45 @@ namespace AZ
return m_normals[index];
}
const Vector2& BlendShapeData::GetUV(unsigned int vertexIndex, unsigned int uvSetIndex) const
{
AZ_Assert(uvSetIndex < MaxNumUVSets, "uvSet index out of range");
AZ_Assert(vertexIndex < m_uvs[uvSetIndex].size(), "uvSet index out of range");
return m_uvs[uvSetIndex][vertexIndex];
}
AZStd::vector<Vector4>& BlendShapeData::GetTangents()
{
return m_tangents;
}
const AZStd::vector<Vector4>& BlendShapeData::GetTangents() const
{
return m_tangents;
}
AZStd::vector<Vector3>& BlendShapeData::GetBitangents()
{
return m_bitangents;
}
const AZStd::vector<Vector3>& BlendShapeData::GetBitangents() const
{
return m_bitangents;
}
const AZStd::vector<Vector2>& BlendShapeData::GetUVs(AZ::u8 uvSetIndex) const
{
AZ_Assert(uvSetIndex < MaxNumUVSets, "uvSet index out of range");
return m_uvs[uvSetIndex];
}
const AZStd::vector<SceneAPI::DataTypes::Color>& BlendShapeData::GetColors(AZ::u8 colorSetIndex) const
{
AZ_Assert(colorSetIndex < MaxNumColorSets, "colorSet index out of range");
return m_colors[colorSetIndex];
}
unsigned int BlendShapeData::GetFaceVertexIndex(unsigned int face, unsigned int vertexIndex) const
{
AZ_Assert(face < m_faces.size(), "GetFaceVertexPositionIndex face index not in range");
@@ -16,6 +16,7 @@
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneData/SceneDataConfiguration.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexColorData.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBlendShapeData.h>
namespace AZ
@@ -30,8 +31,19 @@ namespace AZ
public:
AZ_RTTI(BlendShapeData, "{FF875C22-2E4F-4CE3-BA49-09BF78C70A09}", SceneAPI::DataTypes::IBlendShapeData)
// Maximum number of color sets matches limitation set in assImp (AI_MAX_NUMBER_OF_COLOR_SETS)
static constexpr AZ::u8 MaxNumColorSets = 8;
// Maximum number of uv sets matches limitation set in assImp (AI_MAX_NUMBER_OF_TEXTURECOORDS)
static constexpr AZ::u8 MaxNumUVSets = 8;
SCENE_DATA_API ~BlendShapeData() override;
SCENE_DATA_API virtual unsigned int AddVertex(const Vector3& position, const Vector3& normal);
SCENE_DATA_API void AddTangentAndBitangent(const Vector4& tangent, const Vector3& bitangent);
SCENE_DATA_API void AddUV(const Vector2& uv, AZ::u8 uvSetIndex);
SCENE_DATA_API void AddColor(const SceneAPI::DataTypes::Color& color, AZ::u8 colorSetIndex);
SCENE_DATA_API void ReserveData(
unsigned int numVertices, bool reserveTangents, const AZStd::bitset<MaxNumUVSets>& uvSetUsedFlags,
const AZStd::bitset<MaxNumColorSets>& colorSetUsedFlags);
//assume consistent winding - no stripping or fanning expected (3 index per face)
SCENE_DATA_API virtual void AddFace(const Face& face);
@@ -48,6 +60,14 @@ namespace AZ
SCENE_DATA_API const Vector3& GetPosition(unsigned int index) const override;
SCENE_DATA_API const Vector3& GetNormal(unsigned int index) const override;
SCENE_DATA_API const Vector2& GetUV(unsigned int vertexIndex, unsigned int uvSetIndex) const;
SCENE_DATA_API AZStd::vector<Vector4>& GetTangents();
SCENE_DATA_API const AZStd::vector<Vector4>& GetTangents() const;
SCENE_DATA_API AZStd::vector<Vector3>& GetBitangents();
SCENE_DATA_API const AZStd::vector<Vector3>& GetBitangents() const;
SCENE_DATA_API const AZStd::vector<Vector2>& GetUVs(AZ::u8 uvSetIndex) const;
SCENE_DATA_API const AZStd::vector<SceneAPI::DataTypes::Color>& GetColors(AZ::u8 colorSetIndex) const;
SCENE_DATA_API unsigned int GetFaceVertexIndex(unsigned int face, unsigned int vertexIndex) const override;
@@ -56,6 +76,11 @@ namespace AZ
protected:
AZStd::vector<Vector3> m_positions;
AZStd::vector<Vector3> m_normals;
AZStd::vector<Vector4> m_tangents;
AZStd::vector<Vector3> m_bitangents;
AZStd::vector<AZ::Vector2> m_uvs[MaxNumUVSets];
AZStd::vector<SceneAPI::DataTypes::Color> m_colors[MaxNumColorSets];
AZStd::vector<Face> m_faces;
AZStd::unordered_map<int, int> m_vertexIndexToControlPointIndexMap;
@@ -30,49 +30,56 @@ namespace AZ::SceneAPI::SceneData
void CoordinateSystemRule::UpdateCoordinateSystemConverter()
{
switch (m_targetCoordinateSystem)
if (m_useAdvancedData)
{
case ZUpPositiveYForward:
m_coordinateSystemConverter = {};
}
else
{
switch (m_targetCoordinateSystem)
{
// Source coordinate system, use identity for now, which will currently just assume LY's coordinate system.
const AZ::Vector3 sourceBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
case ZUpPositiveYForward:
{
// Source coordinate system, use identity for now, which will currently just assume LY's coordinate system.
const AZ::Vector3 sourceBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// The target coordinate system, with X and Y inverted (rotate 180 degrees over Z)
const AZ::Vector3 targetBasisVectors[3] = { AZ::Vector3(-1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f,-1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// The target coordinate system, with X and Y inverted (rotate 180 degrees over Z)
const AZ::Vector3 targetBasisVectors[3] = { AZ::Vector3(-1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f,-1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// X, Y and Z are all at the same indices inside the target coordinate system, compared to the source coordinate system.
const AZ::u32 targetBasisIndices[3] = { 0, 1, 2 };
// X, Y and Z are all at the same indices inside the target coordinate system, compared to the source coordinate system.
const AZ::u32 targetBasisIndices[3] = { 0, 1, 2 };
m_coordinateSystemConverter = CoordinateSystemConverter::CreateFromBasisVectors(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
break;
m_coordinateSystemConverter = CoordinateSystemConverter::CreateFromBasisVectors(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
break;
case ZUpNegativeYForward:
{
// Source coordinate system, use identity for now, which will currently just assume LY's coordinate system.
const AZ::Vector3 sourceBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
case ZUpNegativeYForward:
{
// Source coordinate system, use identity for now, which will currently just assume LY's coordinate system.
const AZ::Vector3 sourceBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// The target coordinate system, which is the same as the source, so basically we won't do anything here.
const AZ::Vector3 targetBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// The target coordinate system, which is the same as the source, so basically we won't do anything here.
const AZ::Vector3 targetBasisVectors[3] = { AZ::Vector3( 1.0f, 0.0f, 0.0f),
AZ::Vector3( 0.0f, 1.0f, 0.0f),
AZ::Vector3( 0.0f, 0.0f, 1.0f) };
// X, Y and Z are all at the same indices inside the target coordinate system, compared to the source coordinate system.
const AZ::u32 targetBasisIndices[3] = { 0, 1, 2 };
// X, Y and Z are all at the same indices inside the target coordinate system, compared to the source coordinate system.
const AZ::u32 targetBasisIndices[3] = { 0, 1, 2 };
m_coordinateSystemConverter = CoordinateSystemConverter::CreateFromBasisVectors(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
break;
m_coordinateSystemConverter = CoordinateSystemConverter::CreateFromBasisVectors(sourceBasisVectors, targetBasisVectors, targetBasisIndices);
}
break;
default:
AZ_Assert(false, "Unsupported coordinate system conversion");
};
default:
AZ_Assert(false, "Unsupported coordinate system conversion");
};
}
}
void CoordinateSystemRule::SetTargetCoordinateSystem(CoordinateSystem targetCoordinateSystem)
@@ -94,22 +101,74 @@ namespace AZ::SceneAPI::SceneData
return;
}
serializeContext->Class<CoordinateSystemRule, IRule>()->Version(1)
->Field("targetCoordinateSystem", &CoordinateSystemRule::m_targetCoordinateSystem);
serializeContext->Class<CoordinateSystemRule, IRule>()->Version(2) // LYN-2442
->Field("targetCoordinateSystem", &CoordinateSystemRule::m_targetCoordinateSystem)
->Field("useAdvancedData", &CoordinateSystemRule::m_useAdvancedData)
->Field("originNodeName", &CoordinateSystemRule::m_originNodeName)
->Field("rotation", &CoordinateSystemRule::m_rotation)
->Field("translation", &CoordinateSystemRule::m_translation)
->Field("scale", &CoordinateSystemRule::m_scale);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<CoordinateSystemRule>("Coordinate system change", "Modify the target coordinate system, applying a transformation to all data (transforms and vertex data if it exists).")
editContext->Class<CoordinateSystemRule>("Coordinate system change",
"Modify the target coordinate system, applying a transformation to all data (transforms and vertex data if it exists).")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->DataElement(AZ::Edit::UIHandlers::ComboBox, &CoordinateSystemRule::m_targetCoordinateSystem, "Facing direction", "Change the direction the actor/motion will face by applying a post transformation to the data.")
->DataElement(AZ::Edit::UIHandlers::Default, &CoordinateSystemRule::m_useAdvancedData,
"Use Advanced Settings",
"Toggles on the advanced settings for transforming the mesh group.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &CoordinateSystemRule::m_targetCoordinateSystem,
"Facing direction",
"Change the direction the actor/motion will face by applying a post transformation to the data.")
->EnumAttribute(CoordinateSystem::ZUpNegativeYForward, "Do nothing")
->EnumAttribute(CoordinateSystem::ZUpPositiveYForward, "Rotate 180 degrees around the up axis");
->EnumAttribute(CoordinateSystem::ZUpPositiveYForward, "Rotate 180 degrees around the up axis")
->Attribute(AZ::Edit::Attributes::Visibility, &CoordinateSystemRule::GetBasicVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement("NodeListSelection", &CoordinateSystemRule::m_originNodeName,
"Relative Origin Node",
"Select a Node from the scene as the origin for this export.")
->Attribute("DisabledOption", "")
->Attribute("DefaultToDisabled", false)
->Attribute("ExcludeEndPoints", true)
->Attribute(AZ::Edit::Attributes::Visibility, &CoordinateSystemRule::GetAdvancedVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
->DataElement(AZ::Edit::UIHandlers::Default, &CoordinateSystemRule::m_translation,
"Translation",
"Moves the group along the given vector.")
->Attribute(AZ::Edit::Attributes::Visibility, &CoordinateSystemRule::GetAdvancedVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &CoordinateSystemRule::m_rotation,
"Rotation",
"Sets the orientation offset of the processed mesh in degrees. Rotates the group after translation.")
->Attribute(Edit::Attributes::LabelForX, "P")
->Attribute(Edit::Attributes::LabelForY, "R")
->Attribute(Edit::Attributes::LabelForZ, "Y")
->Attribute(AZ::Edit::Attributes::Visibility, &CoordinateSystemRule::GetAdvancedVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
->DataElement(AZ::Edit::UIHandlers::Default, &CoordinateSystemRule::m_scale,
"Scale",
"Sets the scale offset of the processed mesh.")
->Attribute(Edit::Attributes::Min, 0.0001)
->Attribute(Edit::Attributes::Max, 1000.0)
->Attribute(AZ::Edit::Attributes::Visibility, &CoordinateSystemRule::GetAdvancedVisibility)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues);
}
}
AZ::Crc32 CoordinateSystemRule::GetBasicVisibility() const
{
return (m_useAdvancedData) ? AZ::Edit::PropertyVisibility::Hide : AZ::Edit::PropertyVisibility::Show;
}
AZ::Crc32 CoordinateSystemRule::GetAdvancedVisibility() const
{
return (m_useAdvancedData) ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
}
bool CoordinateSystemRule::ConvertLegacyCoordinateSystemRule(AZ::SerializeContext& serializeContext,
AZ::SerializeContext::DataElementNode& classElement)
{
@@ -155,4 +214,54 @@ namespace AZ::SceneAPI::SceneData
return true;
}
bool CoordinateSystemRule::GetUseAdvancedData() const
{
return m_useAdvancedData;
}
void CoordinateSystemRule::SetUseAdvancedData(bool useAdvancedData)
{
m_useAdvancedData = useAdvancedData;
}
const AZStd::string& CoordinateSystemRule::GetOriginNodeName() const
{
return m_originNodeName;
}
void CoordinateSystemRule::SetOriginNodeName(const AZStd::string& originNodeName)
{
m_originNodeName = originNodeName;
}
const Quaternion& CoordinateSystemRule::GetRotation() const
{
return m_rotation;
}
void CoordinateSystemRule::SetRotation(const Quaternion& rotation)
{
m_rotation = rotation;
}
const Vector3& CoordinateSystemRule::GetTranslation() const
{
return m_translation;
}
void CoordinateSystemRule::SetTranslation(const Vector3& translation)
{
m_translation = translation;
}
float CoordinateSystemRule::GetScale() const
{
return m_scale;
}
void CoordinateSystemRule::SetScale(float scale)
{
m_scale = scale;
}
} // namespace AZ::SceneAPI::SceneData
@@ -39,12 +39,34 @@ namespace AZ::SceneAPI::SceneData
SCENE_DATA_API const CoordinateSystemConverter& GetCoordinateSystemConverter() const override { return m_coordinateSystemConverter; }
static void Reflect(AZ::ReflectContext* context);
SCENE_DATA_API static void Reflect(AZ::ReflectContext* context);
SCENE_DATA_API static bool ConvertLegacyCoordinateSystemRule(AZ::SerializeContext& serializeContext,
AZ::SerializeContext::DataElementNode& classElement);
// advanced coordinate settings
SCENE_DATA_API bool GetUseAdvancedData() const override;
SCENE_DATA_API void SetUseAdvancedData(bool useAdvancedData);
SCENE_DATA_API const AZStd::string& GetOriginNodeName() const override;
SCENE_DATA_API void SetOriginNodeName(const AZStd::string& originNodeName);
SCENE_DATA_API const Quaternion& GetRotation() const override;
SCENE_DATA_API void SetRotation(const Quaternion& rotation);
SCENE_DATA_API const Vector3& GetTranslation() const override;
SCENE_DATA_API void SetTranslation(const Vector3& translation);
SCENE_DATA_API float GetScale() const override;
SCENE_DATA_API void SetScale(float scale);
protected:
AZ::Crc32 GetBasicVisibility() const;
AZ::Crc32 GetAdvancedVisibility() const;
CoordinateSystemConverter m_coordinateSystemConverter;
CoordinateSystem m_targetCoordinateSystem;
// advanced coordinate settings
bool m_useAdvancedData = false;
AZStd::string m_originNodeName;
AZ::Quaternion m_rotation = AZ::Quaternion::CreateIdentity();
AZ::Vector3 m_translation = AZ::Vector3::CreateZero();
float m_scale = 1.0f;
};
} // namespace AZ::SceneAPI::SceneData
@@ -14,7 +14,7 @@
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneData/ReflectionRegistrar.h>
#include <SceneAPI/SceneData/Rules/CommentRule.h>
#include <SceneAPI/SceneData/Rules/CoordinateSystemRule.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/RTTI/BehaviorContext.h>
@@ -87,6 +87,7 @@ namespace AZ
AZ::SceneAPI::RegisterDataTypeReflection(m_serializeContext.get());
AZ::SceneAPI::Containers::SceneManifest::Reflect(m_serializeContext.get());
AZ::SceneAPI::DataTypes::IManifestObject::Reflect(m_serializeContext.get());
m_serializeContext->Class<AZ::SceneAPI::DataTypes::IRule, AZ::SceneAPI::DataTypes::IManifestObject>()->Version(1);
AZ::SceneAPI::MockRotationRule::Reflect(m_serializeContext.get());
m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
@@ -174,5 +175,53 @@ namespace AZ
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.27)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.65)"));
}
TEST_F(SceneManifest_JSON, LoadFromString_CoordinateSystemRule_ReturnsTrue)
{
AZ::SceneAPI::SceneData::CoordinateSystemRule foo;
EXPECT_FALSE(foo.GetUseAdvancedData());
using namespace SceneAPI::Containers;
constexpr const char* jsonCoordinateSystemRule = { R"JSON(
{
"values": [
{
"$type": "CoordinateSystemRule",
"useAdvancedData": true,
"originNodeName": "test_origin_name",
"translation": [1.0, 2.0, 3.0],
"rotation": { "yaw" : 45.0, "pitch" : 18.5, "roll" : 215.0 },
"scale": 10.0
}
]
})JSON" };
SceneManifest loaded;
auto loadFromStringResult = loaded.LoadFromString(jsonCoordinateSystemRule, m_serializeContext.get(), m_jsonRegistrationContext.get());
EXPECT_TRUE(loadFromStringResult.IsSuccess());
EXPECT_FALSE(loaded.IsEmpty());
auto writeToJsonResult =
SceneManifestContainer::SaveToJsonDocumentHelper(loaded, m_serializeContext.get(), m_jsonRegistrationContext.get());
ASSERT_TRUE(writeToJsonResult.IsSuccess());
AZStd::string jsonText;
auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText);
ASSERT_TRUE(writeToStringResult.IsSuccess());
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("$type": "CoordinateSystemRule")"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("useAdvancedData": true,)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("originNodeName": "test_origin_name",)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("rotation": [)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.028)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(-0.40)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(0.85)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(-0.33)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("translation": [)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(1.0)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(2.0)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"(3.0)"));
EXPECT_THAT(jsonText.c_str(), ::testing::HasSubstr(R"("scale": 10.0)"));
}
}
}