ソースを参照

Add AssImp import settings to the Scene Processor (#16753)

* First working version of Import Settings panel.
The settings themselves aren't applied yet.

Signed-off-by: Mike Balfour <[email protected]>

* Disambiguate AZ::SceneData from AZ::SceneAPI::SceneData

Signed-off-by: Mike Balfour <[email protected]>

* Expose the manifest loader for use by SceneBuilder.

Signed-off-by: Mike Balfour <[email protected]>

* First working version of import settings

Signed-off-by: Mike Balfour <[email protected]>

* Cleaned up optimize mesh text to make it more descriptive

Signed-off-by: Mike Balfour <[email protected]>

* Fix bug where extra import settings would get added on load.

Signed-off-by: Mike Balfour <[email protected]>

* Fix crash that occurs if settings get out of sync.

Signed-off-by: Mike Balfour <[email protected]>

* Disable the Import Group UX settings for now.

Signed-off-by: Mike Balfour <[email protected]>

* Add support for setting the settings via API.
Also adds support for globally changing the settings via setreg.
Signed-off-by: Mike Balfour <[email protected]>

* Removed unnecessary [[maybe_unused]]
Signed-off-by: Mike Balfour <[email protected]>

* Remove bizarrely extraneous use of AZStd::function.
Signed-off-by: Mike Balfour <[email protected]>

* PR feedback
Added default Scene constructor, nested the namespaces, removed extraneous NameLabelOverride.

Signed-off-by: Mike Balfour <[email protected]>

* Revert the previous tab order changes but fix bug where negative tab orders didn't compare correctly vs max int.

Signed-off-by: Mike Balfour <[email protected]>

* Update Code/Tools/SceneAPI/SceneData/Behaviors/ImportGroup.h

Co-authored-by: lumberyard-employee-dm <[email protected]>
Signed-off-by: Mike Balfour <[email protected]>

* Fix accidental uncommenting.

Signed-off-by: Mike Balfour <[email protected]>

* Fixed whitespace.

Signed-off-by: Mike Balfour <[email protected]>

* Added missing include

Signed-off-by: Mike Balfour <[email protected]>

* Fix for lua so that it doesn't pick the default constructor by mistake.

Signed-off-by: Mike Balfour <[email protected]>

---------

Signed-off-by: Mike Balfour <[email protected]>
Co-authored-by: lumberyard-employee-dm <[email protected]>
Mike Balfour 2 年 前
コミット
2c0f93fce4
26 ファイル変更532 行追加58 行削除
  1. 11 7
      Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp
  2. 3 2
      Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.h
  3. 25 23
      Code/Tools/SceneAPI/SDKWrapper/SceneWrapper.cpp
  4. 3 2
      Code/Tools/SceneAPI/SDKWrapper/SceneWrapper.h
  5. 6 6
      Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp
  6. 5 5
      Code/Tools/SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp
  7. 2 2
      Code/Tools/SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h
  8. 42 6
      Code/Tools/SceneAPI/SceneBuilder/SceneImporter.cpp
  9. 2 0
      Code/Tools/SceneAPI/SceneBuilder/SceneImporter.h
  10. 1 0
      Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp
  11. 2 1
      Code/Tools/SceneAPI/SceneCore/Containers/Scene.h
  12. 35 0
      Code/Tools/SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h
  13. 6 0
      Code/Tools/SceneAPI/SceneCore/DllMain.cpp
  14. 5 3
      Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h
  15. 46 0
      Code/Tools/SceneAPI/SceneCore/Import/SceneImportSettings.cpp
  16. 30 0
      Code/Tools/SceneAPI/SceneCore/Import/SceneImportSettings.h
  17. 3 0
      Code/Tools/SceneAPI/SceneCore/scenecore_files.cmake
  18. 101 0
      Code/Tools/SceneAPI/SceneData/Behaviors/BehaviorsImportGroup.cpp
  19. 43 0
      Code/Tools/SceneAPI/SceneData/Behaviors/ImportGroup.h
  20. 2 0
      Code/Tools/SceneAPI/SceneData/Behaviors/Registry.cpp
  21. 89 0
      Code/Tools/SceneAPI/SceneData/Groups/ImportGroup.cpp
  22. 53 0
      Code/Tools/SceneAPI/SceneData/Groups/ImportGroup.h
  23. 2 0
      Code/Tools/SceneAPI/SceneData/ReflectionRegistrar.cpp
  24. 4 0
      Code/Tools/SceneAPI/SceneData/SceneData_files.cmake
  25. 1 1
      Code/Tools/SceneAPI/SceneUI/SceneWidgets/ManifestWidget.cpp
  26. 10 0
      Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshOptimizerComponent.cpp

+ 11 - 7
Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp

@@ -47,7 +47,7 @@ namespace AZ
         }
         }
 #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
 #endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
 
 
-        bool AssImpSceneWrapper::LoadSceneFromFile(const char* fileName)
+        bool AssImpSceneWrapper::LoadSceneFromFile(const char* fileName, const AZ::SceneAPI::SceneImportSettings& importSettings)
         {
         {
             AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName);
             AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName);
             AZ_TraceContext("Filename", fileName);
             AZ_TraceContext("Filename", fileName);
@@ -71,6 +71,13 @@ namespace AZ
             // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this,
             // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this,
             // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release.
             // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release.
             // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph.
             // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph.
+            unsigned int importFlags =
+                aiProcess_Triangulate                                               // Triangulates all faces of all meshes
+                | static_cast<unsigned long>(aiProcess_GenBoundingBoxes)            // Generate bounding boxes
+                | aiProcess_GenNormals                                              // Generate normals for meshes
+                | (importSettings.m_optimizeScene ? aiProcess_OptimizeGraph : 0)    // Merge excess scene nodes together
+                | (importSettings.m_optimizeMeshes ? aiProcess_OptimizeMeshes : 0)  // Combines meshes in the scene together
+                ;
 
 
             // aiProcess_LimitBoneWeights is not enabled because it will remove bones which are not associated with a mesh.
             // aiProcess_LimitBoneWeights is not enabled because it will remove bones which are not associated with a mesh.
             // This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer.
             // This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer.
@@ -81,10 +88,7 @@ namespace AZ
             // This is here as a bread crumb to save others times investigating issues with empty bones.
             // This is here as a bread crumb to save others times investigating issues with empty bones.
             // m_importer.SetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, false);
             // m_importer.SetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, false);
             m_sceneFileName = fileName;
             m_sceneFileName = fileName;
-            m_assImpScene = m_importer->ReadFile(fileName,
-                aiProcess_Triangulate //Triangulates all faces of all meshes
-                | static_cast<unsigned long>(aiProcess_GenBoundingBoxes) // Generate bounding boxes
-                | aiProcess_GenNormals); //Generate normals for meshes
+            m_assImpScene = m_importer->ReadFile(fileName, importFlags);
 
 
 #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
 #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
             // Reset abort behavior for anything else that may call abort.
             // Reset abort behavior for anything else that may call abort.
@@ -105,9 +109,9 @@ namespace AZ
             return true;
             return true;
         }
         }
 
 
-        bool AssImpSceneWrapper::LoadSceneFromFile(const AZStd::string& fileName)
+        bool AssImpSceneWrapper::LoadSceneFromFile(const AZStd::string& fileName, const AZ::SceneAPI::SceneImportSettings& importSettings)
         {
         {
-            return LoadSceneFromFile(fileName.c_str());
+            return LoadSceneFromFile(fileName.c_str(), importSettings);
         }
         }
 
 
         const std::shared_ptr<SDKNode::NodeWrapper> AssImpSceneWrapper::GetRootNode() const
         const std::shared_ptr<SDKNode::NodeWrapper> AssImpSceneWrapper::GetRootNode() const

+ 3 - 2
Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.h

@@ -7,6 +7,7 @@
  */
  */
 #pragma once
 #pragma once
 #include <SceneAPI/SDKWrapper/SceneWrapper.h>
 #include <SceneAPI/SDKWrapper/SceneWrapper.h>
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
 #include <assimp/Importer.hpp>
 #include <assimp/Importer.hpp>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
 
 
@@ -24,8 +25,8 @@ namespace AZ
             AssImpSceneWrapper(aiScene* aiScene);
             AssImpSceneWrapper(aiScene* aiScene);
             ~AssImpSceneWrapper() override = default;
             ~AssImpSceneWrapper() override = default;
 
 
-            bool LoadSceneFromFile(const char* fileName) override;
-            bool LoadSceneFromFile(const AZStd::string& fileName) override;
+            bool LoadSceneFromFile(const char* fileName, const AZ::SceneAPI::SceneImportSettings& importSettings) override;
+            bool LoadSceneFromFile(const AZStd::string& fileName, const AZ::SceneAPI::SceneImportSettings& importSettings) override;
 
 
             const std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() const override;
             const std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() const override;
             std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() override;
             std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() override;

+ 25 - 23
Code/Tools/SceneAPI/SDKWrapper/SceneWrapper.cpp

@@ -9,30 +9,32 @@
 
 
 namespace AZ
 namespace AZ
 {
 {
-   namespace SDKScene
-   {
-      const char* SceneWrapperBase::s_defaultSceneName = "myScene";
+    namespace SDKScene
+    {
+        const char* SceneWrapperBase::s_defaultSceneName = "myScene";
 
 
-      bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const char* fileName)
-      {
-          return false;
-      }
-      bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const AZStd::string& fileName)
-      {
-          return LoadSceneFromFile(fileName.c_str());
-      }
+        bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const char* fileName,
+            [[maybe_unused]] const SceneAPI::SceneImportSettings& importSettings)
+        {
+            return false;
+        }
+        bool SceneWrapperBase::LoadSceneFromFile([[maybe_unused]] const AZStd::string& fileName,
+            const SceneAPI::SceneImportSettings& importSettings)
+        {
+            return LoadSceneFromFile(fileName.c_str(), importSettings);
+        }
 
 
-      const std::shared_ptr<SDKNode::NodeWrapper> SceneWrapperBase::GetRootNode() const
-      {
-          return {};
-      }
-      std::shared_ptr<SDKNode::NodeWrapper> SceneWrapperBase::GetRootNode()
-      {
-          return {};
-      }
+        const std::shared_ptr<SDKNode::NodeWrapper> SceneWrapperBase::GetRootNode() const
+        {
+            return {};
+        }
+        std::shared_ptr<SDKNode::NodeWrapper> SceneWrapperBase::GetRootNode()
+        {
+            return {};
+        }
 
 
-      void SceneWrapperBase::Clear()
-      {
-      }
-   } //namespace Scene
+        void SceneWrapperBase::Clear()
+        {
+        }
+    } //namespace SDKScene
 }// namespace AZ
 }// namespace AZ

+ 3 - 2
Code/Tools/SceneAPI/SDKWrapper/SceneWrapper.h

@@ -9,6 +9,7 @@
 #include <AzCore/std/smart_ptr/shared_ptr.h>
 #include <AzCore/std/smart_ptr/shared_ptr.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/string.h>
 #include <SceneAPI/SDKWrapper/NodeWrapper.h>
 #include <SceneAPI/SDKWrapper/NodeWrapper.h>
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
 
 
 struct aiScene;
 struct aiScene;
 
 
@@ -22,8 +23,8 @@ namespace AZ
             AZ_RTTI(SceneWrapperBase, "{703CD344-2C75-4F30-8CE2-6BDEF2511AFD}");
             AZ_RTTI(SceneWrapperBase, "{703CD344-2C75-4F30-8CE2-6BDEF2511AFD}");
             virtual ~SceneWrapperBase() = default;
             virtual ~SceneWrapperBase() = default;
 
 
-            virtual bool LoadSceneFromFile(const char* fileName);
-            virtual bool LoadSceneFromFile(const AZStd::string& fileName);
+            virtual bool LoadSceneFromFile(const char* fileName, const SceneAPI::SceneImportSettings& importSettings = {});
+            virtual bool LoadSceneFromFile(const AZStd::string& fileName, const SceneAPI::SceneImportSettings& importSettings = {});
 
 
             virtual const std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() const;
             virtual const std::shared_ptr<SDKNode::NodeWrapper> GetRootNode() const;
             virtual std::shared_ptr<SDKNode::NodeWrapper> GetRootNode();
             virtual std::shared_ptr<SDKNode::NodeWrapper> GetRootNode();

+ 6 - 6
Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp

@@ -414,8 +414,8 @@ namespace AZ
                         const aiMeshMorphAnim* nodeAnim = animation->mMorphMeshChannels[channelIndex];
                         const aiMeshMorphAnim* nodeAnim = animation->mMorphMeshChannels[channelIndex];
                         // Morph animations need a regular animation on the node, as well.
                         // Morph animations need a regular animation on the node, as well.
                         // If there is no bone animation on the current node, then generate one here.
                         // If there is no bone animation on the current node, then generate one here.
-                        AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
-                            AZStd::make_shared<SceneData::GraphData::AnimationData>();
+                        AZStd::shared_ptr<AZ::SceneData::GraphData::AnimationData> createdAnimationData =
+                            AZStd::make_shared<AZ::SceneData::GraphData::AnimationData>();
 
 
                         const size_t numKeyframes = GetNumKeyFrames(
                         const size_t numKeyframes = GetNumKeyFrames(
                             nodeAnim->mNumKeys,
                             nodeAnim->mNumKeys,
@@ -565,8 +565,8 @@ namespace AZ
                         animation->mDuration,
                         animation->mDuration,
                         animation->mTicksPerSecond);
                         animation->mTicksPerSecond);
 
 
-                    AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
-                       AZStd::make_shared<SceneData::GraphData::AnimationData>();
+                    AZStd::shared_ptr<AZ::SceneData::GraphData::AnimationData> createdAnimationData =
+                       AZStd::make_shared<AZ::SceneData::GraphData::AnimationData>();
                     createdAnimationData->ReserveKeyFrames(numKeyFrames);
                     createdAnimationData->ReserveKeyFrames(numKeyFrames);
                     createdAnimationData->SetTimeStepBetweenFrames(s_defaultTimeStepBetweenFrames);
                     createdAnimationData->SetTimeStepBetweenFrames(s_defaultTimeStepBetweenFrames);
 
 
@@ -663,8 +663,8 @@ namespace AZ
                             mesh->mName.C_Str(), meshIdx, mesh->mNumAnimMeshes);
                             mesh->mName.C_Str(), meshIdx, mesh->mNumAnimMeshes);
                         continue;
                         continue;
                     }
                     }
-                    AZStd::shared_ptr<SceneData::GraphData::BlendShapeAnimationData> morphAnimNode =
-                        AZStd::make_shared<SceneData::GraphData::BlendShapeAnimationData>();
+                    AZStd::shared_ptr<AZ::SceneData::GraphData::BlendShapeAnimationData> morphAnimNode =
+                        AZStd::make_shared<AZ::SceneData::GraphData::BlendShapeAnimationData>();
 
 
                     const size_t numKeyFrames = GetNumKeyFrames(static_cast<AZ::u32>(keys.size()), animation->mDuration, animation->mTicksPerSecond);
                     const size_t numKeyFrames = GetNumKeyFrames(static_cast<AZ::u32>(keys.size()), animation->mDuration, animation->mTicksPerSecond);
                     morphAnimNode->ReserveKeyFrames(numKeyFrames);
                     morphAnimNode->ReserveKeyFrames(numKeyFrames);

+ 5 - 5
Code/Tools/SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp

@@ -22,7 +22,7 @@
 namespace AZ::SceneAPI::SceneBuilder
 namespace AZ::SceneAPI::SceneBuilder
 {
 {
     bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const SceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
     bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const SceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
-        const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc)
+        const AZStd::function<AZStd::shared_ptr<AZ::SceneData::GraphData::MeshData>()>& makeMeshFunc)
     {
     {
         AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
         AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
         int lyMeshIndex = 0;
         int lyMeshIndex = 0;
@@ -117,10 +117,10 @@ namespace AZ::SceneAPI::SceneBuilder
             return AZ::Failure(Events::ProcessingResult::Failure);
             return AZ::Failure(Events::ProcessingResult::Failure);
         }
         }
 
 
-        if (!parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
+        if (!parentData->RTTI_IsTypeOf(AZ::SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
         {
         {
             // The parent node may contain bone information and not mesh information, skip it.
             // The parent node may contain bone information and not mesh information, skip it.
-            if (parentData->RTTI_IsTypeOf(SceneData::GraphData::BoneData::TYPEINFO_Uuid()))
+            if (parentData->RTTI_IsTypeOf(AZ::SceneData::GraphData::BoneData::TYPEINFO_Uuid()))
             {
             {
                 // Return the ignore processing result in the failure.
                 // Return the ignore processing result in the failure.
                 return AZ::Failure(Events::ProcessingResult::Ignored);
                 return AZ::Failure(Events::ProcessingResult::Ignored);
@@ -130,8 +130,8 @@ namespace AZ::SceneAPI::SceneBuilder
             return AZ::Failure(Events::ProcessingResult::Failure);
             return AZ::Failure(Events::ProcessingResult::Failure);
         }
         }
 
 
-        const SceneData::GraphData::MeshData* const parentMeshData =
-            azrtti_cast<const SceneData::GraphData::MeshData* const>(parentData);
+        const AZ::SceneData::GraphData::MeshData* const parentMeshData =
+            azrtti_cast<const AZ::SceneData::GraphData::MeshData* const>(parentData);
         return AZ::Success(parentMeshData);
         return AZ::Success(parentMeshData);
     }
     }
 
 

+ 2 - 2
Code/Tools/SceneAPI/SceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h

@@ -36,9 +36,9 @@ namespace AZ
         namespace SceneBuilder
         namespace SceneBuilder
         {
         {
             bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const SceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
             bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const SceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
-                const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc);
+                const AZStd::function<AZStd::shared_ptr<AZ::SceneData::GraphData::MeshData>()>& makeMeshFunc);
 
 
-            typedef AZ::Outcome<const SceneData::GraphData::MeshData*, Events::ProcessingResult> GetMeshDataFromParentResult;
+            typedef AZ::Outcome<const AZ::SceneData::GraphData::MeshData*, Events::ProcessingResult> GetMeshDataFromParentResult;
             GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context);
             GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context);
 
 
             // If a node in the original scene file has a mesh with multiple materials on it, the associated AssImp
             // If a node in the original scene file has a mesh with multiple materials on it, the associated AssImp

+ 42 - 6
Code/Tools/SceneAPI/SceneBuilder/SceneImporter.cpp

@@ -10,6 +10,7 @@
 #include <AzCore/Debug/Trace.h>
 #include <AzCore/Debug/Trace.h>
 #include <AzCore/Math/Transform.h>
 #include <AzCore/Math/Transform.h>
 #include <AzCore/Serialization/SerializeContext.h>
 #include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Settings/SettingsRegistry.h>
 #include <AzCore/std/containers/queue.h>
 #include <AzCore/std/containers/queue.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/string/conversions.h>
 #include <AzCore/std/string/conversions.h>
@@ -21,11 +22,14 @@
 #include <SceneAPI/SceneBuilder/Importers/ImporterUtilities.h>
 #include <SceneAPI/SceneBuilder/Importers/ImporterUtilities.h>
 #include <SceneAPI/SceneBuilder/Importers/Utilities/RenamedNodesMap.h>
 #include <SceneAPI/SceneBuilder/Importers/Utilities/RenamedNodesMap.h>
 #include <SceneAPI/SceneCore/Containers/Scene.h>
 #include <SceneAPI/SceneCore/Containers/Scene.h>
+#include <SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h>
+#include <SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h>
 #include <SceneAPI/SceneCore/Utilities/Reporting.h>
 #include <SceneAPI/SceneCore/Utilities/Reporting.h>
 #include <SceneAPI/SceneData/GraphData/TransformData.h>
 #include <SceneAPI/SceneData/GraphData/TransformData.h>
 #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
 #include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
 #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
 #include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
 
 
+
 namespace AZ
 namespace AZ
 {
 {
     namespace SceneAPI
     namespace SceneAPI
@@ -61,26 +65,58 @@ namespace AZ
                 }
                 }
             }
             }
 
 
+            SceneAPI::SceneImportSettings SceneImporter::GetSceneImportSettings(const AZStd::string& sourceAssetPath) const
+            {
+                // Start with a default set of import settings.
+                SceneAPI::SceneImportSettings importSettings;
+
+                // Try to read in any global settings from the settings registry.
+                if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
+                {
+                    settingsRegistry->GetObject(importSettings, AZ::SceneAPI::DataTypes::IImportGroup::SceneImportSettingsRegistryKey);
+                }
+
+                // Try reading in the scene manifest (.assetinfo file), which contains the import settings if they've been
+                // changed from the defaults.
+                Containers::Scene scene;
+                Import::ManifestImportRequestHandler manifestHandler;
+                manifestHandler.LoadAsset(
+                    scene, sourceAssetPath,
+                    Uuid::CreateNull(),
+                    Events::AssetImportRequest::RequestingApplication::AssetProcessor);
+
+                // Search for the ImportGroup. If it's there, get the new import settings. If not, we'll just use the defaults.
+                size_t count = scene.GetManifest().GetEntryCount();
+                for (size_t index = 0; index < count; index++)
+                {
+                    if (auto* importGroup = azrtti_cast<DataTypes::IImportGroup*>(scene.GetManifest().GetValue(index).get()); importGroup)
+                    {
+                        importSettings = importGroup->GetImportSettings();
+                        break;
+                    }
+                }
+
+                return importSettings;
+            }
+
             Events::ProcessingResult SceneImporter::ImportProcessing(Events::ImportEventContext& context)
             Events::ProcessingResult SceneImporter::ImportProcessing(Events::ImportEventContext& context)
             {
             {
+                SceneAPI::SceneImportSettings importSettings = GetSceneImportSettings(context.GetInputDirectory());
+
                 m_sceneWrapper->Clear();
                 m_sceneWrapper->Clear();
 
 
-                if (!m_sceneWrapper->LoadSceneFromFile(context.GetInputDirectory().c_str()))
+                if (!m_sceneWrapper->LoadSceneFromFile(context.GetInputDirectory().c_str(), importSettings))
                 {
                 {
                     return Events::ProcessingResult::Failure;
                     return Events::ProcessingResult::Failure;
                 }
                 }
 
 
-                typedef AZStd::function<bool(Containers::Scene & scene)> ConvertFunc;
-                ConvertFunc convertFunc;
                 m_sceneSystem->Set(m_sceneWrapper.get());
                 m_sceneSystem->Set(m_sceneWrapper.get());
                 if (!azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(m_sceneWrapper.get()))
                 if (!azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(m_sceneWrapper.get()))
                 {
                 {
                     return Events::ProcessingResult::Failure;
                     return Events::ProcessingResult::Failure;
                 }
                 }
 
 
-                convertFunc = AZStd::bind(&SceneImporter::ConvertScene, this, AZStd::placeholders::_1);
-                
-                if (convertFunc(context.GetScene()))
+                if (ConvertScene(context.GetScene()))
                 {
                 {
                     return Events::ProcessingResult::Success;
                     return Events::ProcessingResult::Success;
                 }
                 }

+ 2 - 0
Code/Tools/SceneAPI/SceneBuilder/SceneImporter.h

@@ -13,6 +13,7 @@
 #include <SceneAPI/SceneCore/Components/LoadingComponent.h>
 #include <SceneAPI/SceneCore/Components/LoadingComponent.h>
 #include <SceneAPI/SceneCore/Containers/SceneGraph.h>
 #include <SceneAPI/SceneCore/Containers/SceneGraph.h>
 #include <SceneAPI/SceneCore/Events/ImportEventContext.h>
 #include <SceneAPI/SceneCore/Events/ImportEventContext.h>
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
 #include <SceneAPI/SceneBuilder/SceneSystem.h>
 #include <SceneAPI/SceneBuilder/SceneSystem.h>
 #include <SceneAPI/SDKWrapper/SceneWrapper.h>
 #include <SceneAPI/SDKWrapper/SceneWrapper.h>
 
 
@@ -41,6 +42,7 @@ namespace AZ
                 Events::ProcessingResult ImportProcessing(Events::ImportEventContext& context);
                 Events::ProcessingResult ImportProcessing(Events::ImportEventContext& context);
 
 
             protected:
             protected:
+                SceneAPI::SceneImportSettings GetSceneImportSettings(const AZStd::string& sourceAssetPath) const;
                 bool ConvertScene(Containers::Scene& scene) const;
                 bool ConvertScene(Containers::Scene& scene) const;
                 void SanitizeNodeName(AZStd::string& nodeName) const;
                 void SanitizeNodeName(AZStd::string& nodeName) const;
 
 

+ 1 - 0
Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp

@@ -148,6 +148,7 @@ namespace AZ
                         ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
                         ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
                         ->Attribute(AZ::Script::Attributes::Module, "scene")
                         ->Attribute(AZ::Script::Attributes::Module, "scene")
                         ->Constructor<const AZStd::string&>()
                         ->Constructor<const AZStd::string&>()
+                            ->Attribute(AZ::Script::Attributes::DefaultConstructorOverrideIndex, 0)
                         ->Property("name", BehaviorValueGetter(&Scene::m_name), nullptr)
                         ->Property("name", BehaviorValueGetter(&Scene::m_name), nullptr)
                         ->Property("manifestFilename", BehaviorValueGetter(&Scene::m_manifestFilename), nullptr)
                         ->Property("manifestFilename", BehaviorValueGetter(&Scene::m_manifestFilename), nullptr)
                         ->Property("sourceFilename", BehaviorValueGetter(&Scene::m_sourceFilename), nullptr)
                         ->Property("sourceFilename", BehaviorValueGetter(&Scene::m_sourceFilename), nullptr)

+ 2 - 1
Code/Tools/SceneAPI/SceneCore/Containers/Scene.h

@@ -26,7 +26,8 @@ namespace AZ
             {
             {
             public:
             public:
                 AZ_TYPE_INFO(Scene, "{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}");
                 AZ_TYPE_INFO(Scene, "{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}");
-                
+
+                Scene() = default;
                 explicit Scene(const AZStd::string& name);
                 explicit Scene(const AZStd::string& name);
                 explicit Scene(AZStd::string&& name);
                 explicit Scene(AZStd::string&& name);
 
 

+ 35 - 0
Code/Tools/SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/RTTI/RTTI.h>
+#include <SceneAPI/SceneCore/DataTypes/Groups/ISceneNodeGroup.h>
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
+
+namespace AZ::SceneAPI::DataTypes
+{
+    class IImportGroup
+        : public ISceneNodeGroup
+    {
+    public:
+        AZ_RTTI(IImportGroup, "{CF09F740-5A5A-4865-A9A7-FAD1A70C045E}", ISceneNodeGroup);
+
+        ~IImportGroup() override = default;
+
+        //! Settings registry key that contains the default values to use for import settings.
+        //! These can either be set in a setreg file or programmatically by saving into the current settings registry.
+        //! These settings will be overridden by any settings that exist in the .assetinfo file.
+        static inline constexpr const char SceneImportSettingsRegistryKey[] = "/O3DE/Preferences/SceneAPI/ImportSettings";
+
+        //! Get the import settings stored in the Import Group.
+        virtual const SceneImportSettings& GetImportSettings() const = 0;
+
+        //! Set the import settings in this Import Group.
+        virtual void SetImportSettings(const SceneImportSettings& importSettings) = 0;
+    };
+}

+ 6 - 0
Code/Tools/SceneAPI/SceneCore/DllMain.cpp

@@ -29,6 +29,7 @@
 #include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
 #include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
 
 
 #include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
+#include <SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/ISkeletonGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/ISkeletonGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
 #include <SceneAPI/SceneCore/DataTypes/Groups/ISkinGroup.h>
@@ -55,6 +56,7 @@
 
 
 #include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
 #include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
 #include <SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h>
 #include <SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h>
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
 #include <SceneAPI/SceneCore/Utilities/PatternMatcher.h>
 #include <SceneAPI/SceneCore/Utilities/PatternMatcher.h>
 #include <SceneAPI/SceneCore/Utilities/Reporting.h>
 #include <SceneAPI/SceneCore/Utilities/Reporting.h>
 
 
@@ -158,6 +160,7 @@ namespace AZ
                     context->Class<AZ::SceneAPI::DataTypes::ISkeletonGroup, AZ::SceneAPI::DataTypes::IGroup>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::ISkeletonGroup, AZ::SceneAPI::DataTypes::IGroup>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::ISkinGroup, AZ::SceneAPI::DataTypes::ISceneNodeGroup>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::ISkinGroup, AZ::SceneAPI::DataTypes::ISceneNodeGroup>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::IAnimationGroup, AZ::SceneAPI::DataTypes::IGroup>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::IAnimationGroup, AZ::SceneAPI::DataTypes::IGroup>()->Version(1);
+                    context->Class<AZ::SceneAPI::DataTypes::IImportGroup, AZ::SceneAPI::DataTypes::ISceneNodeGroup>()->Version(0);
 
 
                     // Register rule interfaces
                     // Register rule interfaces
                     context->Class<AZ::SceneAPI::DataTypes::IRule, AZ::SceneAPI::DataTypes::IManifestObject>()->Version(1);
                     context->Class<AZ::SceneAPI::DataTypes::IRule, AZ::SceneAPI::DataTypes::IManifestObject>()->Version(1);
@@ -191,6 +194,9 @@ namespace AZ
                     // Register utilities
                     // Register utilities
                     AZ::SceneAPI::SceneCore::PatternMatcher::Reflect(context);
                     AZ::SceneAPI::SceneCore::PatternMatcher::Reflect(context);
                     AZ::SceneAPI::Utilities::DebugSceneGraph::Reflect(context);
                     AZ::SceneAPI::Utilities::DebugSceneGraph::Reflect(context);
+
+                    // Register import settings
+                    AZ::SceneAPI::SceneImportSettings::Reflect(context);
                 }
                 }
             }
             }
 
 

+ 5 - 3
Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h

@@ -17,14 +17,15 @@ namespace AZ
     {
     {
         namespace Import
         namespace Import
         {
         {
-            class ManifestImportRequestHandler
+            class SCENE_CORE_CLASS ManifestImportRequestHandler
                 : public SceneCore::BehaviorComponent
                 : public SceneCore::BehaviorComponent
                 , public Events::AssetImportRequestBus::Handler
                 , public Events::AssetImportRequestBus::Handler
             {
             {
             public:
             public:
                 AZ_COMPONENT(ManifestImportRequestHandler, "{6CF0520E-D5A9-4003-81A5-F20D62010E6F}", SceneCore::BehaviorComponent);
                 AZ_COMPONENT(ManifestImportRequestHandler, "{6CF0520E-D5A9-4003-81A5-F20D62010E6F}", SceneCore::BehaviorComponent);
 
 
-                ~ManifestImportRequestHandler() override = default;
+                SCENE_CORE_API ManifestImportRequestHandler() = default;
+                SCENE_CORE_API ~ManifestImportRequestHandler() override = default;
 
 
                 void Activate() override;
                 void Activate() override;
                 void Deactivate() override;
                 void Deactivate() override;
@@ -32,7 +33,8 @@ namespace AZ
 
 
                 void GetManifestExtension(AZStd::string& result) override;
                 void GetManifestExtension(AZStd::string& result) override;
                 void GetGeneratedManifestExtension(AZStd::string& result) override;
                 void GetGeneratedManifestExtension(AZStd::string& result) override;
-                Events::LoadingResult LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid,
+                SCENE_CORE_API Events::LoadingResult LoadAsset(
+                    Containers::Scene& scene, const AZStd::string& path, const Uuid& guid,
                     RequestingApplication requester) override;
                     RequestingApplication requester) override;
                 void GetPolicyName(AZStd::string& result) const override
                 void GetPolicyName(AZStd::string& result) const override
                 {
                 {

+ 46 - 0
Code/Tools/SceneAPI/SceneCore/Import/SceneImportSettings.cpp

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#include <SceneAPI/SceneCore/Import/SceneImportSettings.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+
+namespace AZ::SceneAPI
+{
+    void SceneImportSettings::Reflect(ReflectContext* context)
+    {
+        if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context); serializeContext)
+        {
+            serializeContext->Class<SceneImportSettings>()
+                ->Version(0)
+                ->Field("OptimizeScene", &SceneImportSettings::m_optimizeScene)
+                ->Field("OptimizeMeshes", &SceneImportSettings::m_optimizeMeshes);
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext(); editContext)
+            {
+                editContext->Class<SceneImportSettings>("Import Settings", "")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute("AutoExpand", true)
+                    ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default,
+                        &SceneImportSettings::m_optimizeScene,
+                        "Collapse/Join Scene Nodes",
+                        "Nodes without animations, bones, lights, or cameras assigned are collapsed and joined. "
+                        "This is useful for non-optimized files that have hundreds or thousands of nodes within them that aren't "
+                        "needed to remain separate in O3DE. This should not be used on files where the nodes need to remain separate "
+                        "for individual submesh control and transformations.")
+                    ->DataElement(
+                        AZ::Edit::UIHandlers::Default,
+                        &SceneImportSettings::m_optimizeMeshes,
+                        "Merge Duplicate Meshes",
+                        "Non-instanced unskinned meshes with the same vertices and faces are merged into instanced meshes. "
+                        "This will reduce the number of draw calls in the scene.");
+            }
+        }
+    }
+}// namespace AZ::SceneAPI

+ 30 - 0
Code/Tools/SceneAPI/SceneCore/Import/SceneImportSettings.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <AzCore/RTTI/RTTI.h>
+
+namespace AZ
+{
+    class ReflectContext;
+} // namespace AZ
+
+namespace AZ::SceneAPI
+{
+    struct SceneImportSettings
+    {
+    public:
+        AZ_RTTI(SceneImportSettings, "{C91CB428-5081-439B-AC40-6149624832D4}");
+        virtual ~SceneImportSettings() = default;
+
+        static void Reflect(ReflectContext* context);
+
+        bool m_optimizeScene = false;
+        bool m_optimizeMeshes = false;
+    };
+} //namespace AZ::SceneAPI

+ 3 - 0
Code/Tools/SceneAPI/SceneCore/scenecore_files.cmake

@@ -28,6 +28,7 @@ set(FILES
     DataTypes/GraphData/IAnimationData.h
     DataTypes/GraphData/IAnimationData.h
     DataTypes/GraphData/IBlendShapeData.h
     DataTypes/GraphData/IBlendShapeData.h
     DataTypes/Groups/IGroup.h
     DataTypes/Groups/IGroup.h
+    DataTypes/Groups/IImportGroup.h
     DataTypes/Groups/ISceneNodeGroup.h
     DataTypes/Groups/ISceneNodeGroup.h
     DataTypes/Groups/IMeshGroup.h
     DataTypes/Groups/IMeshGroup.h
     DataTypes/Groups/ISkeletonGroup.h
     DataTypes/Groups/ISkeletonGroup.h
@@ -119,6 +120,8 @@ set(FILES
     Events/SceneSerializationBus.h
     Events/SceneSerializationBus.h
     Import/ManifestImportRequestHandler.h
     Import/ManifestImportRequestHandler.h
     Import/ManifestImportRequestHandler.cpp
     Import/ManifestImportRequestHandler.cpp
+    Import/SceneImportSettings.h
+    Import/SceneImportSettings.cpp
     Utilities/CoordinateSystemConverter.h
     Utilities/CoordinateSystemConverter.h
     Utilities/CoordinateSystemConverter.cpp
     Utilities/CoordinateSystemConverter.cpp
     Utilities/SceneGraphSelector.h
     Utilities/SceneGraphSelector.h

+ 101 - 0
Code/Tools/SceneAPI/SceneData/Behaviors/BehaviorsImportGroup.cpp

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/std/smart_ptr/make_shared.h>
+#include <SceneAPI/SceneCore/Containers/Scene.h>
+#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
+#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
+#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
+#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
+#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
+#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
+#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
+#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
+#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
+#include <SceneAPI/SceneData/Groups/ImportGroup.h>
+#include <SceneAPI/SceneData/Behaviors/ImportGroup.h>
+
+namespace AZ::SceneAPI::Behaviors
+{
+    // This is set to an extremely low number to help ensure that it appears first in the list of tabs
+    // in the FBX Settings panel. Since these settings are applied before any of the other settings, they
+    // seem like the first ones that the user should be presented with.
+    const int ImportGroup::s_importGroupPreferredTabOrder = -1000000;
+
+    void ImportGroup::Activate()
+    {
+        Events::ManifestMetaInfoBus::Handler::BusConnect();
+        Events::AssetImportRequestBus::Handler::BusConnect();
+    }
+
+    void ImportGroup::Deactivate()
+    {
+        Events::AssetImportRequestBus::Handler::BusDisconnect();
+        Events::ManifestMetaInfoBus::Handler::BusDisconnect();
+    }
+
+    void ImportGroup::Reflect(ReflectContext* context)
+    {
+        SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
+        if (serializeContext)
+        {
+            serializeContext->Class<ImportGroup, BehaviorComponent>()->Version(1);
+        }
+    }
+
+    void ImportGroup::GetCategoryAssignments(
+        [[maybe_unused]] CategoryRegistrationList& categories, [[maybe_unused]] const Containers::Scene& scene)
+    {
+        // The Import Group settings can be made visible and editable in the Asset Browser Inspector by uncommenting
+        // the following line. However, it is currently disabled because changing the settings causes things to break.
+        // Specifically, in the Mesh Group and the PhysX Group, the settings rely on a list of selected and unselected
+        // nodes. Changing the Import optimizations settings will change what nodes exist in the scene, so those lists
+        // will no longer be valid and need to be reset. Also, the various UX widgets for those groups builds up lists
+        // of nodes to populate the dropdown lists with. Those will all need to get refreshed. Finally, if Proc Prefabs
+        // are enabled, the set of mesh groups to export for the Proc Prefab will also need to change to match the new
+        // list of meshes.
+                
+        //categories.emplace_back("Import", SceneData::ImportGroup::TYPEINFO_Uuid(), s_importGroupPreferredTabOrder);
+    }
+
+    void ImportGroup::InitializeObject(
+        [[maybe_unused]] const Containers::Scene& scene, [[maybe_unused]] DataTypes::IManifestObject& target)
+    {
+        if (!target.RTTI_IsTypeOf(SceneData::ImportGroup::TYPEINFO_Uuid()))
+        {
+            return;
+        }
+    }
+
+    Events::ProcessingResult ImportGroup::UpdateManifest(
+        Containers::Scene& scene, [[maybe_unused]] ManifestAction action,
+        [[maybe_unused]] RequestingApplication requester)
+    {
+        // ignore empty scenes (i.e. only has the root node)
+        if (scene.GetGraph().GetNodeCount() == 1)
+        {
+            return Events::ProcessingResult::Ignored;
+        }
+
+        // If there's already an ImportGroup in the manifest, leave it there and return.
+        size_t count = scene.GetManifest().GetEntryCount();
+        for (size_t index = 0; index < count; index++)
+        {
+            if (auto* importGroup = azrtti_cast<DataTypes::IImportGroup*>(scene.GetManifest().GetValue(index).get()); importGroup)
+            {
+                return Events::ProcessingResult::Success;
+            }
+        }
+
+        // There's no ImportGroup yet, so add one.
+        auto importGroup = AZStd::make_shared<SceneData::ImportGroup>();
+        scene.GetManifest().AddEntry(importGroup);
+        return Events::ProcessingResult::Success;
+    }
+} // namespace AZ::SceneAPI::Behaviors

+ 43 - 0
Code/Tools/SceneAPI/SceneData/Behaviors/ImportGroup.h

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <SceneAPI/SceneCore/Components/BehaviorComponent.h>
+#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
+#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
+
+namespace AZ::SceneAPI::Behaviors
+{
+    class ImportGroup 
+        : public SceneCore::BehaviorComponent
+        , public Events::ManifestMetaInfoBus::Handler
+        , public Events::AssetImportRequestBus::Handler
+    {
+    public:
+        AZ_COMPONENT(ImportGroup, "{209DF1FB-449F-403A-A468-32A775289AF8}", SceneCore::BehaviorComponent);
+
+        ~ImportGroup() override = default;
+
+        void Activate() override;
+        void Deactivate() override;
+        static void Reflect(ReflectContext* context);
+
+        void GetCategoryAssignments(CategoryRegistrationList& categories, const Containers::Scene& scene) override;
+        void InitializeObject(const Containers::Scene& scene, DataTypes::IManifestObject& target) override;
+        Events::ProcessingResult UpdateManifest(Containers::Scene& scene, ManifestAction action,
+            RequestingApplication requester) override;
+        void GetPolicyName(AZStd::string& result) const override
+        {
+            result = "SceneAPI::ImportGroup";
+        }
+
+    private:
+        static const int s_importGroupPreferredTabOrder;
+    };
+} // namespace AZ::SceneAPI::Behaviors

+ 2 - 0
Code/Tools/SceneAPI/SceneData/Behaviors/Registry.cpp

@@ -13,6 +13,7 @@
 #include <SceneAPI/SceneData/Behaviors/LodRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/LodRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/MaterialRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/MaterialRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/MeshAdvancedRule.h>
 #include <SceneAPI/SceneData/Behaviors/MeshAdvancedRule.h>
+#include <SceneAPI/SceneData/Behaviors/ImportGroup.h>
 #include <SceneAPI/SceneData/Behaviors/MeshGroup.h>
 #include <SceneAPI/SceneData/Behaviors/MeshGroup.h>
 #include <SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h>
 #include <SceneAPI/SceneData/Behaviors/SkeletonGroup.h>
 #include <SceneAPI/SceneData/Behaviors/SkeletonGroup.h>
@@ -33,6 +34,7 @@ namespace AZ
                     BlendShapeRuleBehavior::CreateDescriptor(),
                     BlendShapeRuleBehavior::CreateDescriptor(),
                     LodRuleBehavior::CreateDescriptor(),
                     LodRuleBehavior::CreateDescriptor(),
                     MaterialRuleBehavior::CreateDescriptor(),
                     MaterialRuleBehavior::CreateDescriptor(),
+                    Behaviors::ImportGroup::CreateDescriptor(),
                     Behaviors::MeshAdvancedRule::CreateDescriptor(),
                     Behaviors::MeshAdvancedRule::CreateDescriptor(),
                     Behaviors::MeshGroup::CreateDescriptor(),
                     Behaviors::MeshGroup::CreateDescriptor(),
                     Behaviors::ScriptProcessorRuleBehavior::CreateDescriptor(),
                     Behaviors::ScriptProcessorRuleBehavior::CreateDescriptor(),

+ 89 - 0
Code/Tools/SceneAPI/SceneData/Groups/ImportGroup.cpp

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <SceneAPI/SceneData/Groups/ImportGroup.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/RTTI/BehaviorContext.h>
+
+namespace AZ::SceneAPI::SceneData
+{
+    ImportGroup::ImportGroup()
+        : m_name("Import Settings")
+        , m_id(Uuid::CreateRandom())
+    {
+    }
+
+    const AZStd::string& ImportGroup::GetName() const
+    {
+        return m_name;
+    }
+
+    const Uuid& ImportGroup::GetId() const
+    {
+        return m_id;
+    }
+
+    Containers::RuleContainer& ImportGroup::GetRuleContainer()
+    {
+        return m_rules;
+    }
+
+    const Containers::RuleContainer& ImportGroup::GetRuleContainerConst() const
+    {
+        return m_rules;
+    }
+
+    DataTypes::ISceneNodeSelectionList& ImportGroup::GetSceneNodeSelectionList()
+    {
+        return m_nodeSelectionList;
+    }
+
+    const DataTypes::ISceneNodeSelectionList& ImportGroup::GetSceneNodeSelectionList() const
+    {
+        return m_nodeSelectionList;
+    }
+
+    const SceneImportSettings& ImportGroup::GetImportSettings() const
+    {
+        return m_importSettings;
+    }
+
+    void ImportGroup::SetImportSettings(const SceneImportSettings& importSettings)
+    {
+        m_importSettings = importSettings;
+    }
+
+    void ImportGroup::Reflect(ReflectContext* context)
+    {
+        if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context); serializeContext)
+        {
+            serializeContext->Class<ImportGroup, DataTypes::IImportGroup>()
+                ->Version(0)
+                ->Field("ImportSettings", &ImportGroup::m_importSettings)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext(); editContext)
+            {
+                editContext->Class<ImportGroup>("Import Settings",
+                        "The import group controls the Asset Importer settings. "
+                        "These settings affect how the source data is processed before being handled by the scene exporters.")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                        ->Attribute("AutoExpand", true)
+                        ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
+                        ->Attribute(AZ::Edit::Attributes::Max, 1)
+                        ->Attribute(AZ::Edit::Attributes::CategoryStyle, "display divider")
+                        ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://www.o3de.org/docs/user-guide/assets/scene-settings/")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &ImportGroup::m_importSettings,
+                        "Import Settings",
+                        "Settings that affect how the scene data is transformed when it is read in.")
+                ;
+            }
+        }
+    }
+}

+ 53 - 0
Code/Tools/SceneAPI/SceneData/Groups/ImportGroup.h

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include <SceneAPI/SceneCore/DataTypes/Groups/IImportGroup.h>
+#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
+#include <SceneAPI/SceneData/ManifestBase/SceneNodeSelectionList.h>
+
+namespace AZ
+{
+    class ReflectContext;
+}
+
+namespace AZ::SceneAPI::SceneData
+{
+    class SCENE_DATA_CLASS ImportGroup final
+        : public DataTypes::IImportGroup
+    {
+    public:
+        AZ_RTTI(ImportGroup, "{41DCBEAB-203C-4A05-96FA-98E1D8A96FA1}", DataTypes::IImportGroup);
+        AZ_CLASS_ALLOCATOR(ImportGroup, SystemAllocator);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        SCENE_DATA_API ImportGroup();
+        SCENE_DATA_API ~ImportGroup() override = default;
+
+        SCENE_DATA_API const AZStd::string& GetName() const override;
+        SCENE_DATA_API const Uuid& GetId() const override;
+
+        SCENE_DATA_API Containers::RuleContainer& GetRuleContainer() override;
+        SCENE_DATA_API const Containers::RuleContainer& GetRuleContainerConst() const override;
+
+        SCENE_DATA_API DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList() override;
+        SCENE_DATA_API const DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList() const override;
+
+        SCENE_DATA_API const SceneImportSettings& GetImportSettings() const override;
+        SCENE_DATA_API void SetImportSettings(const SceneImportSettings& importSettings) override;
+
+    private:
+        SceneImportSettings m_importSettings;
+
+        SceneNodeSelectionList m_nodeSelectionList;
+        Containers::RuleContainer m_rules;
+        AZStd::string m_name;
+        Uuid m_id;
+    };
+}

+ 2 - 0
Code/Tools/SceneAPI/SceneData/ReflectionRegistrar.cpp

@@ -7,6 +7,7 @@
  */
  */
 
 
 #include <SceneAPI/SceneData/ReflectionRegistrar.h>
 #include <SceneAPI/SceneData/ReflectionRegistrar.h>
+#include <SceneAPI/SceneData/Groups/ImportGroup.h>
 #include <SceneAPI/SceneData/Groups/MeshGroup.h>
 #include <SceneAPI/SceneData/Groups/MeshGroup.h>
 #include <SceneAPI/SceneData/Groups/SkeletonGroup.h>
 #include <SceneAPI/SceneData/Groups/SkeletonGroup.h>
 #include <SceneAPI/SceneData/Groups/SkinGroup.h>
 #include <SceneAPI/SceneData/Groups/SkinGroup.h>
@@ -60,6 +61,7 @@ namespace AZ
             }
             }
 
 
             // Groups
             // Groups
+            SceneData::ImportGroup::Reflect(context);
             SceneData::MeshGroup::Reflect(context);
             SceneData::MeshGroup::Reflect(context);
             SceneData::SkeletonGroup::Reflect(context);
             SceneData::SkeletonGroup::Reflect(context);
             SceneData::SkinGroup::Reflect(context);
             SceneData::SkinGroup::Reflect(context);

+ 4 - 0
Code/Tools/SceneAPI/SceneData/SceneData_files.cmake

@@ -13,11 +13,13 @@ set(FILES
     ManifestMetaInfoHandler.cpp
     ManifestMetaInfoHandler.cpp
     ReflectionRegistrar.h
     ReflectionRegistrar.h
     ReflectionRegistrar.cpp
     ReflectionRegistrar.cpp
+    Behaviors/BehaviorsImportGroup.cpp
     Behaviors/BehaviorsMeshGroup.cpp
     Behaviors/BehaviorsMeshGroup.cpp
     Behaviors/BehaviorsSkeletonGroup.cpp
     Behaviors/BehaviorsSkeletonGroup.cpp
     Behaviors/BehaviorsSkinGroup.cpp
     Behaviors/BehaviorsSkinGroup.cpp
     Behaviors/Registry.h
     Behaviors/Registry.h
     Behaviors/Registry.cpp
     Behaviors/Registry.cpp
+    Behaviors/ImportGroup.h
     Behaviors/MeshGroup.h
     Behaviors/MeshGroup.h
     Behaviors/SkeletonGroup.h
     Behaviors/SkeletonGroup.h
     Behaviors/SkinGroup.h
     Behaviors/SkinGroup.h
@@ -35,6 +37,8 @@ set(FILES
     Behaviors/SkinRuleBehavior.cpp
     Behaviors/SkinRuleBehavior.cpp
     Behaviors/ScriptProcessorRuleBehavior.h
     Behaviors/ScriptProcessorRuleBehavior.h
     Behaviors/ScriptProcessorRuleBehavior.cpp
     Behaviors/ScriptProcessorRuleBehavior.cpp
+    Groups/ImportGroup.h
+    Groups/ImportGroup.cpp
     Groups/MeshGroup.h
     Groups/MeshGroup.h
     Groups/MeshGroup.cpp
     Groups/MeshGroup.cpp
     Groups/SkeletonGroup.h
     Groups/SkeletonGroup.h

+ 1 - 1
Code/Tools/SceneAPI/SceneUI/SceneWidgets/ManifestWidget.cpp

@@ -166,7 +166,7 @@ namespace AZ
                 AZStd::sort(categories.begin(), categories.end(), 
                 AZStd::sort(categories.begin(), categories.end(), 
                     [](const Events::ManifestMetaInfo::CategoryRegistration& lhs, const Events::ManifestMetaInfo::CategoryRegistration& rhs)
                     [](const Events::ManifestMetaInfo::CategoryRegistration& lhs, const Events::ManifestMetaInfo::CategoryRegistration& rhs)
                     {
                     {
-                        return (rhs.m_preferredOrder - lhs.m_preferredOrder) > 0;
+                        return rhs.m_preferredOrder > lhs.m_preferredOrder;
                     }
                     }
                 );
                 );
 
 

+ 10 - 0
Gems/SceneProcessing/Code/Source/Generation/Components/MeshOptimizer/MeshOptimizerComponent.cpp

@@ -384,6 +384,16 @@ namespace AZ::SceneGenerationComponents
 
 
             for (const IMeshGroup& meshGroup : meshGroups)
             for (const IMeshGroup& meshGroup : meshGroups)
             {
             {
+                if (!selectedNodes.contains(&meshGroup))
+                {
+                    AZ_Warning(
+                        AZ::SceneAPI::Utilities::LogWindow,
+                        false,
+                        "MeshGroup %s wasn't found in the list of selected nodes.",
+                        meshGroup.GetName().c_str());
+                    continue;
+                }
+
                 // Skip meshes that are not used by this mesh group
                 // Skip meshes that are not used by this mesh group
                 if (AZStd::find(selectedNodes.at(&meshGroup).cbegin(), selectedNodes.at(&meshGroup).cend(), nodePath) == selectedNodes.at(&meshGroup).cend())
                 if (AZStd::find(selectedNodes.at(&meshGroup).cbegin(), selectedNodes.at(&meshGroup).cend(), nodePath) == selectedNodes.at(&meshGroup).cend())
                 {
                 {