Helios - LYN-3250 - Fixed morph targets for meshes that had multiple … (#696)

* Helios - LYN-3250 - Fixed morph targets for meshes that had multiple materials (#374)

Fixed morph targets for meshes that had multiple materials and were split by AssImp: Recombined them into one mesh in the O3DE scene graph, so the behavior would match FBX SDK.
This commit is contained in:
AMZN-stankowi
2021-05-19 13:02:31 -07:00
committed by GitHub
parent 25e811ff6c
commit f779821ac0
25 changed files with 457 additions and 281 deletions
@@ -25,7 +25,6 @@
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
@@ -44,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(2); // LYN-2576
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(3); // LYN-3250
}
}
@@ -55,62 +54,79 @@ namespace AZ
{
return Events::ProcessingResult::Ignored;
}
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
if (!meshDataResult.IsSuccess())
const auto meshHasTangentsAndBitangents = [&scene](const unsigned int meshIndex)
{
return meshDataResult.GetError();
}
const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
return scene->mMeshes[meshIndex]->HasTangentsAndBitangents();
};
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())
// If there are no bitangents on any meshes, there's nothing to import in this function.
const bool anyMeshHasTangentsAndBitangents = AZStd::any_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
if (!anyMeshHasTangentsAndBitangents)
{
return Events::ProcessingResult::Ignored;
}
// AssImp nodes with multiple meshes on them occur when AssImp split a mesh on material.
// This logic recombines those meshes to minimize the changes needed to replace FBX SDK with AssImp, FBX SDK did not separate meshes,
// and the engine has code to do this later.
const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
if (!allMeshesHaveTangentsAndBitangents)
{
const char* mixedBitangentsError =
"Node with name %s has meshes with and without bitangents. "
"Placeholder incorrect bitangents will be generated to allow the data to process, "
"but the source art needs to be fixed to correct this. Either apply bitangents to all meshes on this node, "
"or remove all bitangents from all meshes on this node.";
AZ_Error(
Utilities::ErrorWindow, false, mixedBitangentsError, currentNode->mName.C_Str());
}
const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
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)
for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
{
const Vector3 bitangent(
AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
bitangentStream->AppendBitangent(bitangent);
const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
for (int v = 0; v < mesh->mNumVertices; ++v)
{
if (!mesh->HasTangentsAndBitangents())
{
// This node has mixed meshes with and without bitangents.
// An error was already thrown above. Output stub bitangents so
// the mesh can still be output in some form, even if the data isn't correct.
// The bitangent count needs to match the vertex count on the associated mesh node.
bitangentStream->AppendBitangent(Vector3::CreateAxisY());
}
else
{
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());
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
Events::ProcessingResult bitangentResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, nodeName.c_str());
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, m_defaultNodeName);
bitangentResults = Events::Process(dataPopulated);
if (bitangentResults != Events::ProcessingResult::Failure)
{
bitangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
return bitangentResults;
}