Merge remote-tracking branch 'upstream/main' into Atom/santorac/MaterialTypeCleanup

This commit is contained in:
Chris Santora
2021-05-27 15:12:56 -07:00
270 changed files with 3766 additions and 3811 deletions
@@ -31,13 +31,13 @@ class TestPythonAssetProcessing(object):
unexpected_lines = []
expected_lines = [
'Mock asset exists',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel) found'
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel) found',
'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found'
]
timeout = 180
halt_on_unexpected = False
@@ -38,16 +38,16 @@ def test_azmodel_product(generatedModelAssetPath, expectedSubId):
assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', generatedModelAssetPath, azModelAssetType, False)
assetIdString = assetId.to_string()
if (assetIdString.endswith(':' + expectedSubId) is False):
raise_and_stop(f'Asset has unexpected asset ID ({assetIdString}) for ({generatedModelAssetPath})!')
raise_and_stop(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString}) for ({generatedModelAssetPath}), expected {expectedSubId}!')
else:
print(f'Expected subId for asset ({generatedModelAssetPath}) found')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel', '10315ae0')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel', '10661093')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel', '10af8810')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel', '10f8c263')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel', '100ac47f')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel', '105d8e0c')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel', '1002d464')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive.azmodel', '1024be55')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative.azmodel', '1052c94e')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive.azmodel', '10130556')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative.azmodel', '1065724d')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive.azmodel', '10d16e68')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative.azmodel', '10a71973')
test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel', '10412075')
azlmbr.editor.EditorToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'ExitNoPrompt')
@@ -23,6 +23,25 @@ class TestSurfaceMaskFilter_BasicSurfaceTagCreation(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="TestSurfaceMaskFilter_BasicSurfaceTagCreation", args=["level"])
def run_test(self):
"""
Summary:
Verifies basic surface tag value equality
Expected Behavior:
Surface tags of the same name are equal, and different names aren't.
Test Steps:
1) Open level
2) Create 2 new surface tags of identical names and verify they resolve as equal.
3) Create another new tag of a different name and verify they resolve as different.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
self.log("SurfaceTag test started")
# Create a level
@@ -33,6 +33,25 @@ class TestVegetationInstances_DespawnWhenOutOfRange(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix='VegetationInstances_DespawnWhenOutOfRange', args=['level'])
def run_test(self):
"""
Summary:
Verifies that vegetation instances properly spawn/despawn based on camera range.
Expected Behavior:
Vegetation instances despawn when out of camera range.
Test Steps:
1) Create a new level
2) Create a simple vegetation area, and set the view position near the spawner. Verify instances plant.
3) Move the view position away from the spawner. Verify instances despawn.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new level
self.test_success = self.create_level(
@@ -28,8 +28,21 @@ class TestGradientGeneratorIncompatibilities(EditorTestHelper):
def run_test(self):
"""
Summary:
Verify that Entities are not active when a Gradient Generator and incompatible component are both present
on the same Entity.
This test verifies that components are disabled when conflicting components are present on the same entity.
Expected Behavior:
Gradient Generator components are incompatible with Vegetation area components.
Test Steps:
1) Create a new level
2) Create a new entity in the level
3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity
4) Verify that components are only enabled when entity is free of a conflicting component
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -28,8 +28,21 @@ class TestGradientModifiersIncompatibilities(EditorTestHelper):
def run_test(self):
"""
Summary:
Verify that Entities are not active when a Gradient Modifier and incompatible component are both present
on the same Entity.
This test verifies that components are disabled when conflicting components are present on the same entity.
Expected Behavior:
Gradient Modifier components are incompatible with Vegetation area components.
Test Steps:
1) Create a new level
2) Create a new entity in the level
3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity
4) Verify that components are only enabled when entity is free of a conflicting component
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -9,19 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
"""
The below cases are combined in this script
C2676829
C3961326
C3980659
C3980664
C3980669
C3416548
C2676823
C3961321
C2676826
"""
import os
import sys
@@ -44,7 +44,21 @@ class TestGradientPreviewSettings(EditorTestHelper):
def run_test(self):
"""
Summary:
Verify if the current entity is set to the pin preview to shape entity by default for several components.
This test verifies default values for the pinned entity for Gradient Preview settings.
Expected Behavior:
Pinned entity is self for all gradient generator/modifiers.
Test Steps:
1) Create a new level
2) Create a new entity in the level
3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to
self
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -31,11 +31,21 @@ class TestGradientSurfaceTagEmitterDependencies(EditorTestHelper):
def run_test(self):
"""
Summary:
Component has a dependency on a Gradient component
This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component.
Expected Result:
Component is disabled until a Gradient Generator, Modifier or Gradient Reference component
(and any sub-dependencies) is added to the entity.
Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference
component (and any sub-dependencies) is added to the entity.
Test Steps:
1) Open level
2) Create a new entity with a Gradient Surface Tag Emitter component
3) Verify the component is disabled until a dependent component is also added to the entity
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -28,8 +28,20 @@ class TestGradientTransformRequiresShape(EditorTestHelper):
def run_test(self):
"""
Summary:
Verify that Gradient Transform Modifier component requires a
Shape component before the Entity can become active.
This test verifies that the Gradient Transform Modifier component is dependent on a shape component.
Expected Result:
Gradient Transform Modifier component is disabled until a shape component is added to the entity.
Test Steps:
1) Open level
2) Create a new entity with a Gradient Transform Modifier component
3) Verify the component is disabled until a shape component is also added to the entity
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -28,8 +28,20 @@ class TestImageGradientRequiresShape(EditorTestHelper):
def run_test(self):
"""
Summary:
Verify that Image Gradient component requires a
Shape component before the Entity can become active.
This test verifies that the Image Gradient component is dependent on a shape component.
Expected Result:
Gradient Transform Modifier component is disabled until a shape component is added to the entity.
Test Steps:
1) Open level
2) Create a new entity with a Image Gradient component
3) Verify the component is disabled until a shape component is also added to the entity
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -33,6 +33,26 @@ class TestAreaNodeComponentDependency(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="AreaNodeComponentDependency", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with
proper dependent components.
Expected Behavior:
All expected component dependencies are met when adding an area node to a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -33,7 +33,25 @@ class TestGradientNodeEntityCreate(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityCreate", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities.
Expected Behavior:
New entities are created when dragging area nodes to graph area.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the area nodes to the graph area, and ensure a new entity is created
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
newEntityId = parameters[0]
@@ -34,7 +34,26 @@ class TestAreaNodeEntityDelete(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityDelete", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor.
Expected Behavior:
Entities are removed when area nodes are deleted from a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the area nodes to the graph area, and ensure a new entity is created
4) Delete the nodes, and ensure the newly created entities are removed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global createdEntityId
createdEntityId = parameters[0]
@@ -9,24 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
"""
C22602072 - Graph is updated when underlying components are added/removed
1. Open Level.
2. Find LandscapeCanvas named entity.
3. Ensure Vegetation Distribution Component is present on the BushSpawner entity.
4. Open graph and ensure Distribution Filter wrapped node is present.
5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector.
6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is no longer
present in the graph.
7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector.
8. Ensure Altitude Filter was added to the BushSpawner node in the open graph.
9. Add a new entity with unique name as a child of the Landscape Canvas entity.
10. Add a Box Shape component to the new child entity.
11. Ensure Box Shape node is present on the open graph.
"""
import os
import sys
@@ -50,6 +32,36 @@ class TestComponentUpdatesUpdateGraph(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="ComponentUpdatesUpdateGraph", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of
Landscape Canvas.
Expected Behavior:
Graphs properly reflect component changes made to entities outside of Landscape Canvas.
Test Steps:
1. Open Level
2. Find LandscapeCanvas named entity
3. Ensure Vegetation Distribution Component is present on the BushSpawner entity
4. Open graph and ensure Distribution Filter wrapped node is present
5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector
6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is
no longer present in the graph
7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector
8. Ensure Altitude Filter was added to the BushSpawner node in the open graph
9. Add a new entity with unique name as a child of the Landscape Canvas entity
10. Add a Box Shape component to the new child entity
11. Ensure Box Shape node is present on the open graph
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level and instantiate LC_BushFlowerBlender.slice
self.test_success = self.create_level(
self.args["level"],
@@ -37,6 +37,25 @@ class TestCreateNewGraph(EditorTestHelper):
print("New root entity created")
def run_test(self):
"""
Summary:
This test verifies that new graphs can be created in Landscape Canvas.
Expected Behavior:
New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Ensures the root entity created contains a Landscape Canvas component
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=128,
@@ -33,7 +33,25 @@ class TestDisabledNodeDuplication(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="DisabledNodeDuplication", args=["level"])
def run_test(self):
"""
Summary:
This test verifies Editor stability after duplicating disabled Landscape Canvas nodes.
Expected Behavior:
Editor remains stable and free of crashes.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
newEntityId = parameters[0]
@@ -9,17 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
"""
C30813586 - Editor remains stable after Undoing deletion of a node on a slice entity
1. Open level with instantiated slice.
2. Open the graph.
3. Find the BushSpawner's Vegetation Layer Spawner node.
4. Delete the node.
5. Undo to restore the node.
"""
import os
import sys
@@ -44,7 +33,26 @@ class TestUndoNodeDeleteSlice(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="UndoNodeDeleteSlice", args=["level"])
def run_test(self):
"""
Summary:
This test verifies Editor stability after undoing the deletion of nodes on a slice entity.
Expected Behavior:
Editor remains stable and free of crashes.
Test Steps:
1) Create a new level
2) Instantiate a slice with a Landscape Canvas setup
3) Find a specific node on the graph, and delete it
4) Restore the node with Undo
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level and instantiate LC_BushFlowerBlender.slice
self.test_success = self.create_level(
self.args["level"],
@@ -34,6 +34,27 @@ class TestGradientMixerNodeConstruction(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientMixerNodeConstruction", args=["level"])
def run_test(self):
"""
Summary:
This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas.
Expected Behavior:
Entities contain all required components and component references after creating nodes and setting connections
on a Landscape Canvas graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup
4) Verify all components and component references were properly set during graph construction
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -33,6 +33,25 @@ class TestGradientModifierNodeEntityCreate(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityCreate", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities.
Expected Behavior:
New entities are created when dragging Gradient Modifier nodes to graph area.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -34,7 +34,26 @@ class TestGradientModifierNodeEntityDelete(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityDelete", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor.
Expected Behavior:
Entities are removed when Gradient Modifier nodes are deleted from a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created
4) Delete the nodes, and ensure the newly created entities are removed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global createdEntityId
createdEntityId = parameters[0]
@@ -33,6 +33,27 @@ class TestGradientNodeComponentDependency(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientNodeComponentDependency", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with
proper dependent components.
Expected Behavior:
All expected component dependencies are met when adding a Gradient Modifier node to a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are
added
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -32,6 +32,25 @@ class TestGradientNodeEntityCreate(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityCreate", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities.
Expected Behavior:
New entities are created when dragging Gradient nodes to graph area.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -34,6 +34,26 @@ class TestGradientNodeEntityDelete(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityDelete", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor.
Expected Behavior:
Entities are removed when Gradient nodes are deleted from a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created
4) Delete the nodes, and ensure the newly created entities are removed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global createdEntityId
@@ -31,6 +31,26 @@ class TestGraphClosedOnEntityDelete(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GraphClosedOnEntityDelete", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted.
Expected Behavior:
When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Delete the automatically created entity
4) Verify the open graph is closed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newRootEntityId
@@ -29,7 +29,26 @@ class TestGraphClosedOnLevelChange(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GraphClosedOnLevelChange", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes.
Expected Behavior:
When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Open a different level
4) Verify the open graph is closed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level
self.test_success = self.create_level(
self.args["level"],
@@ -29,6 +29,26 @@ class TestGraphClosedTabbedGraph(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GraphClosedTabbedGraph", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that Landscape Canvas tabbed graphs can be independently closed.
Expected Behavior:
Closing a tabbed graph only closes the appropriate graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create several new graphs
3) Close one of the open graphs
4) Ensure the graph properly closed, and other open graphs remain open
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level
self.test_success = self.create_level(
@@ -9,21 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
"""
C22715182 - Components are updated when nodes are added/removed/updated
1. Open Level.
2. Open the graph on LC_BushFlowerBlender.slice
3. Find the Rotation Modifier node on the BushSpawner entity
4. Delete the Rotation Modifier node
5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity
6. Delete the Vegetation Layer Spawner node from the graph
7. Ensure BushSpawner entity is deleted
8. Change connection from second Rotation Modifier node to a different Gradient
9. Ensure Gradient reference on component is updated
"""
import os
import sys
@@ -50,6 +35,31 @@ class TestGraphUpdatesUpdateComponents(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="GraphUpdatesUpdateComponents", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that components are properly updated as nodes are added/removed/updated.
Expected Behavior:
Landscape Canvas node CRUD properly updates component entities.
Test Steps:
1. Open Level.
2. Open the graph on LC_BushFlowerBlender.slice
3. Find the Rotation Modifier node on the BushSpawner entity
4. Delete the Rotation Modifier node
5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity
6. Delete the Vegetation Layer Spawner node from the graph
7. Ensure BushSpawner entity is deleted
8. Change connection from second Rotation Modifier node to a different Gradient
9. Ensure Gradient reference on component is updated
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level and instantiate LC_BushFlowerBlender.slice
self.test_success = self.create_level(
self.args["level"],
@@ -30,6 +30,26 @@ class TestLandscapeCanvasComponentAddedRemoved(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="LandscapeCanvasComponentAddedRemoved", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas component can be added to/removed from an entity.
Expected Behavior:
Closing a tabbed graph only closes the appropriate graph.
Test Steps:
1) Create a new level
2) Create a new entity
3) Add a Landscape Canvas component to the entity
4) Remove the Landscape Canvas component from the entity
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Create a new empty level
self.test_success = self.create_level(
@@ -30,12 +30,21 @@ class TestLandscapeCanvasSliceCreateInstantiate(EditorTestHelper):
def run_test(self):
"""
Summary:
C22602016 A slice containing the LandscapeCanvas component can be created/instantiated.
A slice containing the LandscapeCanvas component can be created/instantiated.
Expected Result:
Slice is created and processed successfully and free of errors/warnings.
Another copy of the slice is instantiated.
Slice is created/processed/instantiated successfully and free of errors/warnings.
Test Steps:
1) Create a new level
2) Create a new entity with a Landscape Canvas component
3) Create a slice of the new entity
4) Instantiate a new copy of the slice
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
@@ -34,6 +34,27 @@ class TestLayerBlenderNodeConstruction(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="LayerBlenderNodeConstruction", args=["level"])
def run_test(self):
"""
Summary:
This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas.
Expected Behavior:
Entities contain all required components and component references after creating nodes and setting connections
on a Landscape Canvas graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup
4) Verify all components and component references were properly set during graph construction
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -34,6 +34,25 @@ class TestLayerExtenderNodeComponentEntitySync(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="LayerExtenderNodeComponentEntitySync", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes.
Expected Behavior:
All wrapped extender nodes can be added to/removed from appropriate parent nodes.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -33,6 +33,25 @@ class TestShapeNodeEntityCreate(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityCreate", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities.
Expected Behavior:
New entities are created when dragging shape nodes to graph area.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the shape nodes to the graph area, and ensure a new entity is created
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global newEntityId
@@ -34,7 +34,27 @@ class TestShapeNodeEntityDelete(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityDelete", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor.
Expected Behavior:
Entities are removed when shape nodes are deleted from a graph.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Drag each of the shape nodes to the graph area, and ensure a new entity is created
4) Delete the nodes, and ensure the newly created entities are removed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
def onEntityCreated(parameters):
global createdEntityId
createdEntityId = parameters[0]
@@ -33,6 +33,27 @@ class TestSlotConnectionsUpdateComponents(EditorTestHelper):
EditorTestHelper.__init__(self, log_prefix="SlotConnectionsUpdateComponents", args=["level"])
def run_test(self):
"""
Summary:
This test verifies that the Landscape Canvas slot connections properly update component references.
Expected Behavior:
A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector.
Test Steps:
1) Create a new level
2) Open Landscape Canvas and create a new graph
3) Several nodes are added to a graph, and connections are set between the nodes
4) Component references are verified via Entity Inspector
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Retrieve the proper component TypeIds per component name
componentNames = [
'Random Noise Gradient',
@@ -172,78 +172,10 @@ namespace AZ
//! Rotation modifiers
//! @{
//! @deprecated Use SetLocalRotation()
//! Sets the entity's rotation in the world.
//! The origin of the axes is the entity's position in world space.
//! @param eulerAnglesRadians A three-dimensional vector, containing Euler angles in radians, to rotate the entity by.
virtual void SetRotation([[maybe_unused]] const AZ::Vector3& eulerAnglesRadians) {}
//! @deprecated Use SetLocalRotation()
//! Sets the entity's rotation around the world's X axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The X coordinate Euler angle in radians to use for the entity's rotation.
virtual void SetRotationX([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use SetLocalRotation()
//! Sets the entity's rotation around the world's Y axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The Y coordinate Euler angle in radians to use for the entity's rotation.
virtual void SetRotationY([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use SetLocalRotation()
//! Sets the entity's rotation around the world's Z axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The Z coordinate Euler angle in radians to use for the entity's rotation.
virtual void SetRotationZ([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use SetLocalRotationQuaternion()
//! Sets the entity's rotation in the world in quaternion notation.
//! The origin of the axes is the entity's position in world space.
//! @param quaternion A quaternion that represents the rotation to use for the entity.
virtual void SetRotationQuaternion([[maybe_unused]] const AZ::Quaternion& quaternion) {}
//! @deprecated Use RotateAroundLocalX()
//! Rotates the entity around the world's X axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The Euler angle in radians by which to rotate the entity around the X axis.
virtual void RotateByX([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use RotateAroundLocalY()
//! Rotates the entity around the world's Y axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The Euler angle in radians by which to rotate the entity around the Y axis.
virtual void RotateByY([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use RotateAroundLocalZ()
//! Rotates the entity around the world's Z axis.
//! The origin of the axis is the entity's position in world space.
//! @param eulerAngleRadians The Euler angle in radians by which to rotate the entity around the Z axis.
virtual void RotateByZ([[maybe_unused]] float eulerAngleRadian) {}
//! @deprecated Use GetLocalRotation()
//! Gets the entity's rotation in the world in Euler angles rotation in radians.
//! @return A three-dimensional vector, containing Euler angles in radians, that represents the entity's rotation.
virtual AZ::Vector3 GetRotationEulerRadians() { return AZ::Vector3(FLT_MAX); }
//! @deprecated Use GetLocalRotationQuaternion()
//! Gets the entity's rotation in the world in quaternion format.
//! @return A quaternion that represents the entity's rotation in world space.
virtual AZ::Quaternion GetRotationQuaternion() { return AZ::Quaternion::CreateZero(); }
//! @deprecated Use GetLocalRotation()
//! Gets the entity's rotation around the world's X axis.
//! @return The Euler angle in radians by which the the entity is rotated around the X axis in world space.
virtual float GetRotationX() { return FLT_MAX; }
//! @deprecated Use GetLocalRotation()
//! Gets the entity's rotation around the world's Y axis.
//! @return The Euler angle in radians by which the the entity is rotated around the Y axis in world space.
virtual float GetRotationY() { return FLT_MAX; }
//! @deprecated Use GetLocalRotation()
//! Gets the entity's rotation around the world's Z axis.
//! @return The Euler angle in radians by which the the entity is rotated around the Z axis in world space.
virtual float GetRotationZ() { return FLT_MAX; }
virtual void SetWorldRotationQuaternion([[maybe_unused]] const AZ::Quaternion& quaternion) {}
//! Get angles in radian for each principle axis around which the world transform is
//! rotated in the order of z-axis and y-axis and then x-axis.
@@ -35,7 +35,7 @@ namespace AZ
return "Android";
case AZ::IOS:
return "iOS";
case AZ::MAC:
case AZ::MAC_ID:
return "Mac";
case AZ::PROVO:
return "Provo";
@@ -213,7 +213,7 @@ namespace AZ
case PlatformId::IOS:
platformCodes.emplace_back(PlatformCodeNameiOS);
break;
case PlatformId::MAC:
case PlatformId::MAC_ID:
platformCodes.emplace_back(PlatformCodeNameMac);
break;
case PlatformId::PROVO:
@@ -56,7 +56,7 @@ namespace AZ
PC,
ANDROID_ID,
IOS,
MAC,
MAC_ID,
PROVO,
SALEM,
JASPER,
@@ -75,7 +75,7 @@ namespace AZ
Platform_PC = 1 << PlatformId::PC,
Platform_ANDROID = 1 << PlatformId::ANDROID_ID,
Platform_IOS = 1 << PlatformId::IOS,
Platform_MAC = 1 << PlatformId::MAC,
Platform_MAC = 1 << PlatformId::MAC_ID,
Platform_PROVO = 1 << PlatformId::PROVO,
Platform_SALEM = 1 << PlatformId::SALEM,
Platform_JASPER = 1 << PlatformId::JASPER,
@@ -13,5 +13,5 @@
namespace AZ
{
static const PlatformID g_currentPlatform = PlatformID::PLATFORM_APPLE_OSX;
static const PlatformID g_currentPlatform = PlatformID::PLATFORM_APPLE_MAC;
}
@@ -2008,13 +2008,12 @@ namespace AZ::IO
// if no bind root is specified, compute one:
strBindRoot = !bindRoot.empty() ? bindRoot : szFullPath->ParentPath().Native();
// Check if archive file disk exist on disk or inside of pak.
bool bFileExists = IsFileExist(szFullPath->Native());
if (!bFileExists && (nFactoryFlags & ZipDir::CacheFactory::FLAGS_READ_ONLY))
// Check if archive file disk exist on disk.
const bool pakOnDisk = FileIOBase::GetDirectInstance()->Exists(szFullPath->c_str());
if (!pakOnDisk && (nFactoryFlags & ZipDir::CacheFactory::FLAGS_READ_ONLY))
{
// Archive file not found.
AZ_TracePrintf("Archive", "Cannot open Archive file %s\n", szFullPath->c_str());
AZ_TracePrintf("Archive", "Archive file %s does not exist\n", szFullPath->c_str());
return nullptr;
}
@@ -2492,8 +2491,6 @@ namespace AZ::IO
void Archive::FindCompressionInfo(bool& found, AZ::IO::CompressionInfo& info, const AZStd::string_view filename)
{
constexpr uint32_t s_compressionTag = static_cast<uint32_t>('Z') << 24 | static_cast<uint32_t>('C') << 16 | static_cast<uint32_t>('R') << 8 | static_cast<uint32_t>('Y');
if (!found)
{
auto correctedFilename = AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(filename);
@@ -2519,7 +2516,6 @@ namespace AZ::IO
found = true;
info.m_archiveFilename.InitFromRelativePath(archive->GetFilePath());
info.m_compressionTag.m_code = s_compressionTag;
info.m_offset = pFileData->GetFileDataOffset();
info.m_compressedSize = entry->desc.lSizeCompressed;
info.m_uncompressedSize = entry->desc.lSizeUncompressed;
@@ -2539,9 +2535,8 @@ namespace AZ::IO
break;
}
info.m_decompressor = [&s_compressionTag]([[maybe_unused]] const AZ::IO::CompressionInfo& info, const void* compressed, size_t compressedSize, void* uncompressed, size_t uncompressedBufferSize)->bool
info.m_decompressor = []([[maybe_unused]] const AZ::IO::CompressionInfo& info, const void* compressed, size_t compressedSize, void* uncompressed, size_t uncompressedBufferSize)->bool
{
AZ_Assert(info.m_compressionTag.m_code == s_compressionTag, "Provided compression info isn't supported by this decompressor.");
size_t nSizeUncompressed = uncompressedBufferSize;
return ZipDir::ZipRawUncompress(uncompressed, &nSizeUncompressed, compressed, compressedSize) == 0;
};
@@ -50,6 +50,7 @@ namespace AZ::IO
, tWrite{ writeTime }
{
}
ArchiveFileIterator::ArchiveFileIterator(FindData* findData, AZStd::string_view filename, const FileDesc& fileDesc)
: m_findData{ findData }
, m_filename{ filename }
@@ -108,13 +109,10 @@ namespace AZ::IO
AZ::StringFunc::Path::GetFullPath(directory.c_str(), searchDirectory);
AZ::StringFunc::Path::GetFullFileName(directory.c_str(), pattern);
}
AZ::IO::FileIOBase::GetDirectInstance()->FindFiles(searchDirectory.c_str(), pattern.c_str(), [&](const char* filePath) -> bool
{
AZ::IO::FileDesc fileDesc;
AZStd::string fullFilePath;
AZ::StringFunc::Path::GetFullFileName(filePath, fullFilePath);
AZStd::string filePathEntry{filePath};
if (AZ::IO::FileIOBase::GetDirectInstance()->IsDirectory(filePath))
{
@@ -135,9 +133,8 @@ namespace AZ::IO
fileDesc.tAccess = fileDesc.tWrite;
fileDesc.tCreate = fileDesc.tWrite;
}
[[maybe_unused]] auto result = m_mapFiles.emplace(AZStd::move(fullFilePath), fileDesc);
AZ_Assert(result.second, "Failed to insert FindData entry for %s", fullFilePath.c_str());
[[maybe_unused]] auto result = m_mapFiles.emplace(AZStd::move(filePathEntry), fileDesc);
AZ_Assert(result.second, "Failed to insert FindData entry for filePath %s", filePath);
return true;
});
}
@@ -273,7 +270,9 @@ namespace AZ::IO
}
auto pakFileIter = m_mapFiles.begin();
fileIterator.m_filename = pakFileIter->first;
AZStd::string fullFilePath;
AZ::StringFunc::Path::GetFullFileName(pakFileIter->first.c_str(), fullFilePath);
fileIterator.m_filename = AZStd::move(fullFilePath);
fileIterator.m_fileDesc = pakFileIter->second;
fileIterator.m_lastFetchValid = true;
@@ -1,22 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzFramework
{
@@ -64,15 +64,13 @@ namespace AzFramework
the EditContext. TController can friend itself to the editor component to make this work if required.
*/
template<typename TController, typename TConfiguration = AZ::ComponentConfig>
class ComponentAdapter
: public AZ::Component
class ComponentAdapter : public AZ::Component
{
public:
AZ_RTTI((ComponentAdapter, "{644A9187-4FDB-42C1-9D59-DD75304B551A}", TController, TConfiguration), AZ::Component);
ComponentAdapter() = default;
ComponentAdapter(const TConfiguration& configuration);
explicit ComponentAdapter(const TConfiguration& configuration);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
@@ -85,7 +83,6 @@ namespace AzFramework
void Deactivate() override;
protected:
static void Reflect(AZ::ReflectContext* context);
// AZ::Component overrides ...
@@ -1,14 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Components/ComponentAdapterHelpers.h>
@@ -32,10 +32,12 @@ namespace AzFramework
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
// clang-format off
serializeContext->Class<ComponentAdapter, Component>()
->Version(1)
->Field("Controller", &ComponentAdapter::m_controller)
;
// clang-format on
}
}
@@ -66,9 +68,6 @@ namespace AzFramework
GetDependentServicesHelper<TController>(services, typename AZ::HasComponentDependentServices<TController>::type());
}
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
template<typename TController, typename TConfiguration>
void ComponentAdapter<TController, TConfiguration>::Init()
{
@@ -78,7 +77,7 @@ namespace AzFramework
template<typename TController, typename TConfiguration>
void ComponentAdapter<TController, TConfiguration>::Activate()
{
m_controller.Activate(GetEntityId());
ComponentActivateHelper<TController>::Activate(m_controller, AZ::EntityComponentIdPair(GetEntityId(), GetId()));
}
template<typename TController, typename TConfiguration>
@@ -13,6 +13,7 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/EntityBus.h>
namespace AzFramework
{
@@ -27,18 +28,43 @@ namespace AzFramework
template<typename T, typename = void>
struct ComponentInitHelper
{
static void Init(T& common)
static void Init([[maybe_unused]] T& controller)
{
AZ_UNUSED(common);
}
};
template<typename T>
struct ComponentInitHelper<T, AZStd::void_t<decltype(AZStd::declval<T>().Init())>>
{
static void Init(T& common)
static void Init(T& controller)
{
common.Init();
controller.Init();
}
};
template<typename T, typename = void>
struct ComponentActivateHelper
{
static void Activate([[maybe_unused]] T& controller, [[maybe_unused]] const AZ::EntityComponentIdPair& entityComponentIdPair)
{
}
};
template<typename T>
struct ComponentActivateHelper<T, AZStd::void_t<decltype(AZStd::declval<T>().Activate(AZ::EntityId()))>>
{
static void Activate(T& controller, const AZ::EntityComponentIdPair& entityComponentIdPair)
{
controller.Activate(entityComponentIdPair.GetEntityId());
}
};
template<typename T>
struct ComponentActivateHelper<T, AZStd::void_t<decltype(AZStd::declval<T>().Activate(AZ::EntityComponentIdPair()))>>
{
static void Activate(T& controller, const AZ::EntityComponentIdPair& entityComponentIdPair)
{
controller.Activate(entityComponentIdPair);
}
};
@@ -327,99 +327,13 @@ namespace AzFramework
return localZ;
}
void TransformComponent::SetRotation(const AZ::Vector3& eulerAnglesRadian)
void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ_Warning("TransformComponent", false, "SetRotation is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(AZ::ConvertEulerRadiansToQuaternion(eulerAnglesRadian));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ_Warning("TransformComponent", false, "SetRotationQuaternion is deprecated, please use SetLocalRotationQuaternion");
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(quaternion);
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationX(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "SetRotationX is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationX(eulerAngleRadian));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationY(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "SetRotationY is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationY(eulerAngleRadian));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationZ(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "SetRotationZ is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = m_worldTM;
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationZ(eulerAngleRadian));
SetWorldTM(newWorldTransform);
}
void TransformComponent::RotateByX(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "RotateByX is deprecated, please use RotateAroundLocalX");
RotateAroundLocalX(eulerAngleRadian);
}
void TransformComponent::RotateByY(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "RotateByY is deprecated, please use RotateAroundLocalY");
RotateAroundLocalY(eulerAngleRadian);
}
void TransformComponent::RotateByZ(float eulerAngleRadian)
{
AZ_Warning("TransformComponent", false, "RotateByZ is deprecated, please use RotateAroundLocalZ");
RotateAroundLocalZ(eulerAngleRadian);
}
AZ::Vector3 TransformComponent::GetRotationEulerRadians()
{
AZ_Warning("TransformComponent", false, "GetRotationEulerRadians is deprecated, please use GetWorldRotation");
return m_worldTM.GetRotation().GetEulerRadians();
}
AZ::Quaternion TransformComponent::GetRotationQuaternion()
{
AZ_Warning("TransformComponent", false, "GetRotationQuaternion is deprecated, please use GetWorldRotationQuaternion");
return m_worldTM.GetRotation();
}
float TransformComponent::GetRotationX()
{
AZ_Warning("TransformComponent", false, "GetRotationX is deprecated, please use GetWorldRotation");
return GetRotationEulerRadians().GetX();
}
float TransformComponent::GetRotationY()
{
AZ_Warning("TransformComponent", false, "GetRotationY is deprecated, please use GetWorldRotation");
return GetRotationEulerRadians().GetY();
}
float TransformComponent::GetRotationZ()
{
AZ_Warning("TransformComponent", false, "GetRotationZ is deprecated, please use GetWorldRotation");
return GetRotationEulerRadians().GetZ();
}
AZ::Vector3 TransformComponent::GetWorldRotation()
{
return m_worldTM.GetRotation().GetEulerRadians();
@@ -830,45 +744,7 @@ namespace AzFramework
->Event("GetLocalX", &AZ::TransformBus::Events::GetLocalX)
->Event("GetLocalY", &AZ::TransformBus::Events::GetLocalY)
->Event("GetLocalZ", &AZ::TransformBus::Events::GetLocalZ)
->Event("RotateByX", &AZ::TransformBus::Events::RotateByX)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("RotateByY", &AZ::TransformBus::Events::RotateByY)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("RotateByZ", &AZ::TransformBus::Events::RotateByZ)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetEulerRotation", &AZ::TransformBus::Events::SetRotation)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetRotationQuaternion", &AZ::TransformBus::Events::SetRotationQuaternion)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetRotationX", &AZ::TransformBus::Events::SetRotationX)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetRotationY", &AZ::TransformBus::Events::SetRotationY)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetRotationZ", &AZ::TransformBus::Events::SetRotationZ)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("GetEulerRotation", &AZ::TransformBus::Events::GetRotationEulerRadians)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("GetRotationQuaternion", &AZ::TransformBus::Events::GetRotationQuaternion)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("GetRotationX", &AZ::TransformBus::Events::GetRotationX)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("GetRotationY", &AZ::TransformBus::Events::GetRotationY)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("GetRotationZ", &AZ::TransformBus::Events::GetRotationZ)
->Attribute(AZ::Script::Attributes::Deprecated, true)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Event("SetWorldRotationQuaternion", &AZ::TransformBus::Events::SetWorldRotationQuaternion)
->Event("GetWorldRotation", &AZ::TransformBus::Events::GetWorldRotation)
->Event("GetWorldRotationQuaternion", &AZ::TransformBus::Events::GetWorldRotationQuaternion)
->Event("SetLocalRotation", &AZ::TransformBus::Events::SetLocalRotation)
@@ -112,22 +112,7 @@ namespace AzFramework
float GetLocalZ() override;
// Rotation modifiers
void SetRotation(const AZ::Vector3& eulerAnglesRadian) override;
void SetRotationQuaternion(const AZ::Quaternion& quaternion) override;
void SetRotationX(float eulerAngleRadian) override;
void SetRotationY(float eulerAngleRadian) override;
void SetRotationZ(float eulerAngleRadian) override;
void RotateByX(float eulerAngleRadian) override;
void RotateByY(float eulerAngleRadian) override;
void RotateByZ(float eulerAngleRadian) override;
AZ::Vector3 GetRotationEulerRadians() override;
AZ::Quaternion GetRotationQuaternion() override;
float GetRotationX() override;
float GetRotationY() override;
float GetRotationZ() override;
void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override;
AZ::Vector3 GetWorldRotation() override;
AZ::Quaternion GetWorldRotationQuaternion() override;
@@ -102,7 +102,7 @@ namespace Physics
/// Is the ragdoll currently simulated?
/// @result True in case the ragdoll is simulated, false if not.
virtual bool IsSimulated() = 0;
virtual bool IsSimulated() const = 0;
/// Writes the state for all of the bodies in the ragdoll to the provided output.
/// The caller owns the output state and can safely manipulate it without affecting the physics simulation.
@@ -57,6 +57,6 @@ namespace AzToolsFramework
virtual void StartPlayInEditor() = 0;
virtual void StopPlayInEditor() = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename) = 0;
virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0;
};
}
@@ -265,7 +265,7 @@ namespace AzToolsFramework
return false;
}
void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename)
void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename)
{
AZ::IO::Path relativePath = m_loaderInterface->GetRelativePathToProject(filename);
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
@@ -276,7 +276,7 @@ namespace AzToolsFramework
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, DefaultLevelTemplateName,
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, templateFilename.c_str(),
assetInfo, watchFolder);
if (sourceInfoFound)
@@ -292,7 +292,7 @@ namespace AzToolsFramework
levelDefaultDom.CopyFrom(dom, levelDefaultDom.GetAllocator());
Prefab::PrefabDomPath sourcePath("/Source");
sourcePath.Set(levelDefaultDom, assetInfo.m_relativePath.c_str());
sourcePath.Set(levelDefaultDom, relativePath.c_str());
templateId = m_prefabSystemComponent->AddTemplate(relativePath, AZStd::move(levelDefaultDom));
}
@@ -170,7 +170,7 @@ namespace AzToolsFramework
void StartPlayInEditor() override;
void StopPlayInEditor() override;
void CreateNewLevelPrefab(AZStd::string_view filename) override;
void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) override;
protected:
@@ -218,7 +218,5 @@ namespace AzToolsFramework
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
AZ::SerializeContext m_serializeContext;
static inline constexpr const char* DefaultLevelTemplateName = "Prefabs/Default_Level.prefab";
};
}
@@ -614,7 +614,7 @@ namespace AzToolsFramework
AZ::Quaternion oldEntityRotation;
AZ::TransformBus::EventResult(oldEntityRotation, id, &AZ::TransformBus::Events::GetWorldRotationQuaternion);
transformComponent->SetRotationQuaternion(oldEntityRotation);
transformComponent->SetWorldRotationQuaternion(oldEntityRotation);
// Ensure the existing hierarchy is maintained
AZ::EntityId oldParentEntityId;
@@ -31,7 +31,7 @@ namespace AzToolsFramework
rayProportion, lineSegmentProportion, worldClosestPositionRay, worldClosestPositionLineSegment);
AZ::Transform worldFromLocalNormalized = worldFromLocal;
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractScale() * nonUniformScale;
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractUniformScale() * nonUniformScale;
const AZ::Transform localFromWorldNormalized = worldFromLocalNormalized.GetInverse();
return { (localFromWorldNormalized.TransformPoint(worldClosestPositionLineSegment)) / scale };
@@ -59,7 +59,7 @@ namespace AzToolsFramework
? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip)
: AZ::Vector3::CreateZero();
const AZ::Vector3 localScale = localTransform.GetScale();
const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale());
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
// calculate scale amount to snap, to align to round scale value
const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping
@@ -113,7 +113,7 @@ namespace AzToolsFramework
/// noise in the value returned when dealing with values far from the origin.
inline float ScaleReciprocal(const AZ::Transform& transform)
{
return Round3(transform.GetScale().GetReciprocal().GetMinElement());
return Round3(1.0f / transform.GetUniformScale());
}
/// Find the reciprocal of the non-uniform scale.
@@ -39,7 +39,7 @@ namespace AzToolsFramework
AZ::Transform result;
result.SetRotation(m_space.GetRotation() * localTransform.GetRotation());
result.SetTranslation(m_space.TransformPoint(m_nonUniformScale * localTransform.GetTranslation()));
result.SetScale(m_space.GetScale() * localTransform.GetScale());
result.SetScale(m_space.GetScale() * localTransform.GetUniformScale());
return result;
}
@@ -1,22 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
namespace AzToolsFramework
{
@@ -31,7 +31,7 @@ namespace AzToolsFramework
To use the EditorComponentAdapter, 3 classes are required:
- a class that implements the functions required for TController (see below)
- a configuration struct/class which extends AZ::ComponentConfig
- A runtime component that will be generated by the editor comoinent on export
- A runtime component that will be generated by the editor component on export
The concrete component extends the adapter and implements behavior which is unique to the component.
@@ -64,15 +64,15 @@ namespace AzToolsFramework
the EditContext. TController can friend itself to the editor component to make this work if required.
*/
template<typename TController, typename TRuntimeComponent, typename TConfiguration = AZ::ComponentConfig>
class EditorComponentAdapter
: public EditorComponentBase
class EditorComponentAdapter : public EditorComponentBase
{
public:
AZ_RTTI((EditorComponentAdapter, "{2F5A3669-FFE9-4CD7-B9E2-7FC8100CF1A2}", TController, TRuntimeComponent, TConfiguration), EditorComponentBase);
AZ_RTTI(
(EditorComponentAdapter, "{2F5A3669-FFE9-4CD7-B9E2-7FC8100CF1A2}", TController, TRuntimeComponent, TConfiguration),
EditorComponentBase);
EditorComponentAdapter() = default;
EditorComponentAdapter(const TConfiguration& configuration);
explicit EditorComponentAdapter(const TConfiguration& configuration);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
@@ -86,7 +86,6 @@ namespace AzToolsFramework
void BuildGameEntity(AZ::Entity* gameEntity) override;
protected:
static void Reflect(AZ::ReflectContext* context);
// AZ::Component overrides ...
@@ -1,14 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Components/ComponentAdapterHelpers.h>
@@ -28,23 +28,21 @@ namespace AzToolsFramework
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorComponentAdapter, EditorComponentBase>()
->Version(1)
->Field("Controller", &EditorComponentAdapter::m_controller)
;
serializeContext->Class<EditorComponentAdapter, EditorComponentBase>()->Version(1)->Field(
"Controller", &EditorComponentAdapter::m_controller);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorComponentAdapter>(
"EditorComponentAdapter", "")
// clang-format off
editContext->Class<EditorComponentAdapter>("EditorComponentAdapter", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorComponentAdapter::m_controller, "Controller", "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorComponentAdapter::OnConfigurationChanged)
;
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorComponentAdapter::OnConfigurationChanged);
// clang-format on
}
}
}
@@ -53,27 +51,35 @@ namespace AzToolsFramework
// Get*Services functions
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetProvidedServices(
AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetProvidedServicesHelper<TController>(services, typename AZ::HasComponentProvidedServices<TController>::type());
AzFramework::Components::GetProvidedServicesHelper<TController>(
services, typename AZ::HasComponentProvidedServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetRequiredServices(
AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetRequiredServicesHelper<TController>(services, typename AZ::HasComponentRequiredServices<TController>::type());
AzFramework::Components::GetRequiredServicesHelper<TController>(
services, typename AZ::HasComponentRequiredServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetIncompatibleServices(
AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetIncompatibleServicesHelper<TController>(services, typename AZ::HasComponentIncompatibleServices<TController>::type());
AzFramework::Components::GetIncompatibleServicesHelper<TController>(
services, typename AZ::HasComponentIncompatibleServices<TController>::type());
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services)
void EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::GetDependentServices(
AZ::ComponentDescriptor::DependencyArrayType& services)
{
AzFramework::Components::GetDependentServicesHelper<TController>(services, typename AZ::HasComponentDependentServices<TController>::type());
AzFramework::Components::GetDependentServicesHelper<TController>(
services, typename AZ::HasComponentDependentServices<TController>::type());
}
//////////////////////////////////////////////////////////////////////////
@@ -99,7 +105,8 @@ namespace AzToolsFramework
if (ShouldActivateController())
{
m_controller.Activate(GetEntityId());
AzFramework::Components::ComponentActivateHelper<TController>::Activate(
m_controller, AZ::EntityComponentIdPair(GetEntityId(), GetId()));
}
}
@@ -122,7 +129,8 @@ namespace AzToolsFramework
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
bool EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>::WriteOutConfig(
AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TConfiguration*>(outBaseConfig))
{
@@ -139,7 +147,8 @@ namespace AzToolsFramework
if (ShouldActivateController())
{
m_controller.Activate(GetEntityId());
AzFramework::Components::ComponentActivateHelper<TController>::Activate(
m_controller, AZ::EntityComponentIdPair(GetEntityId(), GetId()));
}
return AZ::Edit::PropertyRefreshLevels::None;
@@ -520,91 +520,13 @@ namespace AzToolsFramework
return m_editorTransform.m_translate.GetZ();
}
void TransformComponent::SetRotation(const AZ::Vector3& eulerAnglesRadians)
void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotation is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = GetWorldTM();
newWorldTransform.SetRotation(AZ::ConvertEulerRadiansToQuaternion(eulerAnglesRadians));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationQuaternion is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = GetWorldTM();
newWorldTransform.SetRotation(quaternion);
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationX(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationX is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = GetWorldTM();
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationX(eulerAngleRadians));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationY(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationY is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = GetWorldTM();
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationY(eulerAngleRadians));
SetWorldTM(newWorldTransform);
}
void TransformComponent::SetRotationZ(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "SetRotationZ is deprecated, please use SetLocalRotation");
AZ::Transform newWorldTransform = GetWorldTM();
newWorldTransform.SetRotation(AZ::Quaternion::CreateRotationZ(eulerAngleRadians));
SetWorldTM(newWorldTransform);
}
void TransformComponent::RotateByX(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByX is deprecated, please use RotateAroundLocalX");
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationX(eulerAngleRadians));
}
void TransformComponent::RotateByY(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByY is deprecated, please use RotateAroundLocalY");
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationY(eulerAngleRadians));
}
void TransformComponent::RotateByZ(float eulerAngleRadians)
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "RotateByZ is deprecated, please use RotateAroundLocalZ");
SetWorldTM(GetWorldTM() * AZ::Transform::CreateRotationZ(eulerAngleRadians));
}
AZ::Vector3 TransformComponent::GetRotationEulerRadians()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetRotationEulerRadians is deprecated, please use GetWorldRotation");
return GetWorldTM().GetRotation().GetEulerRadians();
}
AZ::Quaternion TransformComponent::GetRotationQuaternion()
{
AZ_Warning("AzToolsFramework::TransformComponent", false, "GetRotationQuaternion is deprecated, please use GetWorldRotationQuaternion");
return GetWorldTM().GetRotation();
}
float TransformComponent::GetRotationX()
{
return GetRotationEulerRadians().GetX();
}
float TransformComponent::GetRotationY()
{
return GetRotationEulerRadians().GetY();
}
float TransformComponent::GetRotationZ()
{
return GetRotationEulerRadians().GetZ();
}
AZ::Vector3 TransformComponent::GetWorldRotation()
{
return GetWorldTM().GetRotation().GetEulerRadians();
@@ -99,22 +99,7 @@ namespace AzToolsFramework
float GetLocalZ() override;
// Rotation modifiers
void SetRotation(const AZ::Vector3& eulerAnglesRadians) override;
void SetRotationQuaternion(const AZ::Quaternion& quaternion) override;
void SetRotationX(float eulerAngleRadians) override;
void SetRotationY(float eulerAngleRadians) override;
void SetRotationZ(float eulerAngleRadians) override;
void RotateByX(float eulerAngleRadians) override;
void RotateByY(float eulerAngleRadians) override;
void RotateByZ(float eulerAngleRadians) override;
AZ::Vector3 GetRotationEulerRadians() override;
AZ::Quaternion GetRotationQuaternion() override;
float GetRotationX() override;
float GetRotationY() override;
float GetRotationZ() override;
void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override;
AZ::Vector3 GetWorldRotation() override;
AZ::Quaternion GetWorldRotationQuaternion() override;
@@ -809,14 +809,12 @@ namespace AzToolsFramework
EntityIdManipulators& entityIdManipulators,
OptionalFrame& pivotOverrideFrame,
ViewportInteraction::KeyboardModifiers& prevModifiers,
bool& transformChangedInternally, SpaceCluster spaceCluster)
bool& transformChangedInternally, const AZStd::optional<ReferenceFrame> spaceLock)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
entityIdManipulators.m_manipulators->SetLocalPosition(action.LocalPosition());
const ReferenceFrame referenceFrame = spaceCluster.m_spaceLock ? spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(action.m_modifiers);
if (action.m_modifiers.Ctrl())
{
// moving with ctrl - setting override
@@ -826,6 +824,8 @@ namespace AzToolsFramework
}
else
{
const ReferenceFrame referenceFrame = spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
// note: used for parent and world depending on the current reference frame
const auto pivotOrientation =
ETCS::CalculateSelectionPivotOrientation(
@@ -1298,7 +1298,7 @@ namespace AzToolsFramework
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
m_transformChangedInternally, m_spaceCluster.m_spaceLock);
});
translationManipulators->InstallLinearManipulatorMouseUpCallback(
@@ -1329,7 +1329,7 @@ namespace AzToolsFramework
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
m_transformChangedInternally, m_spaceCluster.m_spaceLock);
});
translationManipulators->InstallPlanarManipulatorMouseUpCallback(
@@ -1359,7 +1359,7 @@ namespace AzToolsFramework
{
UpdateTranslationManipulator(
action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
m_transformChangedInternally, m_spaceCluster);
m_transformChangedInternally, m_spaceCluster.m_spaceLock);
});
translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
@@ -1437,8 +1437,7 @@ namespace AzToolsFramework
[this, prevModifiers, sharedRotationState]
(const AngularManipulator::Action& action) mutable -> void
{
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock ? m_spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(action.m_modifiers);
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers));
const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
// store the pivot override frame when positioning the manipulator manually (ctrl)
// so we don't lose the orientation when adding/removing entities from the selection
@@ -2605,40 +2604,37 @@ namespace AzToolsFramework
if (buttonId == m_spaceCluster.m_localButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::Local)
if (m_spaceCluster.m_spaceLock.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::Local)
{
m_spaceCluster.m_spaceLock = false;
m_spaceCluster.m_spaceLock = AZStd::nullopt;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::Local;
m_spaceCluster.m_spaceLock = ReferenceFrame::Local;
}
}
else if (buttonId == m_spaceCluster.m_parentButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::Parent)
if (m_spaceCluster.m_spaceLock.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::Parent)
{
m_spaceCluster.m_spaceLock = false;
m_spaceCluster.m_spaceLock = AZStd::nullopt;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::Parent;
m_spaceCluster.m_spaceLock = ReferenceFrame::Parent;
}
}
else if (buttonId == m_spaceCluster.m_worldButtonId)
{
// Unlock
if (m_spaceCluster.m_spaceLock && m_spaceCluster.m_currentSpace == ReferenceFrame::World)
if (m_spaceCluster.m_spaceLock.has_value() && m_spaceCluster.m_spaceLock.value() == ReferenceFrame::World)
{
m_spaceCluster.m_spaceLock = false;
m_spaceCluster.m_spaceLock = AZStd::nullopt;
}
else
{
m_spaceCluster.m_spaceLock = true;
m_spaceCluster.m_currentSpace = ReferenceFrame::World;
m_spaceCluster.m_spaceLock = ReferenceFrame::World;
}
}
};
@@ -3361,8 +3357,7 @@ namespace AzToolsFramework
ViewportInteraction::BuildMouseButtons(
QGuiApplication::mouseButtons()), m_boxSelect.Active());
const ReferenceFrame referenceFrame =
m_spaceCluster.m_spaceLock ? m_spaceCluster.m_currentSpace : ReferenceFrameFromModifiers(modifiers);
const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(modifiers));
UpdateSpaceCluster(referenceFrame);
@@ -106,15 +106,20 @@ namespace AzToolsFramework
World, //!< World space (space aligned to world axes - identity).
};
//! Grouping of viewport ui related state for controlling the current reference space of the Editor.
struct SpaceCluster
{
ViewportUi::ClusterId m_spaceClusterId;
ViewportUi::ButtonId m_localButtonId;
ViewportUi::ButtonId m_parentButtonId;
ViewportUi::ButtonId m_worldButtonId;
AZ::Event<ViewportUi::ButtonId>::Handler m_spaceSelectionHandler;
ReferenceFrame m_currentSpace = ReferenceFrame::Parent;
bool m_spaceLock = false;
SpaceCluster() = default;
// disable copying and moving (implicit)
SpaceCluster(const SpaceCluster&) = delete;
SpaceCluster& operator=(const SpaceCluster&) = delete;
ViewportUi::ClusterId m_spaceClusterId; //!< The id identifying the reference space cluster.
ViewportUi::ButtonId m_localButtonId; //!< Local reference space button id.
ViewportUi::ButtonId m_parentButtonId; //!< Parent reference space button id.
ViewportUi::ButtonId m_worldButtonId; //!< World reference space button id.
AZ::Event<ViewportUi::ButtonId>::Handler m_spaceSelectionHandler; //!< Callback for when a space cluster button is pressed.
AZStd::optional<ReferenceFrame> m_spaceLock; //!< Locked reference frame to use if set.
};
//! Entity selection/interaction handling.
@@ -265,6 +270,9 @@ namespace AzToolsFramework
void SetEntityLocalScale(AZ::EntityId entityId, float localScale);
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation);
// Responsible for keeping the space cluster in sync with the current reference frame.
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any).
AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display.
AZ::EntityId m_editorCameraComponentEntityId; //!< The EditorCameraComponent EntityId if it is set.
@@ -297,9 +305,7 @@ namespace AzToolsFramework
AZ::Event<ViewportUi::ButtonId>::Handler m_transformModeSelectionHandler; //!< Event handler for the Viewport UI cluster.
AzFramework::ClickDetector m_clickDetector; //!< Detect different types of mouse click.
AzFramework::CursorState m_cursorState; //!< Track the mouse position and delta movement each frame.
SpaceCluster m_spaceCluster;
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
SpaceCluster m_spaceCluster; //!< Related viewport ui state for controlling the current reference space.
};
//! The ETCS (EntityTransformComponentSelection) namespace contains functions and data used exclusively by
+1
View File
@@ -173,6 +173,7 @@ ly_add_target(
RUNTIME_DEPENDENCIES
Legacy::CrySystem
Legacy::EditorLib
ProjectManager
)
ly_add_translations(
TARGETS Editor
+1 -1
View File
@@ -3111,7 +3111,7 @@ CCryEditApp::ECreateLevelResult CCryEditApp::CreateLevel(const QString& levelNam
auto* service = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
if (service)
{
service->CreateNewLevelPrefab((const char*)fullyQualifiedLevelName.toUtf8());
service->CreateNewLevelPrefab(fullyQualifiedLevelName.toUtf8().constData(), DefaultLevelTemplateName);
}
}
+2
View File
@@ -358,6 +358,8 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
private:
static inline constexpr const char* DefaultLevelTemplateName = "Prefabs/Default_Level.prefab";
struct PythonOutputHandler;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZStd::shared_ptr<PythonOutputHandler> m_pythonOutputHandler;
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c042fce57915fc749abc7b37de765fd697c3c4d7de045a3d44805aa0ce29901a
size 107016
oid sha256:d717f77fe01f45df934a61bbc215e5322447d21e16f3cebcf2a02f148178f266
size 106449
@@ -14,6 +14,7 @@
#include <AssetImporterPlugin.h>
#include <AssetImporterWindow.h>
#include <QtViewPaneManager.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <LyViewPaneNames.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
@@ -37,6 +38,10 @@ AssetImporterPlugin::AssetImporterPlugin(IEditor* editor)
opt.showInMenu = false; // this view pane is used to display scene settings, but the user never opens it directly through the Tools menu
opt.saveKeyName = "Scene Settings (PREVIEW)"; // user settings for this pane were originally saved with PREVIEW, so ensure that's how they are loaded as well, even after the PREVIEW is removed from the name
AzToolsFramework::RegisterViewPane<AssetImporterWindow>(m_toolName.c_str(), LyViewPane::CategoryTools, opt);
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::CreateAndAddEntityFromComponentTags,
AZStd::vector<AZ::Crc32>({ AZ::SceneAPI::Events::AssetImportRequest::GetAssetImportRequestComponentTag() }), "AssetImportersEntity");
}
void AssetImporterPlugin::Release()
@@ -622,13 +622,14 @@ bool ApplicationManager::Activate()
{
if (!AssetUtilities::ComputeAssetRoot(m_systemRoot))
{
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to compute the asset root for the project, this application cannot launch until this is fixed.");
return false;
}
auto projectName = AssetUtilities::ComputeProjectName();
if (projectName.isEmpty())
{
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to detect name of current game project. Is bootstrap.cfg appropriately configured?");
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to detect name of current game project. Configure your game project name to launch this application.");
return false;
}
@@ -1191,6 +1191,7 @@ bool ApplicationManagerBase::Activate()
QDir projectCache;
if (!AssetUtilities::ComputeProjectCacheRoot(projectCache))
{
AZ_Error("AssetProcessor", false, "Could not compute project cache root, please configure your project correctly to launch Asset Processor.");
return false;
}
@@ -1200,22 +1201,27 @@ bool ApplicationManagerBase::Activate()
// Shutdown if the disk has less than 128MB of free space
if (!CheckSufficientDiskSpace(projectCache.absolutePath(), 128 * 1024 * 1024, true))
{
// CheckSufficientDiskSpace reports an error if disk space is low.
return false;
}
bool appInited = InitApplicationServer();
if (!appInited)
{
AZ_Error(
"AssetProcessor", false, "InitApplicationServer failed, something internal to Asset Processor has failed, please report this to support if you encounter this error.");
return false;
}
if (!InitAssetDatabase())
{
// AssetDatabaseConnection::OpenDatabase reports any errors it encounters.
return false;
}
if (!ApplicationManager::Activate())
{
// ApplicationManager::Activate() reports any errors it encounters.
return false;
}
@@ -1230,6 +1236,7 @@ bool ApplicationManagerBase::Activate()
m_isCurrentlyLoadingGems = true;
if (!ActivateModules())
{
// ActivateModules reports any errors it encounters.
m_isCurrentlyLoadingGems = false;
return false;
}
@@ -1299,6 +1306,7 @@ bool ApplicationManagerBase::Activate()
{
if (!m_applicationServer->startListening())
{
// startListening reports any errors it encounters.
return false;
}
}
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c042fce57915fc749abc7b37de765fd697c3c4d7de045a3d44805aa0ce29901a
size 107016
oid sha256:d717f77fe01f45df934a61bbc215e5322447d21e16f3cebcf2a02f148178f266
size 106449
@@ -38,21 +38,8 @@ namespace AZ
{
namespace FbxSceneBuilder
{
static AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler* g_fbxImporter = nullptr;
static AZStd::vector<AZ::ComponentDescriptor*> g_componentDescriptors;
void Initialize()
{
// Currently it's still needed to explicitly create an instance of this instead of letting
// it be a normal component. This is because ResourceCompilerScene needs to return
// the list of available extensions before it can start the application.
if (!g_fbxImporter)
{
g_fbxImporter = aznew AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler();
g_fbxImporter->Activate();
}
}
void Reflect(AZ::SerializeContext* /*context*/)
{
// Descriptor registration is done in Reflect instead of Initialize because the ResourceCompilerScene initializes the libraries before
@@ -64,6 +51,7 @@ namespace AZ
{
// Global importer and behavior
g_componentDescriptors.push_back(FbxSceneBuilder::FbxImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxSceneImporter::FbxImportRequestHandler::CreateDescriptor());
// Node and attribute importers
g_componentDescriptors.push_back(AssImpBitangentStreamImporter::CreateDescriptor());
@@ -110,13 +98,6 @@ namespace AZ
g_componentDescriptors.clear();
g_componentDescriptors.shrink_to_fit();
}
if (g_fbxImporter)
{
g_fbxImporter->Deactivate();
delete g_fbxImporter;
g_fbxImporter = nullptr;
}
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -125,7 +106,6 @@ namespace AZ
extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env)
{
AZ::Environment::Attach(static_cast<AZ::EnvironmentInstance>(env));
AZ::SceneAPI::FbxSceneBuilder::Initialize();
}
extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context)
{
@@ -10,12 +10,16 @@
*
*/
#include <AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
namespace AZ
{
@@ -23,10 +27,23 @@ namespace AZ
{
namespace FbxSceneImporter
{
const char* FbxImportRequestHandler::s_extension = ".fbx";
void SceneImporterSettings::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext)
{
serializeContext->Class<SceneImporterSettings>()
->Version(2)
->Field("SupportedFileTypeExtensions", &SceneImporterSettings::m_supportedFileTypeExtensions);
}
}
void FbxImportRequestHandler::Activate()
{
if (auto* settingsRegistry = AZ::SettingsRegistry::Get())
{
settingsRegistry->GetObject(m_settings, "/O3DE/SceneAPI/AssetImporter");
}
BusConnect();
}
@@ -37,21 +54,31 @@ namespace AZ
void FbxImportRequestHandler::Reflect(ReflectContext* context)
{
SceneImporterSettings::Reflect(context);
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<FbxImportRequestHandler, SceneCore::BehaviorComponent>()->Version(1);
serializeContext->Class<FbxImportRequestHandler, AZ::Component>()->Version(1)->Attribute(
AZ::Edit::Attributes::SystemComponentTags,
AZStd::vector<AZ::Crc32>(
{AssetBuilderSDK::ComponentTags::AssetBuilder,
AssetImportRequest::GetAssetImportRequestComponentTag()}));
}
}
void FbxImportRequestHandler::GetSupportedFileExtensions(AZStd::unordered_set<AZStd::string>& extensions)
{
extensions.insert(s_extension);
extensions.insert(m_settings.m_supportedFileTypeExtensions.begin(), m_settings.m_supportedFileTypeExtensions.end());
}
Events::LoadingResult FbxImportRequestHandler::LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid, [[maybe_unused]] RequestingApplication requester)
{
if (!AzFramework::StringFunc::Path::IsExtension(path.c_str(), s_extension))
AZStd::string extension;
StringFunc::Path::GetExtension(path.c_str(), extension);
if (!m_settings.m_supportedFileTypeExtensions.contains(extension))
{
return Events::LoadingResult::Ignored;
}
@@ -73,6 +100,11 @@ namespace AZ
return Events::LoadingResult::AssetFailure;
}
}
void FbxImportRequestHandler::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.emplace_back(AZ_CRC_CE("AssetImportRequestHandler"));
}
} // namespace Import
} // namespace SceneAPI
} // namespace AZ
@@ -21,12 +21,21 @@ namespace AZ
{
namespace FbxSceneImporter
{
struct SceneImporterSettings
{
AZ_TYPE_INFO(SceneImporterSettings, "{8BB6C7AD-BF99-44DC-9DA1-E7AD3F03DC10}");
static void Reflect(AZ::ReflectContext* context);
AZStd::unordered_set<AZStd::string> m_supportedFileTypeExtensions;
};
class FbxImportRequestHandler
: public SceneCore::BehaviorComponent
: public AZ::Component
, public Events::AssetImportRequestBus::Handler
{
public:
AZ_COMPONENT(FbxImportRequestHandler, "{9F4B189C-0A96-4F44-A5F0-E087FF1561F8}", SceneCore::BehaviorComponent);
AZ_COMPONENT(FbxImportRequestHandler, "{9F4B189C-0A96-4F44-A5F0-E087FF1561F8}");
~FbxImportRequestHandler() override = default;
@@ -38,8 +47,13 @@ namespace AZ
Events::LoadingResult LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid,
RequestingApplication requester) override;
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
private:
static const char* s_extension;
SceneImporterSettings m_settings;
static constexpr const char* SettingsFilename = "AssetImporterSettings.json";
};
} // namespace FbxSceneImporter
} // namespace SceneAPI
@@ -37,7 +37,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpMeshImporter, SceneCore::LoadingComponent>()->Version(1);
serializeContext->Class<AssImpMeshImporter, SceneCore::LoadingComponent>()->Version(2);
}
}
@@ -71,6 +71,11 @@ namespace AZ
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
using MutexType = AZStd::recursive_mutex;
static AZ::Crc32 GetAssetImportRequestComponentTag()
{
return AZ_CRC_CE("AssetImportRequest");
}
virtual ~AssetImportRequest() = 0;
//! Fills the given list with all available file extensions, excluding the extension for the manifest.
@@ -0,0 +1,45 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"FileMasks": ["_lutr32f"],
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
},
"PlatformsPresets": {
"es3": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
},
"ios": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
},
"osx_gl": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
},
"provo": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
}
}
}
}
@@ -0,0 +1,59 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{ABDFCED1-0565-4B7B-9BC1-82C473BCEEA2}",
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"PlatformsPresets": {
"es3": {
"UUID": "{ABDFCED1-0565-4B7B-9BC1-82C473BCEEA2}",
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"ios": {
"UUID": "{ABDFCED1-0565-4B7B-9BC1-82C473BCEEA2}",
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"osx_gl": {
"UUID": "{ABDFCED1-0565-4B7B-9BC1-82C473BCEEA2}",
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"provo": {
"UUID": "{ABDFCED1-0565-4B7B-9BC1-82C473BCEEA2}",
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
}
}
}
}
@@ -0,0 +1,59 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{6D75F093-C826-437A-AD94-8631A5A4E8A2}",
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"PlatformsPresets": {
"es3": {
"UUID": "{6D75F093-C826-437A-AD94-8631A5A4E8A2}",
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"ios": {
"UUID": "{6D75F093-C826-437A-AD94-8631A5A4E8A2}",
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"osx_gl": {
"UUID": "{6D75F093-C826-437A-AD94-8631A5A4E8A2}",
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"provo": {
"UUID": "{6D75F093-C826-437A-AD94-8631A5A4E8A2}",
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
}
}
}
}
@@ -738,7 +738,7 @@ namespace AZ
}
else if (platformIdentifier == "mac")
{
platformId = AzFramework::PlatformId::MAC;
platformId = AzFramework::PlatformId::MAC_ID;
}
else if (platformIdentifier == "android")
{
@@ -790,7 +790,7 @@ namespace AZ
}
else if (platform == "mac")
{
platformId = AzFramework::PlatformId::MAC;
platformId = AzFramework::PlatformId::MAC_ID;
}
else if (platform == "android")
{
@@ -14,6 +14,9 @@
#include <AzCore/base.h>
#include <Atom/RPI.Public/FeatureProcessor.h>
#include <Atom/RHI.Reflect/Size.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Image/Image.h>
namespace AZ
{
@@ -23,6 +26,57 @@ namespace AZ
using DiffuseProbeGridHandle = AZStd::shared_ptr<DiffuseProbeGrid>;
enum class DiffuseProbeGridMode : uint8_t
{
RealTime,
Baked,
AutoSelect
};
enum class DiffuseProbeGridTextureNotificationType
{
None,
Ready,
Error
};
struct DiffuseProbeGridTexture
{
const AZStd::shared_ptr<AZStd::vector<uint8_t>> m_data;
RHI::Format m_format;
RHI::Size m_size;
};
static const char* DiffuseProbeGridIrradianceFileName = "Irradiance_lutrgba16.dds";
static const char* DiffuseProbeGridDistanceFileName = "Distance_lutrg32f.dds";
static const char* DiffuseProbeGridRelocationFileName = "Relocation_lutrgba16f.dds";
static const char* DiffuseProbeGridClassificationFileName = "Classification_lutr32f.dds";
using DiffuseProbeGridBakeTexturesCallback = AZStd::function<void(
DiffuseProbeGridTexture irradianceTexture,
DiffuseProbeGridTexture distanceTexture,
DiffuseProbeGridTexture relocationTexture,
DiffuseProbeGridTexture classificationTexture)>;
struct DiffuseProbeGridBakedTextures
{
// irradiance and distance images can be used directly
Data::Instance<RPI::Image> m_irradianceImage;
AZStd::string m_irradianceImageRelativePath;
Data::Instance<RPI::Image> m_distanceImage;
AZStd::string m_distanceImageRelativePath;
// relocation and classification images need to be recreated as RW textures
RHI::ImageDescriptor m_relocationImageDescriptor;
AZStd::array_view<uint8_t> m_relocationImageData;
AZStd::string m_relocationImageRelativePath;
RHI::ImageDescriptor m_classificationImageDescriptor;
AZStd::array_view<uint8_t> m_classificationImageData;
AZStd::string m_classificationImageRelativePath;
};
// DiffuseProbeGridFeatureProcessorInterface provides an interface to the feature processor for code outside of Atom
class DiffuseProbeGridFeatureProcessorInterface
: public RPI::FeatureProcessor
@@ -44,6 +98,29 @@ namespace AZ
virtual void Enable(const DiffuseProbeGridHandle& probeGrid, bool enable) = 0;
virtual void SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows) = 0;
virtual void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) = 0;
virtual void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) = 0;
virtual void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) = 0;
virtual void BakeTextures(
const DiffuseProbeGridHandle& probeGrid,
DiffuseProbeGridBakeTexturesCallback callback,
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath) = 0;
// check for and retrieve a new baked texture asset (does not apply to hot-reloaded assets, only initial bakes)
virtual bool CheckTextureAssetNotification(
const AZStd::string& relativePath,
Data::Asset<RPI::StreamingImageAsset>& outTextureAsset,
DiffuseProbeGridTextureNotificationType& outNotificationType) = 0;
virtual bool AreBakedTexturesReferenced(
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath) = 0;
};
} // namespace Render
} // namespace AZ
@@ -1,14 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
@@ -26,14 +26,15 @@ namespace AZ
, public AzToolsFramework::EditorEntityVisibilityNotificationBus::Handler
{
public:
using BaseClass = AzToolsFramework::Components::EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration>;
AZ_RTTI((EditorRenderComponentAdapter, "{AAF38BE4-EA2F-408B-9C44-63C7FBAC6B33}", TController, TRuntimeComponent, TConfiguration), BaseClass);
AZ_RTTI(
(EditorRenderComponentAdapter, "{AAF38BE4-EA2F-408B-9C44-63C7FBAC6B33}", TController, TRuntimeComponent, TConfiguration),
BaseClass);
static void Reflect(AZ::ReflectContext* context);
EditorRenderComponentAdapter() = default;
EditorRenderComponentAdapter(const TConfiguration& config);
explicit EditorRenderComponentAdapter(const TConfiguration& config);
// AzToolsFramework::Components::EditorComponentAdapter overrides
void Activate() override;
@@ -50,7 +51,8 @@ namespace AZ
// Convert pre-existing EditorCompnentAdapter based serialized data to EditorRenderComponentAdapter
template<int TVersion>
static bool ConvertToEditorRenderComponentAdapter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
static bool ConvertToEditorRenderComponentAdapter(
AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
};
} // namespace Render
} // namespace AZ
@@ -1,14 +1,14 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
@@ -19,11 +19,12 @@ namespace AZ
{
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
template<int TVersion>
bool EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::ConvertToEditorRenderComponentAdapter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
bool EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::ConvertToEditorRenderComponentAdapter(
AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() < TVersion)
{
// Get the and remove the EditorComponentAdapter base class data that was previpously serialized
// Get the and remove the EditorComponentAdapter base class data that was previously serialized
AzToolsFramework::Components::EditorComponentAdapter<TController, TRuntimeComponent, TConfiguration> oldBaseClassData;
if (!classElement.FindSubElementAndGetData(AZ_CRC("BaseClass1", 0xd4925735), oldBaseClassData))
@@ -41,8 +42,8 @@ namespace AZ
// Replace the old base class data with EditorRenderComponentAdapter
EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration> newBaseClassData;
AZ::SerializeContext::DataElementNode& newBaseClassElement = classElement.GetSubElement(
classElement.AddElementWithData(context, "BaseClass1", newBaseClassData));
AZ::SerializeContext::DataElementNode& newBaseClassElement =
classElement.GetSubElement(classElement.AddElementWithData(context, "BaseClass1", newBaseClassData));
// Overwrite EditorRenderComponentAdapter base class data with retrieved EditorComponentAdapter base class data
if (!newBaseClassElement.RemoveElementByName(AZ_CRC("BaseClass1", 0xd4925735)))
@@ -62,25 +63,24 @@ namespace AZ
{
BaseClass::Reflect(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorRenderComponentAdapter, BaseClass>()
->Version(0)
;
serializeContext->Class<EditorRenderComponentAdapter, BaseClass>()->Version(0);
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorRenderComponentAdapter>(
"EditorRenderComponentAdapter", "")
// clang-format off
editContext->Class<EditorRenderComponentAdapter>("EditorRenderComponentAdapter", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
// clang-format on
}
}
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::EditorRenderComponentAdapter(const TConfiguration& config)
EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::EditorRenderComponentAdapter(
const TConfiguration& config)
: BaseClass(config)
{
}
@@ -103,7 +103,8 @@ namespace AZ
bool EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::IsVisible() const
{
bool visible = true;
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(visible, this->GetEntityId(), &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible);
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
visible, this->GetEntityId(), &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible);
return visible;
}
@@ -114,15 +115,16 @@ namespace AZ
}
template<typename TController, typename TRuntimeComponent, typename TConfiguration>
void EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::OnEntityVisibilityChanged([[maybe_unused]] bool visibility)
void EditorRenderComponentAdapter<TController, TRuntimeComponent, TConfiguration>::OnEntityVisibilityChanged(
[[maybe_unused]] bool visibility)
{
this->m_controller.Deactivate();
if (this->ShouldActivateController())
{
this->m_controller.Activate(this->GetEntityId());
AzFramework::Components::ComponentActivateHelper<TController>::Activate(
this->m_controller, AZ::EntityComponentIdPair(this->GetEntityId(), this->GetId()));
}
}
} // namespace Render
} // namespace AZ
@@ -279,7 +279,7 @@ namespace AZ
if (handle.IsValid())
{
Quaternion orientation = world.GetRotation();
Vector3 scale = world.GetScale() * nonUniformScale;
Vector3 scale = world.GetUniformScale() * nonUniformScale;
SetDecalHalfSize(handle, scale);
SetDecalPosition(handle, world.GetTranslation());
@@ -285,7 +285,7 @@ namespace AZ
{
if (handle.IsValid())
{
SetDecalHalfSize(handle, nonUniformScale * world.GetScale());
SetDecalHalfSize(handle, nonUniformScale * world.GetUniformScale());
SetDecalPosition(handle, world.GetTranslation());
SetDecalOrientation(handle, world.GetRotation());
@@ -13,6 +13,7 @@
#include <Atom/RHI.Reflect/ShaderResourceGroupLayoutDescriptor.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <DiffuseProbeGrid/DiffuseProbeGrid.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RHI/Factory.h>
@@ -23,6 +24,11 @@ namespace AZ
{
namespace Render
{
DiffuseProbeGrid::DiffuseProbeGrid()
: m_textureReadback(this)
{
}
DiffuseProbeGrid::~DiffuseProbeGrid()
{
m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
@@ -166,6 +172,84 @@ namespace AZ
m_updateRenderObjectSrg = true;
}
void DiffuseProbeGrid::SetMode(DiffuseProbeGridMode mode)
{
// handle auto-select
if (mode == DiffuseProbeGridMode::AutoSelect)
{
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
m_mode = (device->GetFeatures().m_rayTracing) ? DiffuseProbeGridMode::RealTime : DiffuseProbeGridMode::Baked;
}
else
{
m_mode = mode;
}
m_updateTextures = true;
}
void DiffuseProbeGrid::SetBakedTextures(const DiffuseProbeGridBakedTextures& bakedTextures)
{
AZ_Assert(bakedTextures.m_irradianceImage.get(), "Invalid Irradiance image passed to SetBakedTextures");
AZ_Assert(bakedTextures.m_distanceImage.get(), "Invalid Distance image passed to SetBakedTextures");
AZ_Assert(bakedTextures.m_relocationImageData.size() > 0, "Invalid Relocation image data passed to SetBakedTextures");
AZ_Assert(bakedTextures.m_classificationImageData.size() > 0, "Invalid Classification image data passed to SetBakedTextures");
m_bakedIrradianceImage = bakedTextures.m_irradianceImage;
m_bakedDistanceImage = bakedTextures.m_distanceImage;
m_bakedIrradianceRelativePath = bakedTextures.m_irradianceImageRelativePath;
m_bakedDistanceRelativePath = bakedTextures.m_distanceImageRelativePath;
m_bakedRelocationRelativePath = bakedTextures.m_relocationImageRelativePath;
m_bakedClassificationRelativePath = bakedTextures.m_classificationImageRelativePath;
m_bakedRelocationImageData.resize(bakedTextures.m_relocationImageData.size());
memcpy(m_bakedRelocationImageData.data(), bakedTextures.m_relocationImageData.data(), bakedTextures.m_relocationImageData.size());
m_bakedClassificationImageData.resize(bakedTextures.m_classificationImageData.size());
memcpy(m_bakedClassificationImageData.data(), bakedTextures.m_classificationImageData.data(), bakedTextures.m_classificationImageData.size());
// create the relocation and distance RW textures now, these are needed for shader compatibility
// (image data is copied in UpdateTextures)
{
m_bakedRelocationImage = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest initRequest;
initRequest.m_image = m_bakedRelocationImage.get();
initRequest.m_descriptor = RHI::ImageDescriptor::Create2D(
RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead,
bakedTextures.m_relocationImageDescriptor.m_size.m_width,
bakedTextures.m_relocationImageDescriptor.m_size.m_height,
bakedTextures.m_relocationImageDescriptor.m_format);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(initRequest);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize Relocation image");
}
{
m_bakedClassificationImage = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest initRequest;
initRequest.m_image = m_bakedClassificationImage.get();
initRequest.m_descriptor = RHI::ImageDescriptor::Create2D(
RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead,
bakedTextures.m_classificationImageDescriptor.m_size.m_width,
bakedTextures.m_classificationImageDescriptor.m_size.m_height,
bakedTextures.m_classificationImageDescriptor.m_format);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(initRequest);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize Classification image");
}
m_updateTextures = true;
}
bool DiffuseProbeGrid::HasValidBakedTextures() const
{
return m_bakedIrradianceImage.get() &&
m_bakedDistanceImage.get() &&
m_bakedRelocationImage.get() &&
m_bakedClassificationImage.get();
}
uint32_t DiffuseProbeGrid::GetTotalProbeCount() const
{
return m_probeCountX * m_probeCountY * m_probeCountZ;
@@ -188,83 +272,117 @@ namespace AZ
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
// advance to the next image in the frame image array
m_currentImageIndex = (m_currentImageIndex + 1) % ImageFrameCount;
// probe raytrace
{
uint32_t width = m_numRaysPerProbe;
uint32_t height = GetTotalProbeCount();
m_rayTraceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_rayTraceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite, width, height, DiffuseProbeGridRenderData::RayTraceImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeRayTraceImage image");
}
uint32_t probeCountX;
uint32_t probeCountY;
GetTexture2DProbeCount(probeCountX, probeCountY);
// probe irradiance
if (m_mode == DiffuseProbeGridMode::RealTime)
{
uint32_t width = probeCountX * (DefaultNumIrradianceTexels + 2);
uint32_t height = probeCountY * (DefaultNumIrradianceTexels + 2);
// advance to the next image in the frame image array
m_currentImageIndex = (m_currentImageIndex + 1) % ImageFrameCount;
m_irradianceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
// probe raytrace
{
uint32_t width = m_numRaysPerProbe;
uint32_t height = GetTotalProbeCount();
RHI::ImageInitRequest request;
request.m_image = m_irradianceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite, width, height, DiffuseProbeGridRenderData::IrradianceImageFormat);
RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(0.0f, 0.0f, 0.0f, 0.0f);
request.m_optimizedClearValue = &clearValue;
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeIrradianceImage image");
m_rayTraceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_rayTraceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead, width, height, DiffuseProbeGridRenderData::RayTraceImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeRayTraceImage image");
}
// probe irradiance
{
uint32_t width = probeCountX * (DefaultNumIrradianceTexels + 2);
uint32_t height = probeCountY * (DefaultNumIrradianceTexels + 2);
m_irradianceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_irradianceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead, width, height, DiffuseProbeGridRenderData::IrradianceImageFormat);
RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(0.0f, 0.0f, 0.0f, 0.0f);
request.m_optimizedClearValue = &clearValue;
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeIrradianceImage image");
}
// probe distance
{
uint32_t width = probeCountX * (DefaultNumDistanceTexels + 2);
uint32_t height = probeCountY * (DefaultNumDistanceTexels + 2);
m_distanceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_distanceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead, width, height, DiffuseProbeGridRenderData::DistanceImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeDistanceImage image");
}
// probe relocation
{
uint32_t width = probeCountX;
uint32_t height = probeCountY;
m_relocationImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_relocationImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead, width, height, DiffuseProbeGridRenderData::RelocationImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeRelocationImage image");
}
// probe classification
{
uint32_t width = probeCountX;
uint32_t height = probeCountY;
m_classificationImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_classificationImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead, width, height, DiffuseProbeGridRenderData::ClassificationImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeClassificationImage image");
}
}
// probe distance
else if (m_mode == DiffuseProbeGridMode::Baked && HasValidBakedTextures())
{
uint32_t width = probeCountX * (DefaultNumDistanceTexels + 2);
uint32_t height = probeCountY * (DefaultNumDistanceTexels + 2);
// copy the baked relocation and classification texture data to the RW textures
// (these need to be RW for shader compatibility)
RHI::ImageSubresourceRange range{ 0, 0, 0 ,0 };
RHI::ImageSubresourceLayoutPlaced layout;
m_distanceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
// relocation
{
m_bakedRelocationImage->GetSubresourceLayouts(range, &layout, nullptr);
RHI::ImageInitRequest request;
request.m_image = m_distanceImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite, width, height, DiffuseProbeGridRenderData::DistanceImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeDistanceImage image");
}
RHI::ImageUpdateRequest updateRequest;
updateRequest.m_image = m_bakedRelocationImage.get();
updateRequest.m_sourceSubresourceLayout = layout;
updateRequest.m_sourceData = m_bakedRelocationImageData.data();
updateRequest.m_imageSubresourcePixelOffset = RHI::Origin(0, 0, 0);
m_renderData->m_imagePool->UpdateImageContents(updateRequest);
}
// probe relocation
{
uint32_t width = probeCountX;
uint32_t height = probeCountY;
// classification
{
m_bakedClassificationImage->GetSubresourceLayouts(range, &layout, nullptr);
m_relocationImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_relocationImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite, width, height, DiffuseProbeGridRenderData::RelocationImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeRelocationImage image");
}
// probe classification
{
uint32_t width = probeCountX;
uint32_t height = probeCountY;
m_classificationImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = m_classificationImage[m_currentImageIndex].get();
request.m_descriptor = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::ShaderReadWrite, width, height, DiffuseProbeGridRenderData::ClassificationImageFormat);
[[maybe_unused]] RHI::ResultCode result = m_renderData->m_imagePool->InitImage(request);
AZ_Assert(result == RHI::ResultCode::Success, "Failed to initialize m_probeClassificationImage image");
RHI::ImageUpdateRequest updateRequest;
updateRequest.m_image = m_bakedClassificationImage.get();
updateRequest.m_sourceSubresourceLayout = layout;
updateRequest.m_sourceData = m_bakedClassificationImageData.data();
updateRequest.m_imageSubresourcePixelOffset = RHI::Origin(0, 0, 0);
m_renderData->m_imagePool->UpdateImageContents(updateRequest);
}
}
m_updateTextures = false;
@@ -639,16 +757,16 @@ namespace AZ
m_renderObjectSrg->SetConstant(constantIndex, m_ambientMultiplier);
imageIndex = srgLayout->FindShaderInputImageIndex(Name("m_probeIrradiance"));
m_renderObjectSrg->SetImageView(imageIndex, m_irradianceImage[m_currentImageIndex]->GetImageView(m_renderData->m_probeIrradianceImageViewDescriptor).get());
m_renderObjectSrg->SetImageView(imageIndex, GetIrradianceImage()->GetImageView(m_renderData->m_probeIrradianceImageViewDescriptor).get());
imageIndex = srgLayout->FindShaderInputImageIndex(Name("m_probeDistance"));
m_renderObjectSrg->SetImageView(imageIndex, m_distanceImage[m_currentImageIndex]->GetImageView(m_renderData->m_probeDistanceImageViewDescriptor).get());
m_renderObjectSrg->SetImageView(imageIndex, GetDistanceImage()->GetImageView(m_renderData->m_probeDistanceImageViewDescriptor).get());
imageIndex = srgLayout->FindShaderInputImageIndex(Name("m_probeOffsets"));
m_renderObjectSrg->SetImageView(imageIndex, m_relocationImage[m_currentImageIndex]->GetImageView(m_renderData->m_probeRelocationImageViewDescriptor).get());
m_renderObjectSrg->SetImageView(imageIndex, GetRelocationImage()->GetImageView(m_renderData->m_probeRelocationImageViewDescriptor).get());
imageIndex = srgLayout->FindShaderInputImageIndex(Name("m_probeStates"));
m_renderObjectSrg->SetImageView(imageIndex, m_classificationImage[m_currentImageIndex]->GetImageView(m_renderData->m_probeClassificationImageViewDescriptor).get());
m_renderObjectSrg->SetImageView(imageIndex, GetClassificationImage()->GetImageView(m_renderData->m_probeClassificationImageViewDescriptor).get());
SetGridConstants(m_renderObjectSrg);
@@ -17,6 +17,7 @@
#include <Atom/RPI.Public/Scene.h>
#include <AzCore/Math/Random.h>
#include <AzCore/Math/Aabb.h>
#include <DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h>
namespace AZ
{
@@ -26,11 +27,12 @@ namespace AZ
struct DiffuseProbeGridRenderData
{
// [GFX TODO][ATOM-15650] Change DiffuseProbeGrid Classification texture to R8_UINT
static const RHI::Format RayTraceImageFormat = RHI::Format::R32G32B32A32_FLOAT;
static const RHI::Format IrradianceImageFormat = RHI::Format::R16G16B16A16_UNORM;
static const RHI::Format DistanceImageFormat = RHI::Format::R32G32_FLOAT;
static const RHI::Format RelocationImageFormat = RHI::Format::R16G16B16A16_FLOAT;
static const RHI::Format ClassificationImageFormat = RHI::Format::R8_UINT;
static const RHI::Format ClassificationImageFormat = RHI::Format::R32_FLOAT;
// image pool
RHI::Ptr<RHI::ImagePool> m_imagePool;
@@ -61,7 +63,7 @@ namespace AZ
class DiffuseProbeGrid final
{
public:
DiffuseProbeGrid() = default;
DiffuseProbeGrid();
~DiffuseProbeGrid();
void Init(RPI::Scene* scene, DiffuseProbeGridRenderData* diffuseProbeGridRenderData);
@@ -96,6 +98,9 @@ namespace AZ
bool GetUseDiffuseIbl() const { return m_useDiffuseIbl; }
void SetUseDiffuseIbl(bool useDiffuseIbl) { m_useDiffuseIbl = useDiffuseIbl; }
DiffuseProbeGridMode GetMode() const { return m_mode; }
void SetMode(DiffuseProbeGridMode mode);
uint32_t GetNumRaysPerProbe() const { return m_numRaysPerProbe; }
uint32_t GetRemainingRelocationIterations() const { return aznumeric_cast<uint32_t>(m_remainingRelocationIterations); }
@@ -133,11 +138,16 @@ namespace AZ
void UpdateRenderObjectSrg();
// textures
const RHI::Ptr<RHI::Image>& GetRayTraceImage() { return m_rayTraceImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image>& GetIrradianceImage() { return m_irradianceImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image>& GetDistanceImage() { return m_distanceImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image>& GetRelocationImage() { return m_relocationImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image>& GetClassificationImage() { return m_classificationImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image> GetRayTraceImage() { return m_rayTraceImage[m_currentImageIndex]; }
const RHI::Ptr<RHI::Image> GetIrradianceImage() { return m_mode == DiffuseProbeGridMode::RealTime ? m_irradianceImage[m_currentImageIndex] : m_bakedIrradianceImage->GetRHIImage(); }
const RHI::Ptr<RHI::Image> GetDistanceImage() { return m_mode == DiffuseProbeGridMode::RealTime ? m_distanceImage[m_currentImageIndex] : m_bakedDistanceImage->GetRHIImage(); }
const RHI::Ptr<RHI::Image> GetRelocationImage() { return m_mode == DiffuseProbeGridMode::RealTime ? m_relocationImage[m_currentImageIndex] : m_bakedRelocationImage; }
const RHI::Ptr<RHI::Image> GetClassificationImage() { return m_mode == DiffuseProbeGridMode::RealTime ? m_classificationImage[m_currentImageIndex] : m_bakedClassificationImage; }
const AZStd::string& GetBakedIrradianceRelativePath() const { return m_bakedIrradianceRelativePath; }
const AZStd::string& GetBakedDistanceRelativePath() const { return m_bakedDistanceRelativePath; }
const AZStd::string& GetBakedRelocationRelativePath() const { return m_bakedRelocationRelativePath; }
const AZStd::string& GetBakedClassificationRelativePath() const { return m_bakedClassificationRelativePath; }
// attachment Ids
const RHI::AttachmentId GetRayTraceImageAttachmentId() const { return m_rayTraceImageAttachmentId; }
@@ -152,6 +162,12 @@ namespace AZ
bool GetIrradianceClearRequired() const { return m_irradianceClearRequired; }
void ResetIrradianceClearRequired() { m_irradianceClearRequired = false; }
// texture readback
DiffuseProbeGridTextureReadback& GetTextureReadback() { return m_textureReadback; }
void SetBakedTextures(const DiffuseProbeGridBakedTextures& bakedTextures);
bool HasValidBakedTextures() const;
static constexpr uint32_t DefaultNumIrradianceTexels = 6;
static constexpr uint32_t DefaultNumDistanceTexels = 14;
static constexpr int32_t DefaultNumRelocationIterations = 100;
@@ -221,7 +237,10 @@ namespace AZ
// culling
RPI::Cullable m_cullable;
// textures
// grid mode (RealTime or Baked)
DiffuseProbeGridMode m_mode = DiffuseProbeGridMode::RealTime;
// real-time textures
static const uint32_t MaxTextureDimension = 8192;
static const uint32_t ImageFrameCount = 3;
RHI::Ptr<RHI::Image> m_rayTraceImage[ImageFrameCount];
@@ -233,6 +252,25 @@ namespace AZ
bool m_updateTextures = false;
bool m_irradianceClearRequired = true;
// baked textures
Data::Instance<RPI::Image> m_bakedIrradianceImage;
Data::Instance<RPI::Image> m_bakedDistanceImage;
RHI::Ptr<RHI::Image> m_bakedRelocationImage;
RHI::Ptr<RHI::Image> m_bakedClassificationImage;
// baked texture relative paths
AZStd::string m_bakedIrradianceRelativePath;
AZStd::string m_bakedDistanceRelativePath;
AZStd::string m_bakedRelocationRelativePath;
AZStd::string m_bakedClassificationRelativePath;
// baked texture data (only needed for the relocation and classification textures)
AZStd::vector<uint8_t> m_bakedRelocationImageData;
AZStd::vector<uint8_t> m_bakedClassificationImageData;
// texture readback
DiffuseProbeGridTextureReadback m_textureReadback;
// Srgs
Data::Instance<RPI::ShaderResourceGroup> m_rayTraceSrg;
Data::Instance<RPI::ShaderResourceGroup> m_blendIrradianceSrg;
@@ -87,7 +87,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -111,7 +111,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// probe raytrace image
{
@@ -150,7 +150,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -167,7 +167,7 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItem for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendDistanceSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
@@ -87,7 +87,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -111,7 +111,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// probe raytrace image
{
@@ -150,7 +150,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -167,7 +167,7 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItem for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendIrradianceSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
@@ -100,7 +100,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -124,7 +124,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// probe irradiance image
{
@@ -153,7 +153,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see line ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -173,7 +173,7 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItems for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
uint32_t probeCountX;
uint32_t probeCountY;
@@ -91,7 +91,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -115,7 +115,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// probe raytrace image
{
@@ -143,7 +143,7 @@ namespace AZ
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -159,7 +159,7 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItems for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetClassificationSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
@@ -45,6 +45,7 @@ namespace AZ
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
m_diffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
m_realTimeDiffuseProbeGrids.reserve(InitialProbeGridAllocationSize);
RHI::BufferPoolDescriptor desc;
desc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
@@ -61,7 +62,7 @@ namespace AZ
// image pool
{
RHI::ImagePoolDescriptor imagePoolDesc;
imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderReadWrite;
imagePoolDesc.m_bindFlags = RHI::ImageBindFlags::ShaderReadWrite | RHI::ImageBindFlags::CopyRead;
m_probeGridRenderData.m_imagePool = RHI::Factory::Get().CreateImagePool();
[[maybe_unused]] RHI::ResultCode result = m_probeGridRenderData.m_imagePool->Init(*rhiSystem->GetDevice(), imagePoolDesc);
@@ -123,6 +124,32 @@ namespace AZ
m_needUpdatePipelineStates = false;
}
// check pending textures and connect bus for notifications
for (auto& notificationEntry : m_notifyTextureAssets)
{
if (notificationEntry.m_assetId.IsValid())
{
// asset already has an assetId
continue;
}
// query for the assetId
AZ::Data::AssetId assetId;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
assetId,
&AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
notificationEntry.m_relativePath.c_str(),
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
false);
if (assetId.IsValid())
{
notificationEntry.m_assetId = assetId;
notificationEntry.m_asset.Create(assetId, true);
Data::AssetBus::MultiHandler::BusConnect(assetId);
}
}
// if the volumes changed we need to re-sort the probe list
if (m_probeGridSortRequired)
{
@@ -139,6 +166,7 @@ namespace AZ
};
AZStd::sort(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), sortFn);
AZStd::sort(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), sortFn);
m_probeGridSortRequired = false;
}
@@ -160,6 +188,9 @@ namespace AZ
diffuseProbeGrid->SetExtents(extents);
diffuseProbeGrid->SetProbeSpacing(probeSpacing);
m_diffuseProbeGrids.push_back(diffuseProbeGrid);
UpdateRealTimeList(diffuseProbeGrid);
m_probeGridSortRequired = true;
return diffuseProbeGrid;
@@ -169,6 +200,7 @@ namespace AZ
{
AZ_Assert(probeGrid.get(), "RemoveProbeGrid called with an invalid handle");
// remove from main list
auto itEntry = AZStd::find_if(m_diffuseProbeGrids.begin(), m_diffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
return (entry == probeGrid);
@@ -176,6 +208,18 @@ namespace AZ
AZ_Assert(itEntry != m_diffuseProbeGrids.end(), "RemoveProbeGrid called with a probe grid that is not in the probe list");
m_diffuseProbeGrids.erase(itEntry);
// remove from side list of real-time grids
itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
return (entry == probeGrid);
});
if (itEntry != m_realTimeDiffuseProbeGrids.end())
{
m_realTimeDiffuseProbeGrids.erase(itEntry);
}
probeGrid = nullptr;
}
@@ -247,6 +291,134 @@ namespace AZ
probeGrid->SetUseDiffuseIbl(useDiffuseIbl);
}
void DiffuseProbeGridFeatureProcessor::BakeTextures(
const DiffuseProbeGridHandle& probeGrid,
DiffuseProbeGridBakeTexturesCallback callback,
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath)
{
AZ_Assert(probeGrid.get(), "BakeTextures called with an invalid handle");
AddNotificationEntry(irradianceTextureRelativePath);
AddNotificationEntry(distanceTextureRelativePath);
AddNotificationEntry(relocationTextureRelativePath);
AddNotificationEntry(classificationTextureRelativePath);
probeGrid->GetTextureReadback().BeginTextureReadback(callback);
}
void DiffuseProbeGridFeatureProcessor::UpdateRealTimeList(const DiffuseProbeGridHandle& diffuseProbeGrid)
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::RealTime)
{
// add to side list of real-time grids
auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
return (entry == diffuseProbeGrid);
});
if (itEntry == m_realTimeDiffuseProbeGrids.end())
{
m_realTimeDiffuseProbeGrids.push_back(diffuseProbeGrid);
}
}
else
{
// remove from side list of real-time grids
auto itEntry = AZStd::find_if(m_realTimeDiffuseProbeGrids.begin(), m_realTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr<DiffuseProbeGrid> const& entry)
{
return (entry == diffuseProbeGrid);
});
if (itEntry != m_realTimeDiffuseProbeGrids.end())
{
m_realTimeDiffuseProbeGrids.erase(itEntry);
}
}
}
void DiffuseProbeGridFeatureProcessor::AddNotificationEntry(const AZStd::string& relativePath)
{
AZStd::string assetPath = relativePath + ".streamingimage";
// check to see if this is an existing asset
AZ::Data::AssetId assetId;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
assetId,
&AZ::Data::AssetCatalogRequests::GetAssetIdByPath,
assetPath.c_str(),
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
false);
// We only track notifications for new texture assets, meaning assets that are created the first time a DiffuseProbeGrid is baked.
// On subsequent bakes the existing assets are automatically reloaded by the RPI since they are already known by the asset system.
if (!assetId.IsValid())
{
m_notifyTextureAssets.push_back({ assetPath, assetId });
}
}
bool DiffuseProbeGridFeatureProcessor::CheckTextureAssetNotification(
const AZStd::string& relativePath,
Data::Asset<RPI::StreamingImageAsset>& outTextureAsset,
DiffuseProbeGridTextureNotificationType& outNotificationType)
{
for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
{
if (itNotification->m_relativePath == relativePath)
{
outNotificationType = itNotification->m_notificationType;
if (outNotificationType != DiffuseProbeGridTextureNotificationType::None)
{
outTextureAsset = itNotification->m_asset;
m_notifyTextureAssets.erase(itNotification);
}
return true;
}
}
return false;
}
bool DiffuseProbeGridFeatureProcessor::AreBakedTexturesReferenced(
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath)
{
for (auto& diffuseProbeGrid : m_diffuseProbeGrids)
{
if ((diffuseProbeGrid->GetBakedIrradianceRelativePath() == irradianceTextureRelativePath) ||
(diffuseProbeGrid->GetBakedDistanceRelativePath() == distanceTextureRelativePath) ||
(diffuseProbeGrid->GetBakedRelocationRelativePath() == relocationTextureRelativePath) ||
(diffuseProbeGrid->GetBakedClassificationRelativePath() == classificationTextureRelativePath))
{
return true;
}
}
return false;
}
void DiffuseProbeGridFeatureProcessor::SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode)
{
AZ_Assert(probeGrid.get(), "SetMode called with an invalid handle");
probeGrid->SetMode(mode);
UpdateRealTimeList(probeGrid);
m_probeGridSortRequired = true;
}
void DiffuseProbeGridFeatureProcessor::SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures)
{
AZ_Assert(probeGrid.get(), "SetBakedTextures called with an invalid handle");
probeGrid->SetBakedTextures(bakedTextures);
}
void DiffuseProbeGridFeatureProcessor::CreateBoxMesh()
{
// vertex positions
@@ -418,5 +590,34 @@ namespace AZ
}
}
void DiffuseProbeGridFeatureProcessor::HandleAssetNotification(Data::Asset<Data::AssetData> asset, DiffuseProbeGridTextureNotificationType notificationType)
{
for (NotifyTextureAssetVector::iterator itNotification = m_notifyTextureAssets.begin(); itNotification != m_notifyTextureAssets.end(); ++itNotification)
{
if (itNotification->m_assetId == asset.GetId())
{
// store the texture asset
itNotification->m_asset = Data::static_pointer_cast<RPI::StreamingImageAsset>(asset);
itNotification->m_notificationType = notificationType;
// stop notifications on this asset
Data::AssetBus::MultiHandler::BusDisconnect(itNotification->m_assetId);
break;
}
}
}
void DiffuseProbeGridFeatureProcessor::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Ready);
}
void DiffuseProbeGridFeatureProcessor::OnAssetError(Data::Asset<Data::AssetData> asset)
{
AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to load cubemap [%s]", asset.GetHint().c_str());
HandleAssetNotification(asset, DiffuseProbeGridTextureNotificationType::Error);
}
} // namespace Render
} // namespace AZ
@@ -22,6 +22,7 @@ namespace AZ
//! This class manages DiffuseProbeGrids which generate diffuse global illumination
class DiffuseProbeGridFeatureProcessor final
: public DiffuseProbeGridFeatureProcessorInterface
, private Data::AssetBus::MultiHandler
{
public:
AZ_RTTI(AZ::Render::DiffuseProbeGridFeatureProcessor, "{BCD232F9-1EBF-4D0D-A5F4-84AEC933A93C}", DiffuseProbeGridFeatureProcessorInterface);
@@ -46,6 +47,27 @@ namespace AZ
void Enable(const DiffuseProbeGridHandle& probeGrid, bool enable) override;
void SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows) override;
void SetUseDiffuseIbl(const DiffuseProbeGridHandle& probeGrid, bool useDiffuseIbl) override;
void SetMode(const DiffuseProbeGridHandle& probeGrid, DiffuseProbeGridMode mode) override;
void SetBakedTextures(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridBakedTextures& bakedTextures) override;
void BakeTextures(
const DiffuseProbeGridHandle& probeGrid,
DiffuseProbeGridBakeTexturesCallback callback,
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath) override;
bool CheckTextureAssetNotification(
const AZStd::string& relativePath,
Data::Asset<RPI::StreamingImageAsset>& outTextureAsset,
DiffuseProbeGridTextureNotificationType& outNotificationType) override;
bool AreBakedTexturesReferenced(
const AZStd::string& irradianceTextureRelativePath,
const AZStd::string& distanceTextureRelativePath,
const AZStd::string& relocationTextureRelativePath,
const AZStd::string& classificationTextureRelativePath) override;
// FeatureProcessor overrides
void Activate() override;
@@ -56,12 +78,28 @@ namespace AZ
using DiffuseProbeGridVector = AZStd::vector<AZStd::shared_ptr<DiffuseProbeGrid>>;
DiffuseProbeGridVector& GetProbeGrids() { return m_diffuseProbeGrids; }
// retrieve the side list of probe grids that are using real-time (raytraced) mode
DiffuseProbeGridVector& GetRealTimeProbeGrids() { return m_realTimeDiffuseProbeGrids; }
private:
AZ_DISABLE_COPY_MOVE(DiffuseProbeGridFeatureProcessor);
// create the box vertex and index streams, which are used to render the probe volumes
void CreateBoxMesh();
// AssetBus::MultiHandler overrides...
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
void OnAssetError(Data::Asset<Data::AssetData> asset) override;
// updates the real-time list for a specific probe grid
void UpdateRealTimeList(const DiffuseProbeGridHandle& diffuseProbeGrid);
// adds a notification entry for a new asset
void AddNotificationEntry(const AZStd::string& relativePath);
// notifies and removes the notification entry
void HandleAssetNotification(Data::Asset<Data::AssetData> asset, DiffuseProbeGridTextureNotificationType notificationType);
// RPI::SceneNotificationBus::Handler overrides
void OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) override;
void OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) override;
@@ -70,10 +108,13 @@ namespace AZ
void UpdatePipelineStates();
void UpdatePasses();
// list of diffuse probe grids
// list of all diffuse probe grids
const size_t InitialProbeGridAllocationSize = 64;
DiffuseProbeGridVector m_diffuseProbeGrids;
// side list of diffuse probe grids that are in real-time mode (subset of m_diffuseProbeGrids)
DiffuseProbeGridVector m_realTimeDiffuseProbeGrids;
// position structure for the box vertices
struct Position
{
@@ -102,6 +143,17 @@ namespace AZ
// indicates the the diffuse probe grid render pipeline state needs to be updated
bool m_needUpdatePipelineStates = false;
// list of texture assets that we need to check during Simulate() to see if they are ready
struct NotifyTextureAssetEntry
{
AZStd::string m_relativePath;
AZ::Data::AssetId m_assetId;
Data::Asset<RPI::StreamingImageAsset> m_asset;
DiffuseProbeGridTextureNotificationType m_notificationType = DiffuseProbeGridTextureNotificationType::None;
};
typedef AZStd::vector<NotifyTextureAssetEntry> NotifyTextureAssetVector;
NotifyTextureAssetVector m_notifyTextureAssets;
};
} // namespace Render
} // namespace AZ
@@ -136,7 +136,7 @@ namespace AZ
}
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -153,9 +153,9 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
frameGraph.SetEstimatedItemCount(aznumeric_cast<uint32_t>(diffuseProbeGridFeatureProcessor->GetProbeGrids().size()));
frameGraph.SetEstimatedItemCount(aznumeric_cast<uint32_t>(diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().size()));
for (const auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (const auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// TLAS
{
@@ -260,7 +260,7 @@ namespace AZ
rayTracingFeatureProcessor->GetMeshInfoBuffer() &&
rayTracingFeatureProcessor->GetSubMeshCount())
{
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader
// inputs (see line ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -308,7 +308,7 @@ namespace AZ
m_rayTracingShaderTable)
{
// submit the DispatchRaysItem for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
const RHI::ShaderResourceGroup* shaderResourceGroups[] = {
diffuseProbeGrid->GetRayTraceSrg()->GetRHIShaderResourceGroup(),
@@ -91,7 +91,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetProbeGrids().empty())
if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty())
{
// no diffuse probe grids
return;
@@ -108,7 +108,7 @@ namespace AZ
// create the Relocation Srgs for each DiffuseProbeGrid, and check to see if any grids need relocation
bool needRelocation = false;
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision();
if (rayTracingDataRevision != m_rayTracingDataRevision)
@@ -139,7 +139,7 @@ namespace AZ
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// probe raytrace image
{
@@ -167,7 +167,7 @@ namespace AZ
{
RPI::Scene* scene = m_pipeline->GetScene();
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() in ShaderResourceGroupData.cpp)
@@ -187,7 +187,7 @@ namespace AZ
DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor<DiffuseProbeGridFeatureProcessor>();
// submit the DispatchItems for each DiffuseProbeGrid
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetRelocationSrg()->GetRHIShaderResourceGroup();
commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup);
@@ -79,6 +79,12 @@ namespace AZ
params.m_scissorState = scissor;
Base::FrameBeginInternal(params);
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids())
{
// process attachment readback
diffuseProbeGrid->GetTextureReadback().FrameBegin(params);
}
}
void DiffuseProbeGridRenderPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph)
@@ -88,8 +94,21 @@ namespace AZ
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked &&
!diffuseProbeGrid->HasValidBakedTextures())
{
continue;
}
// probe irradiance image
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked)
{
// import the irradiance image now, since it is baked and therefore was not imported during the raytracing pass
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(diffuseProbeGrid->GetIrradianceImageAttachmentId(), diffuseProbeGrid->GetIrradianceImage());
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import probeIrradianceImage");
}
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetIrradianceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeIrradianceImageViewDescriptor;
@@ -100,6 +119,13 @@ namespace AZ
// probe distance image
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked)
{
// import the distance image now, since it is baked and therefore was not imported during the raytracing pass
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(diffuseProbeGrid->GetDistanceImageAttachmentId(), diffuseProbeGrid->GetDistanceImage());
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import probeDistanceImage");
}
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetDistanceImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeDistanceImageViewDescriptor;
@@ -110,6 +136,13 @@ namespace AZ
// probe relocation image
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked)
{
// import the relocation image now, since it is baked and therefore was not imported during the raytracing pass
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(diffuseProbeGrid->GetRelocationImageAttachmentId(), diffuseProbeGrid->GetRelocationImage());
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import probeRelocationImage");
}
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetRelocationImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeRelocationImageViewDescriptor;
@@ -120,6 +153,13 @@ namespace AZ
// probe classification image
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked)
{
// import the classification image now, since it is baked and therefore was not imported during the raytracing pass
[[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(diffuseProbeGrid->GetClassificationImageAttachmentId(), diffuseProbeGrid->GetClassificationImage());
AZ_Assert(result == RHI::ResultCode::Success, "Failed to import probeClassificationImage");
}
RHI::ImageScopeAttachmentDescriptor desc;
desc.m_attachmentId = diffuseProbeGrid->GetClassificationImageAttachmentId();
desc.m_imageViewDescriptor = diffuseProbeGrid->GetRenderData()->m_probeClassificationImageViewDescriptor;
@@ -127,6 +167,8 @@ namespace AZ
frameGraph.UseShaderAttachment(desc, RHI::ScopeAttachmentAccess::ReadWrite);
}
diffuseProbeGrid->GetTextureReadback().Update(GetName());
}
Base::SetupFrameGraphDependencies(frameGraph);
@@ -139,6 +181,12 @@ namespace AZ
for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetProbeGrids())
{
if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked &&
!diffuseProbeGrid->HasValidBakedTextures())
{
continue;
}
// the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs
// (see ValidateSetImageView() of ShaderResourceGroupData.cpp)
diffuseProbeGrid->UpdateRenderObjectSrg();
@@ -0,0 +1,134 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h>
#include <DiffuseProbeGrid/DiffuseProbeGrid.h>
namespace AZ
{
namespace Render
{
DiffuseProbeGridTextureReadback::DiffuseProbeGridTextureReadback(DiffuseProbeGrid* diffuseProbeGrid)
: m_diffuseProbeGrid(diffuseProbeGrid)
{
}
void DiffuseProbeGridTextureReadback::BeginTextureReadback(DiffuseProbeGridBakeTexturesCallback callback)
{
AZ_Assert(m_readbackState == DiffuseProbeGridReadbackState::Idle, "DiffuseProbeGridTextureReadback is already processing a readback request");
m_callback = callback;
m_readbackState = DiffuseProbeGridReadbackState::Irradiance;
}
void DiffuseProbeGridTextureReadback::Update(const AZ::Name& passName)
{
if (m_readbackState == DiffuseProbeGridReadbackState::Idle || m_readbackState == DiffuseProbeGridReadbackState::Complete)
{
return;
}
if (m_attachmentReadback.get() && m_attachmentReadback->GetReadbackState() > RPI::AttachmentReadback::ReadbackState::Idle)
{
// still processing previous request
return;
}
AZStd::string readbackName = AZStd::string::format("DiffuseProbeGridReadback_%s", passName.GetCStr());
RHI::ImageDescriptor descriptor;
RHI::AttachmentId attachmentId;
RPI::AttachmentReadback::CallbackFunction callbackFunction;
switch (m_readbackState)
{
case DiffuseProbeGridReadbackState::Irradiance:
descriptor = m_diffuseProbeGrid->GetIrradianceImage()->GetDescriptor();
attachmentId = m_diffuseProbeGrid->GetIrradianceImageAttachmentId();
callbackFunction = [this](const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
m_irradianceReadbackResult = readbackResult;
m_readbackState = DiffuseProbeGridReadbackState::Distance;
};
break;
case DiffuseProbeGridReadbackState::Distance:
descriptor = m_diffuseProbeGrid->GetDistanceImage()->GetDescriptor();
attachmentId = m_diffuseProbeGrid->GetDistanceImageAttachmentId();
callbackFunction = [this](const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
m_distanceReadbackResult = readbackResult;
m_readbackState = DiffuseProbeGridReadbackState::Relocation;
};
break;
case DiffuseProbeGridReadbackState::Relocation:
descriptor = m_diffuseProbeGrid->GetRelocationImage()->GetDescriptor();
attachmentId = m_diffuseProbeGrid->GetRelocationImageAttachmentId();
callbackFunction = [this](const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
m_relocationReadbackResult = readbackResult;
m_readbackState = DiffuseProbeGridReadbackState::Classification;
};
break;
case DiffuseProbeGridReadbackState::Classification:
descriptor = m_diffuseProbeGrid->GetClassificationImage()->GetDescriptor();
attachmentId = m_diffuseProbeGrid->GetClassificationImageAttachmentId();
callbackFunction = [this](const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
{
m_classificationReadbackResult = readbackResult;
m_readbackState = DiffuseProbeGridReadbackState::Complete;
};
break;
default:
AZ_Assert(false, "Unknown readback state");
}
m_attachmentReadback = AZStd::make_shared<AZ::RPI::AttachmentReadback>(AZ::RHI::ScopeId{ "DiffuseProbeGridTextureReadBack" });
m_attachmentReadback->SetCallback(callbackFunction);
AZ::RPI::PassAttachment passAttachment;
passAttachment.m_descriptor = descriptor;
passAttachment.m_path = attachmentId;
passAttachment.m_name = readbackName;
passAttachment.m_lifetime = RHI::AttachmentLifetimeType::Imported;
m_attachmentReadback->ReadPassAttachment(&passAttachment, AZ::Name(readbackName));
}
void DiffuseProbeGridTextureReadback::FrameBegin(AZ::RPI::Pass::FramePrepareParams& params)
{
if (m_readbackState == DiffuseProbeGridReadbackState::Idle)
{
return;
}
if (!m_attachmentReadback.get())
{
return;
}
if (m_readbackState == DiffuseProbeGridReadbackState::Complete)
{
// readback of all textures is complete, invoke callback and return to Idle state
m_callback(
{ m_irradianceReadbackResult.m_dataBuffer, m_irradianceReadbackResult.m_imageDescriptor.m_format, m_irradianceReadbackResult.m_imageDescriptor.m_size },
{ m_distanceReadbackResult.m_dataBuffer, m_distanceReadbackResult.m_imageDescriptor.m_format, m_distanceReadbackResult.m_imageDescriptor.m_size },
{ m_relocationReadbackResult.m_dataBuffer, m_relocationReadbackResult.m_imageDescriptor.m_format, m_relocationReadbackResult.m_imageDescriptor.m_size },
{ m_classificationReadbackResult.m_dataBuffer, m_classificationReadbackResult.m_imageDescriptor.m_format, m_classificationReadbackResult.m_imageDescriptor.m_size });
m_readbackState = DiffuseProbeGridReadbackState::Idle;
m_attachmentReadback.reset();
return;
}
m_attachmentReadback->FrameBegin(params);
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/RHI/ScopeProducer.h>
#include <Atom/RPI.Public/Pass/AttachmentReadback.h>
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/Feature/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessorInterface.h>
namespace AZ
{
namespace Render
{
class DiffuseProbeGrid;
enum class DiffuseProbeGridReadbackState
{
Idle,
Irradiance,
Distance,
Relocation,
Classification,
Complete
};
//! This class contains functionality necessary to read back the DiffuseProbeGrid textures, which
//! allows them to be saved as assets to run the DiffuseProbeGrid in non-realtime mode.
class DiffuseProbeGridTextureReadback final
{
public:
DiffuseProbeGridTextureReadback(DiffuseProbeGrid* diffuseProbeGrid);
~DiffuseProbeGridTextureReadback() = default;
void BeginTextureReadback(DiffuseProbeGridBakeTexturesCallback callback);
void Update(const AZ::Name& passName);
void FrameBegin(AZ::RPI::Pass::FramePrepareParams& params);
private:
DiffuseProbeGrid* m_diffuseProbeGrid = nullptr;
DiffuseProbeGridReadbackState m_readbackState = DiffuseProbeGridReadbackState::Idle;
AZStd::shared_ptr<AZ::RPI::AttachmentReadback> m_attachmentReadback;
DiffuseProbeGridBakeTexturesCallback m_callback;
AZ::RPI::AttachmentReadback::ReadbackResult m_irradianceReadbackResult;
AZ::RPI::AttachmentReadback::ReadbackResult m_distanceReadbackResult;
AZ::RPI::AttachmentReadback::ReadbackResult m_relocationReadbackResult;
AZ::RPI::AttachmentReadback::ReadbackResult m_classificationReadbackResult;
};
} // namespace Render
} // namespace AZ
@@ -209,7 +209,7 @@ namespace AZ
void ReflectionProbe::SetTransform(const AZ::Transform& transform)
{
// retrieve previous scale and revert the scale on the inner/outer extents
AZ::Vector3 previousScale = m_transform.GetScale();
float previousScale = m_transform.GetUniformScale();
m_outerExtents /= previousScale;
m_innerExtents /= previousScale;
@@ -218,12 +218,12 @@ namespace AZ
// avoid scaling the visualization sphere
AZ::Transform visualizationTransform = m_transform;
visualizationTransform.ExtractScale();
visualizationTransform.ExtractUniformScale();
m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, visualizationTransform);
// update the inner/outer extents with the new scale
m_outerExtents *= m_transform.GetScale();
m_innerExtents *= m_transform.GetScale();
m_outerExtents *= m_transform.GetUniformScale();
m_innerExtents *= m_transform.GetUniformScale();
m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents / 2.0f);
m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents / 2.0f);
@@ -232,14 +232,14 @@ namespace AZ
void ReflectionProbe::SetOuterExtents(const AZ::Vector3& outerExtents)
{
m_outerExtents = outerExtents * m_transform.GetScale();
m_outerExtents = outerExtents * m_transform.GetUniformScale();
m_outerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_outerExtents / 2.0f);
m_updateSrg = true;
}
void ReflectionProbe::SetInnerExtents(const AZ::Vector3& innerExtents)
{
m_innerExtents = innerExtents * m_transform.GetScale();
m_innerExtents = innerExtents * m_transform.GetUniformScale();
m_innerAabbWs = Aabb::CreateCenterHalfExtents(m_transform.GetTranslation(), m_innerExtents / 2.0f);
m_updateSrg = true;
}
@@ -135,6 +135,8 @@ set(FILES
Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.h
Source/DiffuseProbeGrid/DiffuseProbeGrid.cpp
Source/DiffuseProbeGrid/DiffuseProbeGrid.h
Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.cpp
Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h
Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.h
Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.cpp
Source/DisplayMapper/AcesOutputTransformPass.cpp
@@ -164,7 +164,7 @@ namespace AZ
arguments += " -Zi"; // Generate debug information
arguments += " -Zss"; // Compute Shader Hash considering source information
}
arguments += m_dxcAdditionalFreeArguments;
arguments += " " + m_dxcAdditionalFreeArguments;
return arguments;
}
}
@@ -180,6 +180,7 @@ namespace AZ
for (uint32_t imageIndex = static_cast<uint32_t>(NullDescriptorManager::ImageTypes::General2D); imageIndex < static_cast<uint32_t>(NullDescriptorManager::ImageTypes::Count); imageIndex++)
{
// different options for the images
imageCreateInfo.imageType = (imageIndex >= static_cast<uint32_t>(NullDescriptorManager::ImageTypes::General3D)) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
imageCreateInfo.extent = { m_imageNullDescriptor.m_images[imageIndex].m_dimension, m_imageNullDescriptor.m_images[imageIndex].m_dimension, 1 };
imageCreateInfo.samples = m_imageNullDescriptor.m_images[imageIndex].m_sampleCountFlag;
imageCreateInfo.format = m_imageNullDescriptor.m_images[imageIndex].m_format;

Some files were not shown because too many files have changed in this diff Show More