AssImpBitangentStreamImporter.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Serialization/SerializeContext.h>
  9. #include <AzCore/std/smart_ptr/make_shared.h>
  10. #include <AzToolsFramework/Debug/TraceContext.h>
  11. #include <SceneAPI/SceneBuilder/Importers/AssImpBitangentStreamImporter.h>
  12. #include <SceneAPI/SceneBuilder/Importers/ImporterUtilities.h>
  13. #include <SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
  14. #include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
  15. #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
  16. #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
  17. #include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
  18. #include <SceneAPI/SceneData/GraphData/MeshData.h>
  19. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  20. #include <assimp/scene.h>
  21. #include <assimp/mesh.h>
  22. namespace AZ
  23. {
  24. namespace SceneAPI
  25. {
  26. namespace SceneBuilder
  27. {
  28. const char* AssImpBitangentStreamImporter::m_defaultNodeName = "Bitangent";
  29. AssImpBitangentStreamImporter::AssImpBitangentStreamImporter()
  30. {
  31. BindToCall(&AssImpBitangentStreamImporter::ImportBitangentStreams);
  32. }
  33. void AssImpBitangentStreamImporter::Reflect(ReflectContext* context)
  34. {
  35. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
  36. if (serializeContext)
  37. {
  38. serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(3); // LYN-3250
  39. }
  40. }
  41. Events::ProcessingResult AssImpBitangentStreamImporter::ImportBitangentStreams(AssImpSceneNodeAppendedContext& context)
  42. {
  43. AZ_TraceContext("Importer", m_defaultNodeName);
  44. if (!context.m_sourceNode.ContainsMesh())
  45. {
  46. return Events::ProcessingResult::Ignored;
  47. }
  48. const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
  49. const aiScene* scene = context.m_sourceScene.GetAssImpScene();
  50. const auto meshHasTangentsAndBitangents = [&scene](const unsigned int meshIndex)
  51. {
  52. return scene->mMeshes[meshIndex]->HasTangentsAndBitangents();
  53. };
  54. // If there are no bitangents on any meshes, there's nothing to import in this function.
  55. const bool anyMeshHasTangentsAndBitangents = AZStd::any_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
  56. if (!anyMeshHasTangentsAndBitangents)
  57. {
  58. return Events::ProcessingResult::Ignored;
  59. }
  60. // AssImp nodes with multiple meshes on them occur when AssImp split a mesh on material.
  61. // This logic recombines those meshes to minimize the changes needed to replace FBX SDK with AssImp, FBX SDK did not separate meshes,
  62. // and the engine has code to do this later.
  63. const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
  64. if (!allMeshesHaveTangentsAndBitangents)
  65. {
  66. AZ_Error(
  67. Utilities::ErrorWindow, false,
  68. "Node with name %s has meshes with and without bitangents. "
  69. "Placeholder incorrect bitangents will be generated to allow the data to process, "
  70. "but the source art needs to be fixed to correct this. Either apply bitangents to all meshes on this node, "
  71. "or remove all bitangents from all meshes on this node.",
  72. currentNode->mName.C_Str());
  73. }
  74. const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
  75. AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> bitangentStream =
  76. AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexBitangentData>();
  77. // AssImp only has one bitangentStream per mesh.
  78. bitangentStream->SetBitangentSetIndex(0);
  79. bitangentStream->SetGenerationMethod(AZ::SceneAPI::DataTypes::TangentGenerationMethod::FromSourceScene);
  80. bitangentStream->ReserveContainerSpace(vertexCount);
  81. for (unsigned int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
  82. {
  83. const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
  84. for (unsigned int v = 0; v < mesh->mNumVertices; ++v)
  85. {
  86. if (!mesh->HasTangentsAndBitangents())
  87. {
  88. // This node has mixed meshes with and without bitangents.
  89. // An error was already thrown above. Output stub bitangents so
  90. // the mesh can still be output in some form, even if the data isn't correct.
  91. // The bitangent count needs to match the vertex count on the associated mesh node.
  92. bitangentStream->AppendBitangent(Vector3::CreateAxisY());
  93. }
  94. else
  95. {
  96. const Vector3 bitangent(
  97. AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
  98. bitangentStream->AppendBitangent(bitangent);
  99. }
  100. }
  101. }
  102. Containers::SceneGraph::NodeIndex newIndex =
  103. context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
  104. Events::ProcessingResult bitangentResults;
  105. AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, m_defaultNodeName);
  106. bitangentResults = Events::Process(dataPopulated);
  107. if (bitangentResults != Events::ProcessingResult::Failure)
  108. {
  109. bitangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
  110. }
  111. return bitangentResults;
  112. }
  113. } // namespace SceneBuilder
  114. } // namespace SceneAPI
  115. } // namespace AZ