AssImpUvMapImporter.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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/Math/Vector2.h>
  9. #include <AzCore/Serialization/SerializeContext.h>
  10. #include <AzCore/std/containers/array.h>
  11. #include <AzCore/std/numeric.h>
  12. #include <AzCore/std/smart_ptr/make_shared.h>
  13. #include <AzToolsFramework/Debug/TraceContext.h>
  14. #include <SceneAPI/SceneBuilder/ImportContexts/AssImpImportContexts.h>
  15. #include <SceneAPI/SceneBuilder/Importers/AssImpUvMapImporter.h>
  16. #include <SceneAPI/SceneBuilder/Importers/ImporterUtilities.h>
  17. #include <SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
  18. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  19. #include <SceneAPI/SceneData/GraphData/MeshData.h>
  20. #include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
  21. #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
  22. #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
  23. #include <assimp/scene.h>
  24. #include <assimp/mesh.h>
  25. namespace AZ
  26. {
  27. namespace SceneAPI
  28. {
  29. namespace SceneBuilder
  30. {
  31. const char* AssImpUvMapImporter::m_defaultNodeName = "UV";
  32. AssImpUvMapImporter::AssImpUvMapImporter()
  33. {
  34. BindToCall(&AssImpUvMapImporter::ImportUvMaps);
  35. }
  36. void AssImpUvMapImporter::Reflect(ReflectContext* context)
  37. {
  38. SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
  39. if (serializeContext)
  40. {
  41. serializeContext->Class<AssImpUvMapImporter, SceneCore::LoadingComponent>()->Version(4); // LYN-3250
  42. }
  43. }
  44. Events::ProcessingResult AssImpUvMapImporter::ImportUvMaps(AssImpSceneNodeAppendedContext& context)
  45. {
  46. AZ_TraceContext("Importer", m_defaultNodeName);
  47. if (!context.m_sourceNode.ContainsMesh())
  48. {
  49. return Events::ProcessingResult::Ignored;
  50. }
  51. const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
  52. const aiScene* scene = context.m_sourceScene.GetAssImpScene();
  53. // AssImp separates meshes that have multiple materials.
  54. // This code re-combines them to match previous FBX SDK behavior,
  55. // so they can be separated by engine code instead.
  56. bool foundTextureCoordinates = false;
  57. AZStd::array<int, AI_MAX_NUMBER_OF_TEXTURECOORDS> meshesPerTextureCoordinateIndex = {};
  58. for (unsigned int localMeshIndex = 0; localMeshIndex < currentNode->mNumMeshes; ++localMeshIndex)
  59. {
  60. aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[localMeshIndex]];
  61. for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
  62. {
  63. if (!mesh->mTextureCoords[texCoordIndex])
  64. {
  65. continue;
  66. }
  67. ++meshesPerTextureCoordinateIndex[texCoordIndex];
  68. foundTextureCoordinates = true;
  69. }
  70. }
  71. if (!foundTextureCoordinates)
  72. {
  73. return Events::ProcessingResult::Ignored;
  74. }
  75. const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
  76. for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
  77. {
  78. AZ_Error(
  79. Utilities::ErrorWindow,
  80. meshesPerTextureCoordinateIndex[texCoordIndex] == 0 ||
  81. meshesPerTextureCoordinateIndex[texCoordIndex] == static_cast<int>(currentNode->mNumMeshes),
  82. "Texture coordinate index %d for node %s is not on all meshes on this node. "
  83. "Placeholder arbitrary texture values will be generated to allow the data to process, but the source art "
  84. "needs to be fixed to correct this. All meshes on this node should have the same number of texture coordinate channels.",
  85. texCoordIndex,
  86. currentNode->mName.C_Str());
  87. }
  88. Events::ProcessingResultCombiner combinedUvMapResults;
  89. for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
  90. {
  91. // No meshes have this texture coordinate index, skip it.
  92. if (meshesPerTextureCoordinateIndex[texCoordIndex] == 0)
  93. {
  94. continue;
  95. }
  96. AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap =
  97. AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
  98. uvMap->ReserveContainerSpace(vertexCount);
  99. bool customNameFound = false;
  100. AZStd::string name(AZStd::string::format("%s%d", m_defaultNodeName, texCoordIndex));
  101. for (unsigned int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
  102. {
  103. const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
  104. if(mesh->mTextureCoords[texCoordIndex])
  105. {
  106. if (mesh->HasTextureCoordsName(texCoordIndex))
  107. {
  108. if (!customNameFound)
  109. {
  110. name = mesh->GetTextureCoordsName(texCoordIndex)->C_Str();
  111. customNameFound = true;
  112. }
  113. else
  114. {
  115. AZ_Warning(Utilities::WarningWindow,
  116. strcmp(name.c_str(), mesh->GetTextureCoordsName(texCoordIndex)->C_Str()) == 0,
  117. "Node %s has conflicting mesh coordinate names at index %d, %s and %s. Using %s.",
  118. currentNode->mName.C_Str(),
  119. texCoordIndex,
  120. name.c_str(),
  121. mesh->GetTextureCoordsName(texCoordIndex)->C_Str(),
  122. name.c_str());
  123. }
  124. }
  125. }
  126. for (unsigned int v = 0; v < mesh->mNumVertices; ++v)
  127. {
  128. if (mesh->mTextureCoords[texCoordIndex])
  129. {
  130. AZ::Vector2 vertexUV(
  131. mesh->mTextureCoords[texCoordIndex][v].x,
  132. // The engine's V coordinate is reverse of how it's coming in from the SDK.
  133. 1.0f - mesh->mTextureCoords[texCoordIndex][v].y);
  134. uvMap->AppendUV(vertexUV);
  135. }
  136. else
  137. {
  138. // An error was already emitted if the UV channels for all meshes on this node do not match.
  139. // Append an arbitrary UV value so that the mesh can still be processed.
  140. // It's better to let the engine load a partially valid mesh than to completely fail.
  141. uvMap->AppendUV(AZ::Vector2::CreateZero());
  142. }
  143. }
  144. }
  145. uvMap->SetCustomName(name.c_str());
  146. Containers::SceneGraph::NodeIndex newIndex =
  147. context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, name.c_str());
  148. Events::ProcessingResult uvMapResults;
  149. AssImpSceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, name);
  150. uvMapResults = Events::Process(dataPopulated);
  151. if (uvMapResults != Events::ProcessingResult::Failure)
  152. {
  153. uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
  154. }
  155. combinedUvMapResults += uvMapResults;
  156. }
  157. return combinedUvMapResults.GetResult();
  158. }
  159. } // namespace SceneBuilder
  160. } // namespace SceneAPI
  161. } // namespace AZ