AssImpMeshImporterUtilities.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 <assimp/mesh.h>
  9. #include <assimp/scene.h>
  10. #include <AzCore/Casting/numeric_cast.h>
  11. #include <AzCore/std/numeric.h>
  12. #include <AzCore/std/smart_ptr/make_shared.h>
  13. #include <SceneAPI/SceneBuilder/SceneSystem.h>
  14. #include <SceneAPI/SceneBuilder/ImportContexts/AssImpImportContexts.h>
  15. #include <SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
  16. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  17. #include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
  18. #include <SceneAPI/SceneData/GraphData/BoneData.h>
  19. #include <SceneAPI/SceneData/GraphData/MeshData.h>
  20. namespace AZ::SceneAPI::SceneBuilder
  21. {
  22. bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const SceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
  23. const AZStd::function<AZStd::shared_ptr<AZ::SceneData::GraphData::MeshData>()>& makeMeshFunc)
  24. {
  25. AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
  26. int lyMeshIndex = 0;
  27. if(!currentNode || !scene)
  28. {
  29. return false;
  30. }
  31. auto newMesh = makeMeshFunc();
  32. newMesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
  33. newMesh->SetOriginalUnitSizeInMeters(sceneSystem.GetOriginalUnitSizeInMeters());
  34. // AssImp separates meshes that have multiple materials.
  35. // This code re-combines them to match previous FBX SDK behavior,
  36. // so they can be separated by engine code instead.
  37. int vertOffset = 0;
  38. for (unsigned int m = 0; m < currentNode->mNumMeshes; ++m)
  39. {
  40. const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
  41. // Lumberyard materials are created in order based on mesh references in the scene
  42. if (assImpMatIndexToLYIndex.find(mesh->mMaterialIndex) == assImpMatIndexToLYIndex.end())
  43. {
  44. assImpMatIndexToLYIndex.insert(AZStd::pair<int, int>(mesh->mMaterialIndex, lyMeshIndex++));
  45. }
  46. for (unsigned int vertIdx = 0; vertIdx < mesh->mNumVertices; ++vertIdx)
  47. {
  48. AZ::Vector3 vertex(mesh->mVertices[vertIdx].x, mesh->mVertices[vertIdx].y, mesh->mVertices[vertIdx].z);
  49. sceneSystem.SwapVec3ForUpAxis(vertex);
  50. sceneSystem.ConvertUnit(vertex);
  51. newMesh->AddPosition(vertex);
  52. newMesh->SetVertexIndexToControlPointIndexMap(vertIdx + vertOffset, vertIdx + vertOffset);
  53. if (mesh->HasNormals())
  54. {
  55. AZ::Vector3 normal(mesh->mNormals[vertIdx].x, mesh->mNormals[vertIdx].y, mesh->mNormals[vertIdx].z);
  56. sceneSystem.SwapVec3ForUpAxis(normal);
  57. normal.NormalizeSafe();
  58. newMesh->AddNormal(normal);
  59. }
  60. }
  61. // Only print one warning per mesh if it has the wrong number of vertices.
  62. [[maybe_unused]] bool warningPrinted = false;
  63. for (unsigned int faceIdx = 0; faceIdx < mesh->mNumFaces; ++faceIdx)
  64. {
  65. aiFace face = mesh->mFaces[faceIdx];
  66. AZ::SceneAPI::DataTypes::IMeshData::Face meshFace;
  67. // Only faces with exactly 3 indices are supported, since the engine only supports triangles.
  68. if (face.mNumIndices != 3)
  69. {
  70. AZ_Warning(Utilities::ErrorWindow, warningPrinted,
  71. "Mesh on node %s has a face with %d vertices and will be ignored. %s",
  72. currentNode->mName.C_Str(),
  73. face.mNumIndices,
  74. (face.mNumIndices < 3)
  75. ? "This is likely a control curve object."
  76. : "Only 3 vertices are supported per face, you could fix it by triangulating the meshes in the dcc tool.");
  77. warningPrinted = true;
  78. continue;
  79. }
  80. for (unsigned int idx = 0; idx < face.mNumIndices; ++idx)
  81. {
  82. meshFace.vertexIndex[idx] = face.mIndices[idx] + vertOffset;
  83. }
  84. newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
  85. }
  86. vertOffset += mesh->mNumVertices;
  87. }
  88. meshes.push_back(newMesh);
  89. return true;
  90. }
  91. GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context)
  92. {
  93. const DataTypes::IGraphObject* const parentData =
  94. context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition).get();
  95. if (!parentData)
  96. {
  97. AZ_Error(Utilities::ErrorWindow, false,
  98. "GetMeshDataFromParent failed because the parent was null, it should only be called with a valid parent node");
  99. return AZ::Failure(Events::ProcessingResult::Failure);
  100. }
  101. if (!parentData->RTTI_IsTypeOf(AZ::SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
  102. {
  103. // The parent node may contain bone information and not mesh information, skip it.
  104. if (parentData->RTTI_IsTypeOf(AZ::SceneData::GraphData::BoneData::TYPEINFO_Uuid()))
  105. {
  106. // Return the ignore processing result in the failure.
  107. return AZ::Failure(Events::ProcessingResult::Ignored);
  108. }
  109. AZ_Error(Utilities::ErrorWindow, false,
  110. "Tried to get mesh data from parent for non-mesh parent data");
  111. return AZ::Failure(Events::ProcessingResult::Failure);
  112. }
  113. const AZ::SceneData::GraphData::MeshData* const parentMeshData =
  114. azrtti_cast<const AZ::SceneData::GraphData::MeshData* const>(parentData);
  115. return AZ::Success(parentMeshData);
  116. }
  117. uint64_t GetVertexCountForAllMeshesOnNode(const aiNode& node, const aiScene& scene)
  118. {
  119. return AZStd::accumulate(node.mMeshes, node.mMeshes + node.mNumMeshes, uint64_t{ 0u },
  120. [&scene](auto runningTotal, unsigned int meshIndex)
  121. {
  122. return runningTotal + scene.mMeshes[meshIndex]->mNumVertices;
  123. });
  124. }
  125. }