Prechádzať zdrojové kódy

Bugfix: Add source extension to model/material/physics mesh product assets (#16517)

* Fix AP view to only show the final extension, not all extensions.

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

* Change meshes and materials generated from scene-based files to retain their source file extension in the product name.

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

* Bumped version numbers.

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

* PR feedback - bumped engine tool version number

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

* PR feedback - string to string_view

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

* Removed unnecessary const

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

* Fix up python tests for new product asset names

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

---------

Signed-off-by: Mike Balfour <[email protected]>
Mike Balfour 2 rokov pred
rodič
commit
a9d33a6517
82 zmenil súbory, kde vykonal 216 pridanie a 142 odobranie
  1. 2 2
      AutomatedTesting/Editor/Scripts/auto_lod.py
  2. 3 3
      AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py
  3. 2 2
      AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
  4. 1 1
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HairAdded.py
  5. 3 3
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py
  6. 5 5
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py
  7. 2 2
      AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py
  8. 1 1
      AutomatedTesting/Gem/PythonTests/EditorPythonBindings/tests/Editor_ComponentAssetCommands_Works.py
  9. 1 1
      AutomatedTesting/Gem/PythonTests/Physics/TestSuite_InDevelopment.py
  10. 1 1
      AutomatedTesting/Gem/PythonTests/Physics/tests/EntityComponentTests/PhysX_Mesh_Collider_Component_CRUD.py
  11. 2 2
      AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_MultipleSurfaceSlots.py
  12. 2 2
      AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshAutoAssignedWhenAddingRenderMeshComponent.py
  13. 1 1
      AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshAutoAssignedWhenModifyingRenderMeshComponent.py
  14. 1 1
      AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshConvexMeshCollides.py
  15. 1 1
      AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshNotAutoAssignedWhenNoPhysicsFbx.py
  16. 7 7
      AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test.py
  17. 7 7
      AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py
  18. 6 6
      AutomatedTesting/Gem/PythonTests/assetpipeline/asset_bundler_tests/asset_bundler_batch_tests.py
  19. 1 1
      AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py
  20. 1 1
      AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/hydra_SubID_NoChange_MeshChanged.py
  21. 1 1
      AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/hydra_SubID_WarningReported_AssetRemoved.py
  22. 3 3
      AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py
  23. 1 1
      AutomatedTesting/Gem/PythonTests/editor/EditorScripts/DPE_AllComponentPropertyTypesEditable.py
  24. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py
  25. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py
  26. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py
  27. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py
  28. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py
  29. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py
  30. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py
  31. 6 6
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py
  32. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py
  33. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py
  34. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py
  35. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py
  36. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py
  37. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py
  38. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py
  39. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py
  40. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py
  41. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py
  42. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py
  43. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py
  44. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py
  45. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py
  46. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py
  47. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py
  48. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py
  49. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py
  50. 2 2
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py
  51. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py
  52. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py
  53. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py
  54. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py
  55. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py
  56. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py
  57. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py
  58. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py
  59. 1 1
      AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
  60. 1 1
      Code/Tools/AssetProcessor/native/ui/AssetTreeItem.cpp
  61. 6 0
      Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp
  62. 1 0
      Code/Tools/SceneAPI/SceneCore/Containers/Scene.h
  63. 24 5
      Code/Tools/SceneAPI/SceneCore/Utilities/FileUtilities.cpp
  64. 3 1
      Code/Tools/SceneAPI/SceneCore/Utilities/FileUtilities.h
  65. 1 1
      Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp
  66. 1 1
      Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp
  67. 3 2
      Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp
  68. 1 1
      Gems/Atom/Tools/MaterialCanvas/Code/Source/Window/MaterialCanvasViewportContent.cpp
  69. 1 1
      Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorViewportContent.cpp
  70. 1 1
      Gems/Atom/Tools/PassCanvas/Code/Source/Window/PassCanvasViewportContent.cpp
  71. 1 1
      Gems/AtomLyIntegration/CommonFeatures/Assets/Editor/Scripts/LegacyContentConversion/LegacyMaterialComponentConverter.py
  72. 5 5
      Gems/AtomLyIntegration/CommonFeatures/Assets/Editor/Scripts/LegacyContentConversion/LegacyMeshComponentConverter.py
  73. 1 1
      Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp
  74. 14 1
      Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp
  75. 15 1
      Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp
  76. 8 1
      Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp
  77. 3 2
      Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp
  78. 7 7
      Gems/Prefab/PrefabBuilder/PrefabGroup/DefaultProceduralPrefab.cpp
  79. 2 1
      Gems/Prefab/PrefabBuilder/PrefabGroup/DefaultProceduralPrefab.h
  80. 12 3
      Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp
  81. 1 1
      Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py
  82. 1 1
      engine.json

+ 2 - 2
AutomatedTesting/Editor/Scripts/auto_lod.py

@@ -79,11 +79,11 @@ def update_manifest(scene):
     # Add an EditorMeshComponent to the entity
     editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
     # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
-    # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
+    # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.fbx.azmodel
     # The assetHint will be converted to an AssetId later during prefab loading
     json_update = json.dumps({
         "Controller": { "Configuration": { "ModelAsset": {
-            "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
+            "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".fbx.azmodel" }}}
         });
     # Apply the JSON above to the component we created
     result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)

+ 3 - 3
AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py

@@ -151,10 +151,10 @@ def update_manifest(scene):
                                                                entity_id, "AZ::Render::EditorMeshComponent")
         # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just
         # created + the azmodel extension The MeshGroup we created will be output as a product in the asset's path
-        # named mesh_group_name.azmodel The assetHint will be converted to an AssetId later during prefab loading
+        # named mesh_group_name.fbx.azmodel The assetHint will be converted to an AssetId later during prefab loading
         json_update = json.dumps({
             "Controller": {"Configuration": {"ModelAsset": {
-                "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel"}}}
+                "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".fbx.azmodel"}}}
         })
         # Apply the JSON above to the component we created
         result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
@@ -172,7 +172,7 @@ def update_manifest(scene):
                 "ShapeConfiguration": {
                     "PhysicsAsset": {
                         "Asset": {
-                            "assetHint": os.path.join(source_relative_path, source_filename_only + "_triangle.pxmesh")
+                            "assetHint": os.path.join(source_relative_path, source_filename_only + "_triangle.fbx.pxmesh")
                         }
                     }
                 }

+ 2 - 2
AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py

@@ -184,7 +184,7 @@ def create_basic_atom_rendering_scene():
     ground_plane_material_component = ground_plane_entity.add_component(AtomComponentProperties.material())
     ground_plane_entity.set_local_uniform_scale(32.0)
     ground_plane_mesh_component = ground_plane_entity.add_component(AtomComponentProperties.mesh())
-    ground_plane_mesh_asset_path = os.path.join("testdata", "objects", "plane.azmodel")
+    ground_plane_mesh_asset_path = os.path.join("testdata", "objects", "plane.fbx.azmodel")
     ground_plane_mesh_asset = Asset.find_asset_by_path(ground_plane_mesh_asset_path, False)
     ground_plane_mesh_component.set_component_property_value(
         AtomComponentProperties.mesh('Model Asset'), ground_plane_mesh_asset.id)
@@ -204,7 +204,7 @@ def create_basic_atom_rendering_scene():
     sphere_entity = EditorEntity.create_editor_entity_at(
         math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id)
     sphere_mesh_component = sphere_entity.add_component(AtomComponentProperties.mesh())
-    sphere_mesh_asset_path = os.path.join("models", "sphere.azmodel")
+    sphere_mesh_asset_path = os.path.join("models", "sphere.fbx.azmodel")
     sphere_mesh_asset = Asset.find_asset_by_path(sphere_mesh_asset_path, False)
     sphere_mesh_component.set_component_property_value(
         AtomComponentProperties.mesh('Model Asset'), sphere_mesh_asset.id)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HairAdded.py

@@ -354,7 +354,7 @@ def AtomEditorComponents_Hair_AddedToEntity():
         Report.result(Tests.hair_enabled, hair_component.is_enabled())
 
         # 8. Set assets for Actor and Hair
-        head_path = os.path.join('testdata', 'headbonechainhairstyle', 'test_hair_bone_chain_head_style.azmodel')
+        head_path = os.path.join('testdata', 'headbonechainhairstyle', 'test_hair_bone_chain_head_style.fbx.azmodel')
         head_asset = Asset.find_asset_by_path(head_path)
         hair_path = os.path.join('testdata', 'headbonechainhairstyle', 'test_hair_bone_chain_head_style.tfxhair')
         hair_asset = Asset.find_asset_by_path(hair_path)

+ 3 - 3
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py

@@ -218,12 +218,12 @@ def AtomEditorComponents_Material_AddedToEntity():
 
         # 12. Set a model asset to Mesh component
         # Set a simple model to ensure that the more complex model will load cleanly
-        model_path = os.path.join('objects', 'cube.azmodel')
+        model_path = os.path.join('objects', 'cube.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
         mesh_component.set_component_property_value(AtomComponentProperties.mesh('Model Asset'), model.id)
         general.idle_wait_frames(1)
         # Update model asset to a model with 5 LOD materials
-        model_path = os.path.join('testdata', 'objects', 'modelhotreload', 'sphere_5lods.azmodel')
+        model_path = os.path.join('testdata', 'objects', 'modelhotreload', 'sphere_5lods.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
         mesh_component.set_component_property_value(AtomComponentProperties.mesh('Model Asset'), model.id)
         general.idle_wait_frames(1)
@@ -242,7 +242,7 @@ def AtomEditorComponents_Material_AddedToEntity():
         # .\o3de\Gems\AtomLyIntegration\CommonFeatures\Code\Source\Material\EditorMaterialComponentSlot.cpp
         label = item.GetLabel()
         Report.result(Tests.model_material_label, label == 'lambert0')
-        # Asset path for lambert0 is 'objects/sphere_5lods_lambert0_11781189446760285338.azmaterial'; numbers may vary
+        # Asset path for lambert0 is 'objects/sphere_5lods_lambert0_11781189446760285338.fbx.azmaterial'; numbers may vary
         default_asset = Asset(item.GetDefaultAssetId())
         default_asset_path = default_asset.get_path()
         Report.result(

+ 5 - 5
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py

@@ -79,10 +79,10 @@ class Tests:
         "Mesh component removed successfully",
         "P1: Mesh component was not correctly removed from the entity")
     model_asset_is_optimized = (
-        "tube.azmodel has <= 66 vertices",
+        "tube.fbx.azmodel has <= 66 vertices",
         "P0: Model has not been fully optimized")
     model_different_bone_ids_same_position_should_weld_vertices = (
-        "sameposition_differentboneIds_shouldnotweldvertices.azmodel has 48 vertices",
+        "sameposition_differentboneIds_shouldnotweldvertices.fbx.azmodel has 48 vertices",
         "P0: Vertices were welded when they shouldnt be")
 
 
@@ -215,7 +215,7 @@ def AtomEditorComponents_Mesh_AddedToEntity():
         Report.result(Tests.creation_redo, mesh_entity.exists())
 
         # 5. Set Mesh component asset property
-        model_path = os.path.join('testdata', 'objects', 'modelhotreload', 'sphere_5lods.azmodel')
+        model_path = os.path.join('testdata', 'objects', 'modelhotreload', 'sphere_5lods.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
         mesh_component.set_component_property_value(AtomComponentProperties.mesh('Model Asset'), model.id)
         Report.result(Tests.model_asset_specified,
@@ -326,7 +326,7 @@ def AtomEditorComponents_Mesh_AddedToEntity():
         Report.result(Tests.is_visible, mesh_entity.is_visible() is True)
         
         # 21. Test that vertex welding is functioning
-        model_path = os.path.join('testdata', 'objects', 'tube.azmodel')
+        model_path = os.path.join('testdata', 'objects', 'tube.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
         onModelReadyHelper = OnModelReadyHelper()
         onModelReadyHelper.wait_for_on_model_ready(mesh_entity.id, mesh_component, model.id)
@@ -339,7 +339,7 @@ def AtomEditorComponents_Mesh_AddedToEntity():
                           AtomComponentProperties.mesh('Vertex Count LOD0')) <= 66)
 
         # 22. Test that vertices with the same position but different boneId's aren't unintentionally welded
-        model_path = os.path.join('testdata', 'objects', 'skinnedmesh', 'meshoptimization', 'sameposition_differentjointids_shouldnotweldvertices.azmodel')
+        model_path = os.path.join('testdata', 'objects', 'skinnedmesh', 'meshoptimization', 'sameposition_differentjointids_shouldnotweldvertices.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
         onModelReadyHelper = OnModelReadyHelper()
         onModelReadyHelper.wait_for_on_model_ready(mesh_entity.id, mesh_component, model.id)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py

@@ -245,7 +245,7 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel():
         # 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Model Asset property.
         ground_plane_mesh_component = ground_plane_entity.add_component(AtomComponentProperties.mesh())
         Report.result(Tests.mesh_component_added, ground_plane_entity.has_component(AtomComponentProperties.mesh()))
-        ground_plane_model_asset_path = os.path.join("testdata", "objects", "plane.azmodel")
+        ground_plane_model_asset_path = os.path.join("testdata", "objects", "plane.fbx.azmodel")
         ground_plane_model_asset = Asset.find_asset_by_path(ground_plane_model_asset_path, False)
         ground_plane_mesh_component.set_component_property_value(
             AtomComponentProperties.mesh('Model Asset'), ground_plane_model_asset.id)
@@ -283,7 +283,7 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel():
 
         # 18. Add Mesh component to Sphere Entity and set the Model Asset property for the Mesh component.
         sphere_mesh_component = sphere_entity.add_component(AtomComponentProperties.mesh())
-        sphere_model_asset_path = os.path.join("models", "sphere.azmodel")
+        sphere_model_asset_path = os.path.join("models", "sphere.fbx.azmodel")
         sphere_model_asset = Asset.find_asset_by_path(sphere_model_asset_path, False)
         sphere_mesh_component.set_component_property_value(
             AtomComponentProperties.mesh('Model Asset'), sphere_model_asset.id)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/EditorPythonBindings/tests/Editor_ComponentAssetCommands_Works.py

@@ -113,7 +113,7 @@ class Editor_ComponentAssetCommands_Works(BaseClass):
         pte = pteObj.GetValue()
 
         # Tests for the Asset<> case
-        testAssetId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'assets/objects/foliage/cedar.azmodel', math.Uuid(), False)
+        testAssetId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'assets/objects/foliage/cedar.fbx.azmodel', math.Uuid(), False)
         Editor_ComponentAssetCommands_Works.GetSetCompareTest(component, "Controller|Configuration|Model Asset", testAssetId)
         Editor_ComponentAssetCommands_Works.PteTest(pte, "Controller|Configuration|Model Asset", testAssetId)
 

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Physics/TestSuite_InDevelopment.py

@@ -97,7 +97,7 @@ class EditorTestAutomation(EditorTestSuite):
     class Tick_CharacterGameplayComponentMotionIsSmooth(EditorBatchedTest):
         from .tests.tick import Tick_CharacterGameplayComponentMotionIsSmooth as test_module
 
-    @pytest.mark.xfail(reason="AssertionError: Couldn't find Asset with path: Objects/SphereBot/r0-b_body.azmodel")
+    @pytest.mark.xfail(reason="AssertionError: Couldn't find Asset with path: Objects/SphereBot/r0-b_body.fbx.azmodel")
     class Collider_PxMeshAutoAssignedWhenModifyingRenderMeshComponent(EditorBatchedTest):
         from .tests.collider import Collider_PxMeshAutoAssignedWhenModifyingRenderMeshComponent as test_module
 

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Physics/tests/EntityComponentTests/PhysX_Mesh_Collider_Component_CRUD.py

@@ -44,7 +44,7 @@ def PhysX_Mesh_Collider_Component_CRUD():
     from consts.physics import PHYSX_MESH_COLLIDER
 
     # 0) Pre-conditions
-    physx_mesh = os.path.join("objects", "_primitives", "_box_1x1.pxmesh")
+    physx_mesh = os.path.join("objects", "_primitives", "_box_1x1.fbx.pxmesh")
     physx_material = os.path.join("physx", "glass.physxmaterial")
 
     TestHelper.init_idle()

+ 2 - 2
AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_MultipleSurfaceSlots.py

@@ -59,8 +59,8 @@ def Collider_MultipleSurfaceSlots():
     SURFACE_TAG_COUNT = 4  # Number of surface tags included in used asset
 
     # Asset paths
-    STATIC_MESH = os.path.join("assets", "Physics", "Collider_MultipleSurfaceSlots", "test.azmodel")
-    PHYSX_MESH = os.path.join("assets", "Physics","Collider_MultipleSurfaceSlots", "test.pxmesh")
+    STATIC_MESH = os.path.join("assets", "Physics", "Collider_MultipleSurfaceSlots", "test.fbx.azmodel")
+    PHYSX_MESH = os.path.join("assets", "Physics","Collider_MultipleSurfaceSlots", "test.fbx.pxmesh")
 
     # 1) Load the empty level
     hydra.open_base_level()

+ 2 - 2
AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshAutoAssignedWhenAddingRenderMeshComponent.py

@@ -58,9 +58,9 @@ def Collider_PxMeshAutoAssignedWhenAddingRenderMeshComponent():
     import editor_python_test_tools.hydra_editor_utils as hydra
 
     # Asset paths
-    STATIC_MESH = os.path.join("assets", "Physics", "Collider_PxMeshAutoAssigned", "spherebot", "r0-b_body.azmodel")
+    STATIC_MESH = os.path.join("assets", "Physics", "Collider_PxMeshAutoAssigned", "spherebot", "r0-b_body.fbx.azmodel")
     PHYSX_MESH = os.path.join(
-        "assets", "Physics", "Collider_PxMeshAutoAssigned", "spherebot", "r0-b_body.pxmesh"
+        "assets", "Physics", "Collider_PxMeshAutoAssigned", "spherebot", "r0-b_body.fbx.pxmesh"
     )
 
     # 1) Load the empty level

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshAutoAssignedWhenModifyingRenderMeshComponent.py

@@ -59,7 +59,7 @@ def Collider_PxMeshAutoAssignedWhenModifyingRenderMeshComponent():
     # Open 3D Engine Imports
     import azlmbr.legacy.general as general
 
-    MESH_ASSET_PATH = os.path.join("Objects", "SphereBot", "r0-b_body.azmodel")
+    MESH_ASSET_PATH = os.path.join("Objects", "SphereBot", "r0-b_body.fbx.azmodel")
     MESH_PROPERTY_PATH = "Controller|Configuration|Model Asset"
     TESTED_PROPERTY_PATH = "Shape Configuration|Asset|PhysX Mesh"
 

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshConvexMeshCollides.py

@@ -72,7 +72,7 @@ def Collider_PxMeshConvexMeshCollides():
     import azlmbr.legacy.general as general
 
     # Constants
-    MESH_ASSET_PATH = os.path.join("assets", "Physics", "Collider_PxMeshConvexMeshCollides", "spherebot", "r0-b_body.pxmesh")
+    MESH_ASSET_PATH = os.path.join("assets", "Physics", "Collider_PxMeshConvexMeshCollides", "spherebot", "r0-b_body.fbx.pxmesh")
     TIMEOUT = 2.0
 
     # 1) Load the level

+ 1 - 1
AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_PxMeshNotAutoAssignedWhenNoPhysicsFbx.py

@@ -66,7 +66,7 @@ def Collider_PxMeshNotAutoAssignedWhenNoPhysicsFbx():
     import azlmbr.asset as azasset
 
     # Asset paths
-    STATIC_MESH = os.path.join("assets", "Physics", "Collider_PxMeshNotAutoAssignedWhenNoPhysicsFbx", "test_asset.azmodel")
+    STATIC_MESH = os.path.join("assets", "Physics", "Collider_PxMeshNotAutoAssignedWhenNoPhysicsFbx", "test_asset.fbx.azmodel")
 
     # 1) Load the empty level
     hydra.open_base_level()

+ 7 - 7
AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test.py

@@ -50,13 +50,13 @@ def compile_test_case_name(request):
 def find_products(cache_folder, platform):
     con = sqlite3.connect(os.path.join(cache_folder, 'assetdb.sqlite'))
     detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/test_asset.mock_asset')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel')
-    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.fbx.azmodel')
+    detect_product(con, platform, 'gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.fbx.azmodel')
     con.close()
 
 

+ 7 - 7
AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py

@@ -41,13 +41,13 @@ def on_notify_editor_initialized(args):
         else:
             print(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString})!')
 
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel')
-    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.fbx.azmodel')
+    test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.fbx.azmodel')
 
     # clear up notification handler
     global handler

+ 6 - 6
AutomatedTesting/Gem/PythonTests/assetpipeline/asset_bundler_tests/asset_bundler_batch_tests.py

@@ -1124,8 +1124,8 @@ class TestsAssetBundlerBatch(object):
 
         asset_processor.batch_process(platforms=workspace.asset_processor_platform)
         expected_assets = [
-            "objects/cube_lod0.azlod",
-            "objects/cube_lod0_index.azbuffer",
+            "objects/cube_lod0.fbx.azlod",
+            "objects/cube_lod0_index.fbx.azbuffer",
             "resourcepools/defaultvertexbufferpool.pool"
         ]
         # Test Asset Structure:
@@ -1138,10 +1138,10 @@ class TestsAssetBundlerBatch(object):
         # Even if we exclude all parents besides "ParentA", we should still have "CommonChild" since it is a product dependency of "ParentA"
         bundler_batch_helper.call_assetLists(
             assetListFile=bundler_batch_helper['asset_info_file_request'],
-            addSeed="objects/cube_lod0.azlod",
-            skip="objects/cube_lod0_position0.azbuffer, objects/cube_lod0_tangent0.azbuffer,"
-                 "objects/cube_lod0_normal0.azbuffer, objects/cube_lod0_bitangent0.azbuffer,"
-                 "objects/cube_lod0_uv0.azbuffer",
+            addSeed="objects/cube_lod0.fbx.azlod",
+            skip="objects/cube_lod0_position0.fbx.azbuffer, objects/cube_lod0_tangent0.fbx.azbuffer,"
+                 "objects/cube_lod0_normal0.fbx.azbuffer, objects/cube_lod0_bitangent0.fbx.azbuffer,"
+                 "objects/cube_lod0_uv0.fbx.azbuffer",
             platform=workspace.asset_processor_platform
         )
         assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])

+ 1 - 1
AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py

@@ -194,7 +194,7 @@ blackbox_fbx_tests = [
                                     sub_id=330338417,
                                     asset_type=b'51f376140d774f369ac67ed70a0ac868'),
                                 asset_db_utils.DBProduct(
-                                    product_name='softnamingphysics/physicstest.pxmesh',
+                                    product_name='softnamingphysics/physicstest.fbx.pxmesh',
                                     sub_id=640975857,
                                     asset_type=b'7a2871b95eab4de0a901b0d2c6920ddb'),
                                 asset_db_utils.DBProduct(

+ 1 - 1
AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/hydra_SubID_NoChange_MeshChanged.py

@@ -61,7 +61,7 @@ def SubID_NoChange_MeshChanged():
         dst = os.path.join(dirpath, 'Objects', 'shaderball_simple.fbx.assetinfo')
 
         # Test Setup: Find the asset by asset path
-        model_path = os.path.join('objects', 'shaderball_simple.azmodel')
+        model_path = os.path.join('objects', 'shaderball_simple.fbx.azmodel')
         model = Asset.find_asset_by_path(model_path)
 
         # Test Setup: Ensure there is no assetinfo file in the dst path, if there is, remove it.

+ 1 - 1
AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/hydra_SubID_WarningReported_AssetRemoved.py

@@ -62,7 +62,7 @@ def SubID_WarningReported_AssetRemoved():
     dst = os.path.join(dirpath, 'Objects', 'shaderball_simple.fbx.assetinfo')
 
     # Test Setup: Find the asset by asset path - Use azmaterial as we will be removing the azmodels during the test.
-    model_path = os.path.join('objects', 'shaderball_simple_phong_0_17699592688871882463.azmaterial')
+    model_path = os.path.join('objects', 'shaderball_simple_phong_0_17699592688871882463.fbx.azmaterial')
     model = Asset.find_asset_by_path(model_path)
     checkModel = OnModelReloaded()
 

+ 3 - 3
AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py

@@ -64,7 +64,7 @@ def AssetPicker_UI_UX():
         file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"]
 
         def is_asset_assigned(component, interaction_option):
-            path = os.path.join("assets", "objects", "foliage", "cedar.azmodel")
+            path = os.path.join("assets", "objects", "foliage", "cedar.fbx.azmodel")
             expected_asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', path, math.Uuid(),
                                                              False)
             result = hydra.get_component_property_value(component, "Controller|Configuration|Model Asset")
@@ -235,7 +235,7 @@ def AssetPicker_UI_UX():
 
         # Assign Model Asset via OK button
         pyside_utils.click_button_async(attached_button)
-        await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "ok")
+        await asset_picker(["azmodel", "fbx"], "cedar.fbx (ModelAsset)", "ok")
 
         # 5) Verify if Model Asset is assigned
         try:
@@ -259,7 +259,7 @@ def AssetPicker_UI_UX():
 
         # Assign Model Asset via Enter
         pyside_utils.click_button_async(attached_button)
-        await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "enter")
+        await asset_picker(["azmodel", "fbx"], "cedar.fbx (ModelAsset)", "enter")
 
         # 5) Verify if Model Asset is assigned
         try:

+ 1 - 1
AutomatedTesting/Gem/PythonTests/editor/EditorScripts/DPE_AllComponentPropertyTypesEditable.py

@@ -112,7 +112,7 @@ def DPE_AllComponentPropertyTypesEditable():
         edit_component_property_value(light_component, 'Controller|Configuration|Color', math.Color(0.5, 0.5, 0.5, 0.5))
 
         # Asset Picker
-        asset_to_pick_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+        asset_to_pick_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
         asset_to_pick = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_to_pick_path,
                                                      math.Uuid(), False)
         edit_component_property_value(mesh_component, 'Controller|Configuration|Model Asset', asset_to_pick)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py

@@ -71,7 +71,7 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
 
-    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower")[0]
 
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py

@@ -49,7 +49,7 @@ def AltitudeFilter_FilterStageToggle():
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
 
-    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower2")[0]
 
     vegetation = dynveg.create_temp_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py

@@ -65,7 +65,7 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
 
-    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower3")[0]
 
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, flower_prefab)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py

@@ -114,9 +114,9 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea():
 
     # 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "AssetList_PinkFlower")[0]
-    purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     purple_flower_prefab = dynveg.create_temp_mesh_prefab(purple_flower_asset_path, "AssetList_PurpleFlower")[0]
     asset_list_entity = create_asset_list_entity("Asset List 1", center_point, pink_flower_prefab)
     asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py

@@ -65,7 +65,7 @@ def AssetWeightSelector_InstancesExpressBasedOnWeight():
     # 2) Create a new instance spawner entity with multiple Prefab Instance Spawner descriptors, one set to a
     # valid prefab entity, and one set to None
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "AssetWeight_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py

@@ -69,7 +69,7 @@ def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius():
 
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
-    cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.azmodel")
+    cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.fbx.azmodel")
     cube_prefab = dynveg.create_temp_mesh_prefab(cube_asset_path, "DistanceBetween_1m_cube2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
                                                                cube_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py

@@ -67,7 +67,7 @@ def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius():
 
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
-    cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.azmodel")
+    cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.fbx.azmodel")
     cube_prefab = dynveg.create_temp_mesh_prefab(cube_asset_path, "DistanceBetween_1m_cube")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point,
                                                                16.0, 16.0, 16.0, cube_prefab)

+ 6 - 6
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py

@@ -39,11 +39,11 @@ def DynVegUtils_TempPrefabCreationWorks():
     with Tracer() as error_tracer:
         # Create dictionary for prefab filenames and paths to create using helper function
         mesh_prefabs = {
-            "UtilsTest_PinkFlower": os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel"),
-            "UtilsTest_PurpleFlower": os.path.join("assets", "objects", "foliage", "grass_flower_purple.azmodel"),
-            "UtilsTest_1m_Cube": os.path.join("objects", "_primitives", "_box_1x1.azmodel"),
-            "UtilsTest_CedarTree": os.path.join("assets", "objects", "foliage", "cedar.azmodel"),
-            "UtilsTest_Bush": os.path.join("assets", "objects", "foliage", "bush_privet_01.azmodel"),
+            "UtilsTest_PinkFlower": os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel"),
+            "UtilsTest_PurpleFlower": os.path.join("assets", "objects", "foliage", "grass_flower_purple.fbx.azmodel"),
+            "UtilsTest_1m_Cube": os.path.join("objects", "_primitives", "_box_1x1.fbx.azmodel"),
+            "UtilsTest_CedarTree": os.path.join("assets", "objects", "foliage", "cedar.fbx.azmodel"),
+            "UtilsTest_Bush": os.path.join("assets", "objects", "foliage", "bush_privet_01.fbx.azmodel"),
                    }
 
         # 1) Open an existing simple level
@@ -66,7 +66,7 @@ def DynVegUtils_TempPrefabCreationWorks():
             f"Failed to create temporary mesh prefab: {physx_prefab_filename}"
         )
         test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", os.path.join(
-            "assets", "objects", "foliage", "cedar.pxmesh"), math.Uuid(), False)
+            "assets", "objects", "foliage", "cedar.fbx.pxmesh"), math.Uuid(), False)
         dynveg.create_temp_physx_mesh_collider(test_physx_mesh_asset_id, physx_prefab_filename)
         Report.result(physx_collider_prefab_created, helper.wait_for_condition(lambda:
                                                                                PrefabInstance.is_valid(prefab[1]), 3.0))

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py

@@ -68,7 +68,7 @@ def InstanceSpawnerPriority_LayerAndSubPriority():
 
     # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
     spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Priority_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py

@@ -65,7 +65,7 @@ def LayerBlocker_InstancesBlockedInConfiguredArea():
 
     # 2) Create a new instance spawner entity
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Blocker_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point,
                                                                16.0, 16.0, 16.0, pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py

@@ -49,7 +49,7 @@ def LayerSpawner_FilterStageToggle():
 
     # Create a vegetation area with all needed components
     position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerFilter_PinkFlower")[0]
     vegetation_entity = dynveg.create_temp_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0,
                                                                   pink_flower_prefab)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py

@@ -77,7 +77,7 @@ def LayerSpawner_InheritBehaviorFlag():
     veg_1.create_entity(
         position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"]
     )
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerInheritBehavior_PinkFlower")[0]
     set_prefab_asset(veg_1, 2, pink_flower_prefab)
     veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
@@ -87,7 +87,7 @@ def LayerSpawner_InheritBehaviorFlag():
     veg_2.create_entity(
         position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"]
     )
-    purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     purple_flower_prefab = dynveg.create_temp_mesh_prefab(purple_flower_asset_path, "temp_PurpleFlower")[0]
     set_prefab_asset(veg_2, 2, purple_flower_prefab)
     veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py

@@ -60,7 +60,7 @@ def LayerSpawner_InstancesPlantInAllSupportedShapes():
 
     # 2) Create basic vegetation area entity and set the properties
     entity_position = math.Vector3(125.0, 136.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerShapePlant_PinkFlower")[0]
     vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0,
                                                            pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py

@@ -100,7 +100,7 @@ def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera():
                                                          surface_height)
 
     # Create the two vegetation areas
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerViewportRefresh_PinkFlower")[0]
     first_veg_entity = dynveg.create_temp_prefab_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
                                                                  box_size, pink_flower_prefab)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py

@@ -58,7 +58,7 @@ def MeshBlocker_InstancesBlockedByMesh():
 
     # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "MeshBlocker_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0,
                                                                pink_flower_prefab)
@@ -75,7 +75,7 @@ def MeshBlocker_InstancesBlockedByMesh():
     if blocker_entity.id.IsValid():
         print(f"'{blocker_entity.name}' created")
     cubeId = asset.AssetCatalogRequestBus(
-        bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
+        bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.fbx.azmodel"), math.Uuid(),
         False)
 
     blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py

@@ -60,7 +60,7 @@ def MeshBlocker_InstancesBlockedByMeshHeightTuning():
 
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "MeshBlocker_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0,
                                                                pink_flower_prefab)
@@ -78,7 +78,7 @@ def MeshBlocker_InstancesBlockedByMeshHeightTuning():
     if blocker_entity.id.IsValid():
         Report.info(f"'{blocker_entity.name}' created")
     sphere_id = asset.AssetCatalogRequestBus(
-        bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
+        bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.fbx.azmodel"), math.Uuid(),
         False)
     blocker_entity.get_set_test(1, "Controller|Configuration|Model Asset", sphere_id)
     components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 5.0)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py

@@ -91,7 +91,7 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor():
     dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0)
 
     # Create a new entity with required vegetation area components
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PhysXCollider_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_center_point, test_box_size,
                                                                test_box_size, test_box_size, pink_flower_prefab)
@@ -173,7 +173,7 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor():
     test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(
         bus.Broadcast, "GetAssetIdByPath", os.path.join("assets", "objects",
                                                         "pxmesh",
-                                                        "test.pxmesh"), math.Uuid(), False)
+                                                        "test.fbx.pxmesh"), math.Uuid(), False)
     collider_entity.remove_component(PHYSX_PRIMITIVE_COLLIDER)
     collider_entity.add_component(PHYSX_MESH_COLLIDER)
     helper.wait_for_condition(lambda: editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled',

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py

@@ -72,7 +72,7 @@ def PositionModifier_AutoSnapToSurfaceWorks():
 
     # 2) Create a new entity with required vegetation area components and a Position Modifier
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PosMod_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0,
                                                                16.0, pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py

@@ -109,7 +109,7 @@ def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets():
 
     # 2) Create a new entity with required vegetation area components
     spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PosMod_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0,
                                                                1.0, pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py

@@ -86,7 +86,7 @@ def RotationModifierOverrides_InstancesRotateWithinRange():
 
     # 2) Create vegetation entity and add components
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RotMod_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py

@@ -124,7 +124,7 @@ def RotationModifier_InstancesRotateWithinRange():
     general.set_current_view_position(512.0, 480.0, 38.0)
 
     # 2) Set up vegetation entities
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RotMod_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", LEVEL_CENTER, 2.0, 2.0, 2.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py

@@ -98,7 +98,7 @@ def ScaleModifierOverrides_InstancesProperlyScale():
 
     # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ScaleMod_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py

@@ -92,7 +92,7 @@ def ScaleModifier_InstancesProperlyScale():
     # 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
     # Vegetation Scale Modifier
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ScaleMod_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py

@@ -55,7 +55,7 @@ def ShapeIntersectionFilter_FilterStageToggle():
 
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ShapeIntersection_PinkFlower")[0]
     vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 16.0,
                                                            pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py

@@ -68,7 +68,7 @@ def ShapeIntersectionFilter_InstancesPlantInAssignedShape():
 
     # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ShapeIntersection_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
                                                                pink_flower_prefab)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py

@@ -64,14 +64,14 @@ def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment():
 
     # Create a spawner entity setup with all needed components
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SlopeAlign_PinkFlower2")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0,
                                                                pink_flower_prefab)
 
     # Create a sloped mesh surface for the instances to plant on
     center_point = math.Vector3(502.0, 512.0, 24.0)
-    mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
+    mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.fbx.azmodel")
     mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
                                               False)
     rotation = math.Vector3(0.0, radians(45.0), 0.0)

+ 2 - 2
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py

@@ -65,14 +65,14 @@ def SlopeAlignmentModifier_InstanceSurfaceAlignment():
 
     # Create a spawner entity setup with all needed components
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SlopeAlign_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0,
                                                                pink_flower_prefab)
 
     # Create a sloped mesh surface for the instances to plant on
     center_point = math.Vector3(502.0, 512.0, 24.0)
-    mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
+    mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.fbx.azmodel")
     mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
                                               False)
     rotation = math.Vector3(0.0, radians(45.0), 0.0)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py

@@ -70,7 +70,7 @@ def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes():
 
     # 2) Create a new entity with required vegetation area components
     center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Slope_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py

@@ -60,7 +60,7 @@ def SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks():
     # 2) Verifies if a prefab containing the Vegetation Layer Spawner component can be created.
     # 2.1) Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerPrefab_PinkFlower")[0]
     veg_1 = dynveg.create_temp_prefab_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0,
                                                       pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py

@@ -75,7 +75,7 @@ def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected():
 
     # 2) Create a new instance spawner entity with multiple Prefab Instance Spawner descriptors
     spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskOverrides_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0,
                                                                16.0, pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py

@@ -97,7 +97,7 @@ def SurfaceMaskFilter_ExclusionList():
 
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskTagExclusion_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py

@@ -98,7 +98,7 @@ def SurfaceMaskFilter_InclusionList():
 
     # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
     entity_position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskTagInclusion_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py

@@ -53,7 +53,7 @@ def SystemSettings_SectorPointDensity():
 
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SectorPoint_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 1.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py

@@ -49,7 +49,7 @@ def SystemSettings_SectorSize():
 
     # Create basic vegetation entity
     position = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SectorSize_PinkFlower")[0]
     vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 1.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py

@@ -53,7 +53,7 @@ def VegetationInstances_DespawnWhenOutOfRange():
 
     # Create vegetation layer spawner
     world_center = math.Vector3(512.0, 512.0, 32.0)
-    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel")
+    pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.fbx.azmodel")
     pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RangeDespawn_PinkFlower")[0]
     spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", world_center, 16.0, 16.0, 16.0,
                                                                pink_flower_prefab)

+ 1 - 1
AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py

@@ -78,7 +78,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z
 
 def create_mesh_surface_entity_with_slopes(name, center_point, uniform_scale):
     # Creates an entity with the assigned mesh_asset as the specified scale and sets up as a planting surface
-    mesh_asset_path = os.path.join("models", "sphere.azmodel")
+    mesh_asset_path = os.path.join("models", "sphere.fbx.azmodel")
     mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
                                               False)
     surface_entity = hydra.Entity(name)

+ 1 - 1
Code/Tools/AssetProcessor/native/ui/AssetTreeItem.cpp

@@ -27,7 +27,7 @@ namespace AssetProcessor
         m_scanFolderID(scanFolderID)
     {
         QFileInfo fileInfo(name);
-        m_extension = fileInfo.completeSuffix();
+        m_extension = fileInfo.suffix();
     }
 
     int AssetTreeItemData::GetColumnCount() const

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

@@ -42,6 +42,12 @@ namespace AZ
                 return m_sourceFilename;
             }
 
+            AZStd::string_view Scene::GetSourceExtension() const
+            {
+                const AZ::IO::PathView sourcePath(m_sourceFilename);
+                return AZStd::string_view(sourcePath.Extension());
+            }
+
             const Uuid& Scene::GetSourceGuid() const
             {
                 return m_sourceGuid;

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

@@ -33,6 +33,7 @@ namespace AZ
                 void SetSource(const AZStd::string& filename, const Uuid& guid);
                 void SetSource(AZStd::string&& filename, const Uuid& guid);
                 const AZStd::string& GetSourceFilename() const;
+                AZStd::string_view GetSourceExtension() const;
                 const Uuid& GetSourceGuid() const;
 
                 void SetWatchFolder(const AZStd::string& watchFolder);

+ 24 - 5
Code/Tools/SceneAPI/SceneCore/Utilities/FileUtilities.cpp

@@ -17,16 +17,35 @@ namespace AZ
     {
         namespace Utilities
         {
-            AZStd::string FileUtilities::CreateOutputFileName(const AZStd::string& groupName, const AZStd::string& outputDirectory, const AZStd::string& extension)
+            AZStd::string FileUtilities::CreateOutputFileName(
+                const AZStd::string& groupName, const AZStd::string& outputDirectory, const AZStd::string& extension,
+                const AZStd::string& sourceFileExtension)
             {
-                AZStd::string result;
+                // Create an initial name that looks like 'directory/groupName'
+                AZ::IO::Path result(outputDirectory);
+                result /= groupName;
 
-                if (!AzFramework::StringFunc::Path::ConstructFull(outputDirectory.c_str(), groupName.c_str(), extension.c_str(), result, true))
+                // Either add an extension or replace the existing one with the source file extension. This will typically
+                // add the extension since most group names don't have an extension already.
+                // This will ensure that final file name is unique based on the source file extension.
+                // For example, 'model.fbx' and 'model.stl' would both have a groupName of 'model', and would then produce
+                // 'model.azmodel' for example as the product asset for both. By appending the original source extension here,
+                // we end up with the unique names of 'model.fbx.azmodel' and 'model.stl.azmodel'.
+                // This could theoretically be fixed in the groupName generation, but that requires changes in many more places to the
+                // code, along with knock-off effects that come from preserving the '.' which is also used by the SceneAPI to
+                // separate node names. By adding it to the end file name, we avoid all of the negative effects and can centralize
+                // the change to this one place.
+                result.ReplaceExtension(AZ::IO::PathView(sourceFileExtension));
+
+                // Append product extension to the file path by manipulating the string directly
+                if (!extension.starts_with('.'))
                 {
-                    return "";
+                    result.Native() += '.';
                 }
+                result.Native() += extension;
 
-                return result;
+                // Return the final file name.
+                return result.LexicallyNormal().Native();
             }
 
             bool FileUtilities::EnsureTargetFolderExists(const AZStd::string& path)

+ 3 - 1
Code/Tools/SceneAPI/SceneCore/Utilities/FileUtilities.h

@@ -20,7 +20,9 @@ namespace AZ
             class FileUtilities
             {
             public:
-                SCENE_CORE_API static AZStd::string CreateOutputFileName(const AZStd::string& groupName, const AZStd::string& outputDirectory, const AZStd::string& extension);
+                SCENE_CORE_API static AZStd::string CreateOutputFileName(
+                    const AZStd::string& groupName, const AZStd::string& outputDirectory, const AZStd::string& extension,
+                    const AZStd::string& sourceFileExtension);
                 SCENE_CORE_API static bool EnsureTargetFolderExists(const AZStd::string& path);
                 SCENE_CORE_API static AZStd::string GetRelativePath(const AZStd::string& path, const AZStd::string& rootPath);
             };

+ 1 - 1
Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp

@@ -30,7 +30,7 @@ namespace AZ
 
             // load visualization plane model and material
             m_visualizationModelAsset = AZ::RPI::AssetUtils::LoadCriticalAsset<AZ::RPI::ModelAsset>(
-                "Models/OcclusionCullingPlane.azmodel",
+                "Models/OcclusionCullingPlane.fbx.azmodel",
                 AZ::RPI::AssetUtils::TraceLevel::Assert);
 
             m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(MeshHandleDescriptor{ m_visualizationModelAsset });

+ 1 - 1
Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp

@@ -59,7 +59,7 @@ namespace AZ
 
             // We don't have to pre-load this asset before passing it to MeshFeatureProcessor, because the MeshFeatureProcessor will handle the async-load for us.
             m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
-                "Models/ReflectionProbeSphere.azmodel",
+                "Models/ReflectionProbeSphere.fbx.azmodel",
                 AZ::RPI::AssetUtils::TraceLevel::Assert);
 
             MeshHandleDescriptor visualizationMeshDescriptor;

+ 3 - 2
Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp

@@ -290,7 +290,8 @@ namespace AZ
             [[maybe_unused]] const char* assetTypeDebugName) const
         {
             const AZStd::string assetFileName = SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
-                assetContext.m_relativeFileName, context.GetOutputDirectory(), assetContext.m_extension);
+                assetContext.m_relativeFileName, context.GetOutputDirectory(), assetContext.m_extension,
+                context.GetScene().GetSourceExtension());
 
             if (!Utils::SaveObjectToFile(assetFileName, assetContext.m_dataStreamType, asset.Get()))
             {
@@ -337,7 +338,7 @@ namespace AZ
             if (auto* serialize = azrtti_cast<SerializeContext*>(context))
             {
                 serialize->Class<ModelExporterComponent, SceneAPI::SceneCore::ExportingComponent>()
-                    ->Version(3);
+                    ->Version(4);
             }
         }
 

+ 1 - 1
Gems/Atom/Tools/MaterialCanvas/Code/Source/Window/MaterialCanvasViewportContent.cpp

@@ -72,7 +72,7 @@ namespace MaterialCanvas
 
         AZ::Render::MeshComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId,
-            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel"));
+            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.fbx.azmodel"));
 
         AZ::Render::MaterialComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialAssetId,

+ 1 - 1
Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorViewportContent.cpp

@@ -70,7 +70,7 @@ namespace MaterialEditor
 
         AZ::Render::MeshComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId,
-            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel"));
+            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.fbx.azmodel"));
 
         AZ::Render::MaterialComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialAssetId,

+ 1 - 1
Gems/Atom/Tools/PassCanvas/Code/Source/Window/PassCanvasViewportContent.cpp

@@ -72,7 +72,7 @@ namespace PassCanvas
 
         AZ::Render::MeshComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId,
-            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel"));
+            AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.fbx.azmodel"));
 
         AZ::Render::MaterialComponentRequestBus::Event(
             GetShadowCatcherEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialAssetId,

+ 1 - 1
Gems/AtomLyIntegration/CommonFeatures/Assets/Editor/Scripts/LegacyContentConversion/LegacyMaterialComponentConverter.py

@@ -222,7 +222,7 @@ class Material_Component_Converter(object):
         if isActor:
             cacheFbxPath = "".join((oldFbxRelativePathWithoutExtension, ".actor"))
         else:
-            cacheFbxPath = "".join((oldFbxRelativePathWithoutExtension, ".azmodel"))
+            cacheFbxPath = "".join((oldFbxRelativePathWithoutExtension, ".fbx.azmodel"))
 
         if cacheFbxPath in self.assetCatalogHelper.relativePathToAssetIdDict:
             fbxAssetId = self.assetCatalogHelper.relativePathToAssetIdDict[cacheFbxPath]

+ 5 - 5
Gems/AtomLyIntegration/CommonFeatures/Assets/Editor/Scripts/LegacyContentConversion/LegacyMeshComponentConverter.py

@@ -55,8 +55,8 @@ class Mesh_Component_Converter(Component_Converter):
                         
                         # Legacy assetId looks like this "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:3250cdc0,type={C2869E3B-DDA0-4E01-8FE3-6770D788866B},hint={objects/airship/airship_pod_outerwalls.cgf}
                         # atomAssetId looks like this "{BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,
-                        # newAssetId should look like "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/airship/airship_pod_outerwalls.azmodel}"
-                                                #value"id={E01FB8B5-D2B3-52D8-BC36-644FC0E3B5F4}:268435463,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/props/barrel_01.azmodel}"
+                        # newAssetId should look like "id={BCD2BB63-338F-53BE-98E1-BF847138B78E}:########,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/airship/airship_pod_outerwalls.fbx.azmodel}"
+                                                #value"id={E01FB8B5-D2B3-52D8-BC36-644FC0E3B5F4}:268435463,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/props/barrel_01.fbx.azmodel}"
                         # get the relative path to the mesh
                         meshPathStartIndex = assetId.find("hint={")
                         meshPathStartIndex += len("hint={")
@@ -64,7 +64,7 @@ class Mesh_Component_Converter(Component_Converter):
                         self.oldFbxRelativePathWithoutExtension = assetId[meshPathStartIndex: meshPathEndIndex]
                         
                         # swap the sub-id for the atom model sub-id
-                        atomModelRelativePath = "{0}.azmodel".format(self.oldFbxRelativePathWithoutExtension)
+                        atomModelRelativePath = "{0}.fbx.azmodel".format(self.oldFbxRelativePathWithoutExtension)
                         if atomModelRelativePath in self.assetCatalogHelper.relativePathToAssetIdDict:
                             atomAssetId = self.assetCatalogHelper.relativePathToAssetIdDict[atomModelRelativePath]
                             atomSubId = atomAssetId[atomAssetId.find(":") + 1:]
@@ -111,7 +111,7 @@ class Mesh_Component_Converter(Component_Converter):
         #            </Class>
         #            <Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
         #                <Class name="AZ::Render::MeshComponentConfig" field="Configuration" type="{63737345-51B1-472B-9355-98F99993909B}">
-        #                    <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
+        #                    <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.fbx.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
         #                    <Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
         #                </Class>
         #            </Class>
@@ -128,7 +128,7 @@ class Mesh_Component_Converter(Component_Converter):
         #            </Class>
         #            <Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
         #                <Class name="AZ::Render::MeshComponentConfig" field="Configuration" type="{63737345-51B1-472B-9355-98F99993909B}">
-        #                    <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
+        #                    <Class name="Asset" field="ModelAsset" value="id={509D78D3-2196-50C2-808C-FEDC3C31380D}:10000007,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/suzanne.fbx.azmodel}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
         #                    <Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
         #                </Class>
         #            </Class>

+ 1 - 1
Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp

@@ -277,7 +277,7 @@ namespace EMStudio
         AZ::TransformBus::Event(m_groundEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, identityTransform);
 
         auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>(
-            "objects/groudplane/groundplane_512x512m.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert);
+            "objects/groudplane/groundplane_512x512m.fbx.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert);
         AZ::Render::MeshComponentRequestBus::Event(
             m_groundEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset);
 

+ 14 - 1
Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp

@@ -116,7 +116,20 @@ namespace EMotionFX
 
         AZ::SceneAPI::Events::ProcessingResult ActorGroupExporter::SaveActor(ActorGroupExportContext& context)
         {
-            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(context.m_group.GetName(), context.m_outputDirectory, "");
+            // If we wanted to preserve the input file's extension as a part of the product asset name, we would pass
+            // context.m_scene.GetSourceExtension() here instead of emptySourceExtension. We aren't currently doing that for
+            // EmotionFX files (.actor, .motion) because source assets (.motionset, .emfxworkspace) can have references to
+            // existing product asset file names. Those names would need to get fixed up to contain the extension to preserve backwards
+            // compatibility.
+            // For example, 'robot.fbx' will produce 'robot.actor' here. If we pass in GetSourceExtension(), it would
+            // produce 'robot.fbx.actor'. The reason to want the latter is so that multiple input files that vary by extension only
+            // would produce different outputs (ex: 'robot.fbx' -> 'robot.fbx.actor', 'robot.obj' -> 'robot.obj.actor').
+            // If this is ever desired, the source asset input serialization would need to be modified to correctly change the
+            // assetId field that's stored in the source assets, and the version number on those files should be incremented.
+            const AZStd::string emptySourceExtension;
+            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(
+                context.m_group.GetName(), context.m_outputDirectory, "", emptySourceExtension);
+
             if (filename.empty() || !SceneUtil::FileUtilities::EnsureTargetFolderExists(filename))
             {
                 return SceneEvents::ProcessingResult::Failure;

+ 15 - 1
Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp

@@ -52,8 +52,22 @@ namespace EMotionFX
                 return SceneEvents::ProcessingResult::Ignored;
             }
 
+            // If we wanted to preserve the input file's extension as a part of the product asset name, we would pass
+            // context.m_scene.GetSourceExtension() here instead of emptySourceExtension. We aren't currently doing that for
+            // EmotionFX files (.actor, .motion) because source assets (.motionset, .emfxworkspace) can have references to
+            // existing product asset file names. Those names would need to get fixed up to contain the extension to preserve backwards
+            // compatibility.
+            // For example, 'walk.fbx' will produce 'walk.motion' here. If we pass in GetSourceExtension(), it would
+            // produce 'walk.fbx.motion'. The reason to want the latter is so that multiple input files that vary by extension only
+            // would produce different outputs (ex: 'walk.fbx' -> 'walk.fbx.motion', 'walk.obj' -> 'walk.obj.motion').
+            // If this is ever desired, the source asset input serialization would need to be modified to correctly change the
+            // assetId field that's stored in the source assets, and the version number on those files should be incremented.
+            const AZStd::string emptySourceExtension;
+
             const AZStd::string& groupName = context.m_group.GetName();
-            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(groupName, context.m_outputDirectory, s_fileExtension);
+            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(
+                groupName, context.m_outputDirectory, s_fileExtension, emptySourceExtension);
+
             if (filename.empty() || !SceneUtil::FileUtilities::EnsureTargetFolderExists(filename))
             {
                 return SceneEvents::ProcessingResult::Failure;

+ 8 - 1
Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp

@@ -1242,12 +1242,19 @@ namespace EMotionFX
 
     AZ::Data::AssetId Actor::ConstructSkinMetaAssetId(const AZ::Data::AssetId& meshAssetId)
     {
+        // Get the full mesh asset path (ex: 'objects/model.fbx.azmodel')
         AZStd::string meshAssetPath;
         AZ::Data::AssetCatalogRequestBus::BroadcastResult(meshAssetPath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, meshAssetId);
+
+        // Get just the filename, stripping off the path and the extension (ex: 'model.fbx')
         AZStd::string meshAssetFileName;
         AzFramework::StringFunc::Path::GetFileName(meshAssetPath.c_str(), meshAssetFileName);
 
-        return AZ::RPI::SkinMetaAsset::ConstructAssetId(meshAssetId, meshAssetFileName);
+        // Strip off the source extension as well, to bring us down to the base asset name (ex: 'model')
+        AZStd::string baseMeshAssetFileName;
+        AzFramework::StringFunc::Path::GetFileName(meshAssetFileName.c_str(), baseMeshAssetFileName);
+
+        return AZ::RPI::SkinMetaAsset::ConstructAssetId(meshAssetId, baseMeshAssetFileName);
     }
 
     bool Actor::DoesSkinMetaAssetExist(const AZ::Data::AssetId& meshAssetId)

+ 3 - 2
Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp

@@ -139,7 +139,7 @@ namespace PhysX
             if (serializeContext)
             {
                 serializeContext->Class<MeshExporter, AZ::SceneAPI::SceneCore::ExportingComponent>()
-                    ->Version(6 + (1<<PX_PHYSICS_VERSION_MAJOR)); // Use PhysX version to trigger assets recompilation
+                    ->Version(7 + (1<<PX_PHYSICS_VERSION_MAJOR)); // Use PhysX version to trigger assets recompilation
             }
         }
 
@@ -543,7 +543,8 @@ namespace PhysX
             SceneEvents::ProcessingResult result = SceneEvents::ProcessingResult::Ignored;
 
             AZStd::string assetName = meshGroup.GetName();
-            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(assetName, context.GetOutputDirectory(), MeshAssetHandler::s_assetFileExtension);
+            AZStd::string filename = SceneUtil::FileUtilities::CreateOutputFileName(
+                assetName, context.GetOutputDirectory(), MeshAssetHandler::s_assetFileExtension, context.GetScene().GetSourceExtension());
 
             MeshAssetData assetData;
 

+ 7 - 7
Gems/Prefab/PrefabBuilder/PrefabGroup/DefaultProceduralPrefab.cpp

@@ -263,7 +263,8 @@ namespace AZ::SceneAPI
     bool DefaultProceduralPrefabGroup::AddEditorMeshComponent(
         const AZ::EntityId& entityId,
         const AZStd::string& relativeSourcePath,
-        const AZStd::string& meshGroupName) const
+        const AZStd::string& meshGroupName,
+        const AZStd::string& sourceFileExtension) const
     {
         // Since the mesh component lives in a gem, then create it by name
         AzFramework::BehaviorComponentId editorMeshComponent;
@@ -280,15 +281,14 @@ namespace AZ::SceneAPI
         }
 
         // assign mesh asset id hint using JSON
-        AZStd::string modelAssetPath;
-        modelAssetPath = relativeSourcePath;
-        AZ::StringFunc::Path::ReplaceFullName(modelAssetPath, meshGroupName.c_str());
-        AZ::StringFunc::Replace(modelAssetPath, "\\", "/"); // asset paths use forward slashes
+        AZ::IO::Path modelAssetPath(relativeSourcePath, '/');
+        modelAssetPath.ReplaceFilename(AZ::IO::PathView(meshGroupName));
+        modelAssetPath.ReplaceExtension(AZ::IO::PathView(sourceFileExtension));
 
         auto meshAssetJson = AZStd::string::format(
             R"JSON(
                    {"Controller": {"Configuration": {"ModelAsset": { "assetHint": "%s.azmodel"}}}}
-             )JSON", modelAssetPath.c_str());
+             )JSON", modelAssetPath.LexicallyNormal().String().c_str());
 
         bool result = false;
         AzToolsFramework::EntityUtilityBus::BroadcastResult(
@@ -313,7 +313,7 @@ namespace AZ::SceneAPI
         AZStd::shared_ptr<SceneData::MeshGroup> meshGroup(BuildMeshGroupForNode(scene, nodeData, nodeDataMap));
         manifestUpdates.emplace_back(meshGroup);
 
-        if (AddEditorMeshComponent(entityId, relativeSourcePath, meshGroup->GetName()) == false)
+        if (AddEditorMeshComponent(entityId, relativeSourcePath, meshGroup->GetName(), scene.GetSourceExtension()) == false)
         {
             return false;
         }

+ 2 - 1
Gems/Prefab/PrefabBuilder/PrefabGroup/DefaultProceduralPrefab.h

@@ -71,7 +71,8 @@ namespace AZ::SceneAPI
         bool AddEditorMeshComponent(
             const AZ::EntityId& entityId,
             const AZStd::string& relativeSourcePath,
-            const AZStd::string& meshGroupName) const;
+            const AZStd::string& meshGroupName,
+            const AZStd::string& sourceFileExtension) const;
 
         bool CreateMeshGroupAndComponents(
             ManifestUpdates& manifestUpdates,

+ 12 - 3
Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp

@@ -367,10 +367,18 @@ namespace AZ::SceneAPI::Behaviors
         const SceneData::PrefabGroup* prefabGroup,
         const rapidjson::Document& doc) const
     {
+        // Since the prefab group name already has the source file extension added as a part of the name (ex: "model_fbx"),
+        // we won't pass the source file extension again to CreateOuputFileName. This prevents names like "model_fbx.fbx.procprefab".
+        // CreateOutputFileName has been changed to preserve the model's extension as a bugfix, which occurred after the procprefab
+        // system was built, so we need to be concerned with backwards compatibility. Procprefab files are typically referenced
+        // by file name, not by asset ID or source GUID, so we can't introduce changes that would change the procprefab file name.
+        const AZStd::string emptySourceExtension;
+
         AZStd::string filePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
             prefabGroup->GetName().c_str(),
             context.GetOutputDirectory(),
-            AZ::Prefab::PrefabGroupAssetHandler::s_Extension);
+            AZ::Prefab::PrefabGroupAssetHandler::s_Extension,
+            emptySourceExtension);
 
         bool result = WriteOutProductAssetFile(filePath, context, prefabGroup, doc, false);
 
@@ -379,7 +387,8 @@ namespace AZ::SceneAPI::Behaviors
             AZStd::string debugFilePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
                 prefabGroup->GetName().c_str(),
                 context.GetOutputDirectory(),
-                AZ::Prefab::PrefabGroupAssetHandler::s_Extension);
+                AZ::Prefab::PrefabGroupAssetHandler::s_Extension,
+                emptySourceExtension);
             debugFilePath.append(".json");
             WriteOutProductAssetFile(debugFilePath, context, prefabGroup, doc, true);
         }
@@ -491,7 +500,7 @@ namespace AZ::SceneAPI::Behaviors
         SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
         if (serializeContext)
         {
-            serializeContext->Class<PrefabGroupBehavior, BehaviorComponent>()->Version(1);
+            serializeContext->Class<PrefabGroupBehavior, BehaviorComponent>()->Version(2);
         }
 
         BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);

+ 1 - 1
Gems/PythonAssetBuilder/Editor/Scripts/scene_api/physics_data.py

@@ -266,7 +266,7 @@ class PhysicsAssetShapeConfiguration(ShapeConfiguration):
     Methods
     -------
     set_asset_reference(self, assetReference: str)
-        Helper function to set the asset reference to the collision mesh such as 'my/folder/my_mesh.azmodel'
+        Helper function to set the asset reference to the collision mesh such as 'my/folder/my_mesh.fbx.azmodel'
 
     to_dict()
         Converts contents to a Python dictionary

+ 1 - 1
engine.json

@@ -9,7 +9,7 @@
         "editor": "1.0.0",
         "framework": "1.1.0",
         "launcher": "1.0.0",
-        "tools": "1.0.0"
+        "tools": "1.1.0"
     },
     "file_version": 2,
     "copyright_year": 2023,