UVsGenerateComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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 <Generation/Components/UVsGenerator/UVsGenerateComponent.h>
  9. #include <Generation/Components/UVsGenerator/UVsGenerators/SphereMappingUVsGenerator.h>
  10. #include <AzCore/std/smart_ptr/make_shared.h>
  11. #include <SceneAPI/SceneCore/Components/GenerationComponent.h>
  12. #include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
  13. #include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
  14. #include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
  15. #include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
  16. #include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
  17. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
  18. #include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshVertexUVData.h>
  19. #include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
  20. #include <SceneAPI/SceneData/Rules/UVsRule.h>
  21. #include <SceneAPI/SceneCore/Utilities/Reporting.h>
  22. namespace AZ::SceneGenerationComponents
  23. {
  24. //! Check whether UVs are to be generated, and if so, generate them.
  25. class UVsGenerateComponent : public AZ::SceneAPI::SceneCore::GenerationComponent
  26. {
  27. public:
  28. AZ_COMPONENT(UVsGenerateComponent, s_UVsGenerateComponentTypeId, SceneAPI::SceneCore::GenerationComponent);
  29. UVsGenerateComponent();
  30. static void Reflect(AZ::ReflectContext* context);
  31. // Invoked by the CallProcessorBinder flow. This is essentially the entry point for this operation.
  32. AZ::SceneAPI::Events::ProcessingResult GenerateUVsData(UVsGenerateContext& context);
  33. private:
  34. bool GenerateUVsForMesh(
  35. AZ::SceneAPI::Containers::Scene& scene,
  36. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex,
  37. AZ::SceneAPI::DataTypes::IMeshData* meshData,
  38. const AZ::SceneAPI::DataTypes::UVsGenerationMethod generationMethod,
  39. const bool replaceExisting);
  40. //! How many UV Sets already exist on the mesh?
  41. size_t CalcUvSetCount(
  42. AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex) const;
  43. //! find the Nth UV Set on the mesh and return it.
  44. AZ::SceneAPI::DataTypes::IMeshVertexUVData* FindUvData(
  45. AZ::SceneAPI::Containers::SceneGraph& graph,
  46. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex,
  47. AZ::u64 uvSet) const;
  48. //! Return the UV Rule (the modifier on the mesh group) or nullptr if no such modifier is applied.
  49. const AZ::SceneAPI::SceneData::UVsRule* GetUVsRule(const AZ::SceneAPI::Containers::Scene& scene) const;
  50. //! Create a new UV set and hook it into the scene graph
  51. bool CreateUVsLayer(
  52. AZ::SceneAPI::Containers::SceneManifest& manifest,
  53. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex,
  54. AZ::SceneAPI::Containers::SceneGraph& graph,
  55. SceneData::GraphData::MeshVertexUVData** outUVsData);
  56. };
  57. AZ::ComponentDescriptor* CreateUVsGenerateComponentDescriptor()
  58. {
  59. return UVsGenerateComponent::CreateDescriptor();
  60. }
  61. UVsGenerateComponent::UVsGenerateComponent()
  62. {
  63. BindToCall(&UVsGenerateComponent::GenerateUVsData);
  64. }
  65. void UVsGenerateComponent::Reflect(AZ::ReflectContext* context)
  66. {
  67. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  68. if (serializeContext)
  69. {
  70. serializeContext->Class<UVsGenerateComponent, AZ::SceneAPI::SceneCore::GenerationComponent>()->Version(1);
  71. }
  72. }
  73. const AZ::SceneAPI::SceneData::UVsRule* UVsGenerateComponent::GetUVsRule(const AZ::SceneAPI::Containers::Scene& scene) const
  74. {
  75. for (const auto& object : scene.GetManifest().GetValueStorage())
  76. {
  77. if (object->RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::IGroup::TYPEINFO_Uuid()))
  78. {
  79. const AZ::SceneAPI::DataTypes::IGroup* group = azrtti_cast<const AZ::SceneAPI::DataTypes::IGroup*>(object.get());
  80. const AZ::SceneAPI::SceneData::UVsRule* rule = group->GetRuleContainerConst().FindFirstByType<AZ::SceneAPI::SceneData::UVsRule>().get();
  81. if (rule)
  82. {
  83. return rule;
  84. }
  85. }
  86. }
  87. return nullptr;
  88. }
  89. AZ::SceneAPI::Events::ProcessingResult UVsGenerateComponent::GenerateUVsData(UVsGenerateContext& context)
  90. {
  91. // this component runs regardless of what modifiers are present on the mesh.
  92. // Set some defaults to use if no settings are present at all:
  93. AZ::SceneAPI::DataTypes::UVsGenerationMethod defaultGenerationMethod =
  94. AZ::SceneAPI::SceneData::UVsRule::GetDefaultGenerationMethodWithNoRule();
  95. bool defaultReplaceExisting = false;
  96. const AZ::SceneAPI::SceneData::UVsRule* uvsRule = GetUVsRule(context.GetScene());
  97. const AZ::SceneAPI::DataTypes::UVsGenerationMethod generationMethod = uvsRule ? uvsRule->GetGenerationMethod() : defaultGenerationMethod;
  98. const bool replaceExisting = uvsRule ? uvsRule->GetReplaceExisting() : defaultReplaceExisting;
  99. if (generationMethod == SceneAPI::DataTypes::UVsGenerationMethod::LeaveSceneDataAsIs)
  100. {
  101. // no point in going any further if the rule basically says to leave scene data as is
  102. return AZ::SceneAPI::Events::ProcessingResult::Success;
  103. }
  104. // Iterate over all graph content and filter out all meshes.
  105. AZ::SceneAPI::Containers::SceneGraph& graph = context.GetScene().GetGraph();
  106. AZ::SceneAPI::Containers::SceneGraph::ContentStorageData graphContent = graph.GetContentStorage();
  107. // Build a list of mesh data nodes.
  108. AZStd::vector<AZStd::pair<AZ::SceneAPI::DataTypes::IMeshData*, AZ::SceneAPI::Containers::SceneGraph::NodeIndex> > meshes;
  109. for (auto item = graphContent.begin(); item != graphContent.end(); ++item)
  110. {
  111. // Skip anything that isn't a mesh.
  112. if (!(*item) || !(*item)->RTTI_IsTypeOf(AZ::SceneAPI::DataTypes::IMeshData::TYPEINFO_Uuid()))
  113. {
  114. continue;
  115. }
  116. // Get the mesh data and node index and store them in the vector as a pair, so we can iterate over them later.
  117. auto* mesh = static_cast<AZ::SceneAPI::DataTypes::IMeshData*>(item->get());
  118. AZ::SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex = graph.ConvertToNodeIndex(item);
  119. meshes.emplace_back(mesh, nodeIndex);
  120. }
  121. // Iterate over them. We had to build the array before as this method can insert new nodes, so using the iterator directly would fail.
  122. for (auto& [mesh, nodeIndex] : meshes)
  123. {
  124. // Generate UVs for the mesh
  125. if (!GenerateUVsForMesh(context.GetScene(), nodeIndex, mesh, generationMethod, replaceExisting))
  126. {
  127. return AZ::SceneAPI::Events::ProcessingResult::Failure;
  128. }
  129. }
  130. return AZ::SceneAPI::Events::ProcessingResult::Success;
  131. }
  132. bool UVsGenerateComponent::GenerateUVsForMesh(
  133. AZ::SceneAPI::Containers::Scene& scene,
  134. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex,
  135. AZ::SceneAPI::DataTypes::IMeshData* meshData,
  136. const AZ::SceneAPI::DataTypes::UVsGenerationMethod generationMethod,
  137. const bool replaceExisting)
  138. {
  139. AZ::SceneAPI::Containers::SceneGraph& graph = scene.GetGraph();
  140. size_t uvSetCount = CalcUvSetCount(graph, nodeIndex);
  141. // there might already be existing data there - see if there is.
  142. AZ::SceneData::GraphData::MeshVertexUVData* dataToFill = nullptr;
  143. if (uvSetCount > 0)
  144. {
  145. // This modifier always works on UV Set #0.
  146. dataToFill = static_cast<AZ::SceneData::GraphData::MeshVertexUVData*>(FindUvData(graph, nodeIndex, 0));
  147. }
  148. AZStd::string currentNodeName = graph.GetNodeName(nodeIndex).GetPath();
  149. if ((dataToFill) && (!replaceExisting))
  150. {
  151. // if there's already data, and we are not set to replace existing, do not generate data
  152. AZ_Info(
  153. AZ::SceneAPI::Utilities::LogWindow,
  154. "Asked to generate UVs for mesh " AZ_STRING_FORMAT " but it already has UVs and 'replace existing' is not set. Not replacing existing data.\n",
  155. AZ_STRING_ARG(currentNodeName));
  156. return true; // this is not an error!
  157. }
  158. if (!dataToFill)
  159. {
  160. if (!CreateUVsLayer(scene.GetManifest(), nodeIndex, graph, &dataToFill))
  161. {
  162. // the above function will emit an error if it fails.
  163. return false;
  164. }
  165. }
  166. bool allSuccess = true;
  167. AZ_Info(
  168. AZ::SceneAPI::Utilities::LogWindow,
  169. "Generating UVs for " AZ_STRING_FORMAT ".\n",
  170. AZ_STRING_ARG(currentNodeName));
  171. switch (generationMethod)
  172. {
  173. case AZ::SceneAPI::DataTypes::UVsGenerationMethod::SphericalProjection:
  174. {
  175. allSuccess &= AZ::UVsGeneration::Mesh::SphericalMapping::GenerateUVsSphericalMapping(meshData, dataToFill);
  176. break;
  177. }
  178. // for future expansion - add new methods here if you want to support additional methods of UV auto generation.
  179. default:
  180. {
  181. AZ_Assert(false, "Unknown UVs generation method selected (%u) cannot generate UVs.\n", static_cast<AZ::u32>(generationMethod));
  182. allSuccess = false;
  183. }
  184. }
  185. return allSuccess;
  186. }
  187. size_t UVsGenerateComponent::CalcUvSetCount(
  188. AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex) const
  189. {
  190. const auto nameContentView = AZ::SceneAPI::Containers::Views::MakePairView(graph.GetNameStorage(), graph.GetContentStorage());
  191. size_t result = 0;
  192. auto meshChildView = AZ::SceneAPI::Containers::Views::MakeSceneGraphChildView<AZ::SceneAPI::Containers::Views::AcceptEndPointsOnly>(
  193. graph, nodeIndex, nameContentView.begin(), true);
  194. for (auto child = meshChildView.begin(); child != meshChildView.end(); ++child)
  195. {
  196. AZ::SceneAPI::DataTypes::IMeshVertexUVData* data =
  197. azrtti_cast<AZ::SceneAPI::DataTypes::IMeshVertexUVData*>(child->second.get());
  198. if (data)
  199. {
  200. result++;
  201. }
  202. }
  203. return result;
  204. }
  205. AZ::SceneAPI::DataTypes::IMeshVertexUVData* UVsGenerateComponent::FindUvData(
  206. AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, AZ::u64 uvSet) const
  207. {
  208. const auto nameContentView = AZ::SceneAPI::Containers::Views::MakePairView(graph.GetNameStorage(), graph.GetContentStorage());
  209. AZ::u64 uvSetIndex = 0;
  210. auto meshChildView = AZ::SceneAPI::Containers::Views::MakeSceneGraphChildView<AZ::SceneAPI::Containers::Views::AcceptEndPointsOnly>(
  211. graph, nodeIndex, nameContentView.begin(), true);
  212. for (auto child = meshChildView.begin(); child != meshChildView.end(); ++child)
  213. {
  214. AZ::SceneAPI::DataTypes::IMeshVertexUVData* data =
  215. azrtti_cast<AZ::SceneAPI::DataTypes::IMeshVertexUVData*>(child->second.get());
  216. if (data)
  217. {
  218. if (uvSetIndex == uvSet)
  219. {
  220. return data;
  221. }
  222. uvSetIndex++;
  223. }
  224. }
  225. return nullptr;
  226. }
  227. bool UVsGenerateComponent::CreateUVsLayer(
  228. AZ::SceneAPI::Containers::SceneManifest& manifest,
  229. const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex,
  230. AZ::SceneAPI::Containers::SceneGraph& graph,
  231. SceneData::GraphData::MeshVertexUVData** outUVsData)
  232. {
  233. *outUVsData = nullptr;
  234. AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvData =
  235. AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
  236. if (!uvData)
  237. {
  238. // it is unlikely you will even see this message since you are out of memory and the below
  239. AZ_Error(AZ::SceneAPI::Utilities::ErrorWindow, false, "OUT OF MEMORY - Failed to allocate UV data.\n"
  240. "You could try reducing the size of the files, splitting into multiple geometries, or reducing the number "
  241. "or concurrent Asset Processor Jobs allowed to run.");
  242. return false;
  243. }
  244. const AZStd::string uvSetName =
  245. AZ::SceneAPI::DataTypes::Utilities::CreateUniqueName<SceneData::GraphData::MeshVertexUVData>("UV0", manifest);
  246. uvData->SetCustomName(uvSetName.c_str());
  247. AZ::SceneAPI::Containers::SceneGraph::NodeIndex newIndex = graph.AddChild(nodeIndex, uvSetName.c_str(), uvData);
  248. // if this assert triggers theres some terrible bug deep in the scene graph system, and the artist that sees it
  249. // is not going to be able to fix it without code intervention (so assert).
  250. AZ_Assert(newIndex.IsValid(), "Failed to create SceneGraph node for UVs attribute.");
  251. if (!newIndex.IsValid())
  252. {
  253. return false;
  254. }
  255. graph.MakeEndPoint(newIndex);
  256. *outUVsData = uvData.get();
  257. return true;
  258. }
  259. } // namespace AZ::SceneGenerationComponents