diff --git a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
index 33c2bf8d5f..15715f2136 100644
--- a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
@@ -43,6 +43,7 @@ set(GEM_DEPENDENCIES
Gem::GradientSignal
Gem::Vegetation
Gem::Atom_AtomBridge
+ Gem::AtomFont
Gem::NvCloth
Gem::Blast
Gem::AWSCore
diff --git a/AutomatedTesting/Gem/Code/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
index c8eccab947..1c0db5753b 100644
--- a/AutomatedTesting/Gem/Code/tool_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
@@ -55,6 +55,7 @@ set(GEM_DEPENDENCIES
Gem::Atom_RHI.Private
Gem::Atom_Feature_Common.Editor
Gem::Atom_AtomBridge.Editor
+ Gem::AtomFont
Gem::NvCloth.Editor
Gem::Blast.Editor
Gem::AWSCore.Editor
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py
new file mode 100644
index 0000000000..da4898b8a9
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py
@@ -0,0 +1,97 @@
+"""
+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.
+"""
+import pytest
+import os
+import logging
+import ly_test_tools.log.log_monitor
+
+from AWS.Windows.resource_mappings.resource_mappings import resource_mappings
+from AWS.Windows.cdk.cdk import cdk
+from AWS.common.aws_utils import aws_utils
+from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
+
+AWS_PROJECT_NAME = 'AWS-AutomationTest'
+AWS_CLIENT_AUTH_FEATURE_NAME = 'AWSClientAuth'
+AWS_CLIENT_AUTH_DEFAULT_PROFILE_NAME = 'default'
+
+GAME_LOG_NAME = 'Game.log'
+
+logger = logging.getLogger(__name__)
+
+
+@pytest.mark.SUITE_periodic
+@pytest.mark.usefixtures('automatic_process_killer')
+@pytest.mark.usefixtures('asset_processor')
+@pytest.mark.usefixtures('workspace')
+@pytest.mark.parametrize('project', ['AutomatedTesting'])
+@pytest.mark.usefixtures('cdk')
+@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME])
+@pytest.mark.usefixtures('resource_mappings')
+@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
+@pytest.mark.usefixtures('aws_utils')
+@pytest.mark.parametrize('region_name', ['us-west-2'])
+@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
+@pytest.mark.parametrize('session_name', ['o3de-Automation-session'])
+class TestAWSClientAuthPasswordSignIn(object):
+ """
+ Test class to verify AWS Cognito IDP Password sign in and Cognito Identity pool authenticated authorization.
+ """
+
+ def test_password_signin_credentials(self,
+ launcher: pytest.fixture,
+ cdk: pytest.fixture,
+ resource_mappings: pytest.fixture,
+ workspace: pytest.fixture,
+ asset_processor: pytest.fixture,
+ aws_utils: pytest.fixture
+ ):
+ """
+ Setup: Deploys cdk and updates resource mapping file.
+ Tests: Sign up new test user, admin confirm the user, sign in and get aws credentials.
+ Verification: Log monitor looks for success credentials log.
+ """
+ logger.info(f'Cdk stack names:\n{cdk.list()}')
+ stacks = cdk.deploy()
+ resource_mappings.populate_output_keys(stacks)
+ asset_processor.start()
+ asset_processor.wait_for_idle()
+
+ file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME)
+ log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
+
+ launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignUp']
+
+ with launcher.start(launch_ap=False):
+ result = log_monitor.monitor_log_for_lines(
+ expected_lines=['(Script) - Signup Success'],
+ unexpected_lines=['(Script) - Signup Fail'],
+ halt_on_unexpected=True,
+ )
+ assert result, 'Sign Up Success.'
+
+ launcher.stop()
+
+ cognito_idp = aws_utils.client('cognito-idp')
+ user_pool_id = resource_mappings.get_resource_name_id(f'{AWS_CLIENT_AUTH_FEATURE_NAME}.CognitoUserPoolId')
+ print(f'UserPoolId:{user_pool_id}')
+ cognito_idp.admin_confirm_sign_up(
+ UserPoolId=user_pool_id,
+ Username='test1'
+ )
+
+ launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignIn']
+
+ with launcher.start(launch_ap=False):
+ result = log_monitor.monitor_log_for_lines(
+ expected_lines=['(Script) - SignIn Success', '(Script) - Success credentials'],
+ unexpected_lines=['(Script) - SignIn Fail', '(Script) - Fail credentials'],
+ halt_on_unexpected=True,
+ )
+ assert result, 'Sign in Success, fetched authenticated AWS temp credentials.'
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py
index c8d8cff828..b3fa3011ce 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/resource_mappings/resource_mappings.py
@@ -39,6 +39,7 @@ class ResourceMappings:
self._region = region
self._feature_name = feature_name
self._account_id = account_id
+ self._resource_mappings = {}
assert os.path.exists(self._resource_mapping_file_path), \
f'Invalid resource mapping file path {self._resource_mapping_file_path}'
@@ -79,6 +80,7 @@ class ResourceMappings:
resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID'] = output.get('OutputValue',
'InvalidId')
+ self._resource_mappings = resource_mappings
with open(self._resource_mapping_file_path, 'w') as file_content:
json.dump(resource_mappings, file_content, indent=4)
@@ -103,6 +105,9 @@ class ResourceMappings:
self._region = ''
self._client = None
+ def get_resource_name_id(self, resource_key: str):
+ return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID']
+
@pytest.fixture(scope='function')
def resource_mappings(
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/ClientAuthPasswordSignIn.ly b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/ClientAuthPasswordSignIn.ly
new file mode 100644
index 0000000000..24fe4f2482
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/ClientAuthPasswordSignIn.ly
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:43b1a23b62fe2ffa05545ac99524f40b6fff49d6e35925b9d6138c00d8082e86
+size 9073
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/PasswordSignIn.scriptcanvas b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/PasswordSignIn.scriptcanvas
new file mode 100644
index 0000000000..ffc3064084
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/PasswordSignIn.scriptcanvas
@@ -0,0 +1,6642 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/filelist.xml b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/filelist.xml
new file mode 100644
index 0000000000..454b94a80a
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/filelist.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/level.pak b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/level.pak
new file mode 100644
index 0000000000..14e6b3274b
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/level.pak
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f583e0b1b7016a11583383e6c6fcd29f9e796c1a9cd4b6ddb10f7dc91deec17a
+size 3557
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/tags.txt b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/tags.txt
new file mode 100644
index 0000000000..0d6c1880e7
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignIn/tags.txt
@@ -0,0 +1,12 @@
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/ClientAuthPasswordSignUp.ly b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/ClientAuthPasswordSignUp.ly
new file mode 100644
index 0000000000..f853ec3890
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/ClientAuthPasswordSignUp.ly
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b948461412d201b3a80abafa60e916f860e46e28109333fbd263a2d5fc53c5a
+size 9103
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/PasswordSignUp.scriptcanvas b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/PasswordSignUp.scriptcanvas
new file mode 100644
index 0000000000..632d27d5b0
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/PasswordSignUp.scriptcanvas
@@ -0,0 +1,4408 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/filelist.xml b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/filelist.xml
new file mode 100644
index 0000000000..5e47a51414
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/filelist.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/level.pak b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/level.pak
new file mode 100644
index 0000000000..72ac9c767f
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/level.pak
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8cdb456f6eb348be27249d80e9d2262e1e0bdabf2c1ff02c1a64a5609dcd823c
+size 3553
diff --git a/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/tags.txt b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/tags.txt
new file mode 100644
index 0000000000..0d6c1880e7
--- /dev/null
+++ b/AutomatedTesting/Levels/AWS/ClientAuthPasswordSignUp/tags.txt
@@ -0,0 +1,12 @@
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
diff --git a/AutomatedTesting/Registry/authenticationProvider.setreg b/AutomatedTesting/Registry/authenticationProvider.setreg
new file mode 100644
index 0000000000..c90433468c
--- /dev/null
+++ b/AutomatedTesting/Registry/authenticationProvider.setreg
@@ -0,0 +1,5 @@
+{
+ "AWS":
+ {
+ }
+}
\ No newline at end of file
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp
index 79c1a28e5d..bd826544a1 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp
@@ -193,13 +193,12 @@ namespace AzFramework
bool handling = false;
for (auto& cameraInput : m_activeCameraInputs)
{
- cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
- handling = !cameraInput->Idle() || handling;
+ handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
}
for (auto& cameraInput : m_idleCameraInputs)
{
- cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
+ handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
}
return handling;
@@ -262,17 +261,26 @@ namespace AzFramework
{
m_activeCameraInputs[i]->Reset();
m_idleCameraInputs.push_back(m_activeCameraInputs[i]);
- m_activeCameraInputs[i] = m_activeCameraInputs[m_activeCameraInputs.size() - 1];
+ using AZStd::swap;
+ swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
m_activeCameraInputs.pop_back();
}
}
+ void Cameras::Clear()
+ {
+ Reset();
+ AZ_Assert(m_activeCameraInputs.empty(), "Active Camera Inputs is not empty");
+
+ m_idleCameraInputs.clear();
+ }
+
RotateCameraInput::RotateCameraInput(const InputChannelId rotateChannelId)
: m_rotateChannelId(rotateChannelId)
{
}
- void RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
+ bool RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
const ClickDetector::ClickEvent clickEvent = [&event, this] {
if (const auto& input = AZStd::get_if(&event))
@@ -304,6 +312,11 @@ namespace AzFramework
// noop
break;
}
+
+ // note - must also check !ending to ensure the mouse up (release) event
+ // is not consumed and can be propagated to other systems.
+ // (don't swallow mouse up events)
+ return !Idle() && !Ending();
}
Camera RotateCameraInput::StepCamera(
@@ -330,7 +343,7 @@ namespace AzFramework
{
}
- void PanCameraInput::HandleEvents(
+ bool PanCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
if (const auto& input = AZStd::get_if(&event))
@@ -347,6 +360,8 @@ namespace AzFramework
}
}
}
+
+ return !Idle();
}
Camera PanCameraInput::StepCamera(
@@ -411,7 +426,7 @@ namespace AzFramework
{
}
- void TranslateCameraInput::HandleEvents(
+ bool TranslateCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
if (const auto& input = AZStd::get_if(&event))
@@ -429,7 +444,8 @@ namespace AzFramework
m_boost = true;
}
}
- else if (input->m_state == InputChannel::State::Ended)
+ // ensure we don't process end events in the idle state
+ else if (input->m_state == InputChannel::State::Ended && !Idle())
{
m_translation &= ~(translationFromKey(input->m_channelId));
if (m_translation == TranslationType::Nil)
@@ -442,6 +458,8 @@ namespace AzFramework
}
}
}
+
+ return !Idle();
}
Camera TranslateCameraInput::StepCamera(
@@ -503,7 +521,7 @@ namespace AzFramework
m_boost = false;
}
- void OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
+ bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
{
if (const auto* input = AZStd::get_if(&event))
{
@@ -522,8 +540,10 @@ namespace AzFramework
if (Active())
{
- m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
+ return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
}
+
+ return !Idle();
}
Camera OrbitCameraInput::StepCamera(
@@ -533,7 +553,7 @@ namespace AzFramework
if (Beginning())
{
- const auto hasLookAt = [&nextCamera, &targetCamera, lookAtFn = m_lookAtFn] {
+ const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn] {
if (lookAtFn)
{
if (const auto lookAt = lookAtFn())
@@ -585,13 +605,15 @@ namespace AzFramework
return nextCamera;
}
- void OrbitDollyScrollCameraInput::HandleEvents(
+ bool OrbitDollyScrollCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
if (const auto* scroll = AZStd::get_if(&event))
{
BeginActivation();
}
+
+ return !Idle();
}
Camera OrbitDollyScrollCameraInput::StepCamera(
@@ -609,7 +631,7 @@ namespace AzFramework
{
}
- void OrbitDollyCursorMoveCameraInput::HandleEvents(
+ bool OrbitDollyCursorMoveCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
if (const auto& input = AZStd::get_if(&event))
@@ -626,6 +648,8 @@ namespace AzFramework
}
}
}
+
+ return !Idle();
}
Camera OrbitDollyCursorMoveCameraInput::StepCamera(
@@ -637,13 +661,15 @@ namespace AzFramework
return nextCamera;
}
- void ScrollTranslationCameraInput::HandleEvents(
+ bool ScrollTranslationCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
{
if (const auto* scroll = AZStd::get_if(&event))
{
BeginActivation();
}
+
+ return !Idle();
}
Camera ScrollTranslationCameraInput::StepCamera(
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h
index b6b2bc1e6a..582fb5a6de 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h
@@ -149,7 +149,7 @@ namespace AzFramework
ResetImpl();
}
- virtual void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0;
+ virtual bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0;
virtual Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) = 0;
virtual bool Exclusive() const
@@ -171,16 +171,29 @@ namespace AzFramework
class Cameras
{
public:
- void AddCamera(AZStd::shared_ptr cameraInput);
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta);
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime);
+
+ void AddCamera(AZStd::shared_ptr cameraInput);
+ //! Reset the state of all cameras.
void Reset();
+ //! Remove all cameras that were added.
+ void Clear();
+ //! Is one of the cameras in the active camera inputs marked as 'exclusive'.
+ //! @note This implies no other sibling cameras can begin while the exclusive camera is running.
+ bool Exclusive() const;
private:
AZStd::vector> m_activeCameraInputs;
AZStd::vector> m_idleCameraInputs;
};
+ inline bool Cameras::Exclusive() const
+ {
+ return AZStd::any_of(
+ m_activeCameraInputs.begin(), m_activeCameraInputs.end(), [](const auto& cameraInput) { return cameraInput->Exclusive(); });
+ }
+
class CameraSystem
{
public:
@@ -200,7 +213,7 @@ namespace AzFramework
explicit RotateCameraInput(InputChannelId rotateChannelId);
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
private:
@@ -241,7 +254,7 @@ namespace AzFramework
PanCameraInput(InputChannelId panChannelId, PanAxesFn panAxesFn);
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
private:
@@ -282,7 +295,7 @@ namespace AzFramework
explicit TranslateCameraInput(TranslationAxesFn translationAxesFn);
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
void ResetImpl() override;
@@ -352,7 +365,7 @@ namespace AzFramework
{
public:
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
};
@@ -362,7 +375,7 @@ namespace AzFramework
explicit OrbitDollyCursorMoveCameraInput(InputChannelId dollyChannelId);
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
private:
@@ -373,7 +386,7 @@ namespace AzFramework
{
public:
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
};
@@ -383,7 +396,7 @@ namespace AzFramework
using LookAtFn = AZStd::function()>;
// CameraInput overrides ...
- void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
+ bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
bool Exclusive() const override;
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
index 4b8fbca36a..c276463554 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp
@@ -17,6 +17,17 @@ namespace AzFramework
{
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
{
+ const auto previousDetectionState = m_detectionState;
+ if (previousDetectionState == DetectionState::WaitingForMove)
+ {
+ // only allow the action to begin if the mouse has been moved a small amount
+ m_moveAccumulator += ScreenVectorLength(cursorDelta);
+ if (m_moveAccumulator > m_deadZone)
+ {
+ m_detectionState = DetectionState::Moved;
+ }
+ }
+
if (clickEvent == ClickEvent::Down)
{
const auto now = std::chrono::steady_clock::now();
@@ -52,15 +63,9 @@ namespace AzFramework
return clickOutcome;
}
- if (m_detectionState == DetectionState::WaitingForMove)
+ if (previousDetectionState == DetectionState::WaitingForMove && m_detectionState == DetectionState::Moved)
{
- // only allow the action to begin if the mouse has been moved a small amount
- m_moveAccumulator += ScreenVectorLength(cursorDelta);
- if (m_moveAccumulator > m_deadZone)
- {
- m_detectionState = DetectionState::Moved;
- return ClickOutcome::Move;
- }
+ return ClickOutcome::Move;
}
return ClickOutcome::Nil;
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
index 997ccd07d9..a595735d28 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.h
@@ -50,7 +50,11 @@ namespace AzFramework
//! Called from any type of 'handle event' function.
ClickOutcome DetectClick(ClickEvent clickEvent, const ScreenVector& cursorDelta);
+ //! Override the default double click interval.
+ //! @note Default is 400ms - system default.
void SetDoubleClickInterval(float doubleClickInterval);
+ //! Override the dead zone before a 'move' outcome will be triggered.
+ void SetDeadZone(float deadZone);
private:
//! Internal state of ClickDetector based on incoming events.
@@ -72,4 +76,9 @@ namespace AzFramework
{
m_doubleClickInterval = doubleClickInterval;
}
+
+ inline void ClickDetector::SetDeadZone(const float deadZone)
+ {
+ m_deadZone = deadZone;
+ }
} // namespace AzFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index e6bb8c7dee..571aea5875 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -84,6 +84,7 @@ namespace AzToolsFramework
AZStd::vector entities;
AZStd::vector> instances;
+ AZStd::unordered_map nestedInstanceLinkPatchesMap;
// Retrieve all entities affected and identify Instances
if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
@@ -96,6 +97,16 @@ namespace AzToolsFramework
// target templates of the other instances.
for (auto& nestedInstance : instances)
{
+ auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId());
+
+ if (linkRef.has_value())
+ {
+ PrefabDom oldLinkPatches;
+ oldLinkPatches.CopyFrom(linkRef->get().GetLinkDom(), oldLinkPatches.GetAllocator());
+
+ nestedInstanceLinkPatchesMap.emplace(nestedInstance.get(), AZStd::move(oldLinkPatches));
+ }
+
RemoveLink(nestedInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
}
@@ -122,6 +133,9 @@ namespace AzToolsFramework
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
+ // Apply the correct transform to the container for the new instance, and store the patch for use when creating the link.
+ PrefabDom patch = ApplyContainerTransformAndGeneratePatch(containerEntityId, commonRootEntityId, topLevelEntities);
+
// Parent the non-container top level entities to the container entity.
// Parenting the top level container entities will be done during the creation of links.
for (AZ::Entity* topLevelEntity : topLevelEntities)
@@ -141,35 +155,55 @@ namespace AzToolsFramework
instanceToCreate->get().GetNestedInstances([&](AZStd::unique_ptr& nestedInstance) {
AZ_Assert(nestedInstance, "Invalid nested instance found in the new prefab created.");
+
EntityOptionalReference nestedInstanceContainerEntity = nestedInstance->GetContainerEntity();
AZ_Assert(
nestedInstanceContainerEntity, "Invalid container entity found for the nested instance used in prefab creation.");
- AZ::EntityId parentId;
- AZ::TransformBus::EventResult(
- parentId, nestedInstanceContainerEntity->get().GetId(), &AZ::TransformBus::Events::GetParentId);
+ AZ::EntityId nestedInstanceContainerEntityId = nestedInstanceContainerEntity->get().GetId();
+ PrefabDom previousPatch;
- auto entityIterator = AZStd::find_if(
- entities.begin(), entities.end(), [parentId](AZ::Entity* entity) { return entity->GetId() == parentId; });
-
- // If the previous parent entity of the nested instance is not part of the entities of the newly created prefab,
- // then set the parent of the nested prefab as the container entity of the newly created prefab.
- if (entityIterator == entities.end())
+ // Retrieve the previous patch if it exists
+ if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get()))
{
- parentId = containerEntityId;
+ previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]);
}
// These link creations shouldn't be undone because that would put the template in a non-usable state if a user
// chooses to instantiate the template after undoing the creation.
- CreateLink(
- {&nestedInstanceContainerEntity->get()}, *nestedInstance, instanceToCreate->get().GetTemplateId(),
- undoBatch.GetUndoBatch(), parentId, false);
+ CreateLink(*nestedInstance, instanceToCreate->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(previousPatch), false);
+
+ // If this nested instance's container is a top level entity in the new prefab, re-parent it and apply the change.
+ if (AZStd::find(topLevelEntities.begin(), topLevelEntities.end(), &nestedInstanceContainerEntity->get()) != topLevelEntities.end())
+ {
+ Prefab::PrefabDom containerEntityDomBefore;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *nestedInstanceContainerEntity);
+
+ AZ::TransformBus::Event(nestedInstanceContainerEntityId, &AZ::TransformBus::Events::SetParent, containerEntityId);
+
+ PrefabDom containerEntityDomAfter;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *nestedInstanceContainerEntity);
+
+ PrefabDom reparentPatch;
+ m_instanceToTemplateInterface->GeneratePatch(reparentPatch, containerEntityDomBefore, containerEntityDomAfter);
+ m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(reparentPatch, nestedInstanceContainerEntityId);
+
+ // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes as a separate step
+ m_prefabUndoCache.Store(nestedInstanceContainerEntityId, AZStd::move(containerEntityDomAfter));
+
+ // Save these changes as patches to the link
+ PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast(nestedInstanceContainerEntityId)));
+ linkUpdate->SetParent(undoBatch.GetUndoBatch());
+ linkUpdate->Capture(reparentPatch, nestedInstance->GetLinkId());
+
+ linkUpdate->Redo();
+ }
});
// Create a link between the templates of the newly created instance and the instance it's being parented under.
CreateLink(
- topLevelEntities, instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(),
- undoBatch.GetUndoBatch(), commonRootEntityId);
+ instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
+ AZStd::move(patch));
for (AZ::Entity* topLevelEntity : topLevelEntities)
{
@@ -199,6 +233,40 @@ namespace AzToolsFramework
return AZ::Success();
}
+ PrefabDom PrefabPublicHandler::ApplyContainerTransformAndGeneratePatch(AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities)
+ {
+ AZ::Entity* containerEntity = GetEntityById(containerEntityId);
+ AZ_Assert(containerEntity, "Invalid container entity passed to ApplyContainerTransformAndGeneratePatch.");
+
+ // Generate the transform for the container entity out of the top level entities, and set it
+ // This step needs to be done before anything is parented to the container, else children position will be wrong
+ Prefab::PrefabDom containerEntityDomBefore;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
+
+ AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
+ AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
+
+ // Set container entity to be child of common root
+ AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parentEntityId);
+
+ // Set the transform (translation, rotation) of the container entity
+ GenerateContainerEntityTransform(childEntities, containerEntityTranslation, containerEntityRotation);
+ AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
+ AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
+
+ PrefabDom containerEntityDomAfter;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
+
+ PrefabDom patch;
+ m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
+ m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
+
+ // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
+ m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
+
+ return AZStd::move(patch);
+ }
+
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
{
@@ -249,10 +317,10 @@ namespace AzToolsFramework
// Initialize Undo Batch object
ScopedUndoBatch undoBatch("Instantiate Prefab");
+ // Instantiate the Prefab
PrefabDom instanceToParentUnderDomBeforeCreate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
- // Instantiate the Prefab
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder);
if (!instanceToCreate)
@@ -264,11 +332,32 @@ namespace AzToolsFramework
PrefabUndoHelpers::UpdatePrefabInstance(
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
- CreateLink({}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), parent);
+ // Create Link with correct container patches
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
+ AZ::Entity* containerEntity = GetEntityById(containerEntityId);
+ AZ_Assert(containerEntity, "Invalid container entity detected in InstantiatePrefab.");
- // Apply position
+ Prefab::PrefabDom containerEntityDomBefore;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
+
+ // Set container entity's parent
+ AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parent);
+
+ // Set the position of the container entity
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetWorldTranslation, position);
+
+ PrefabDom containerEntityDomAfter;
+ m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
+
+ // Generate patch to be stored in the link
+ PrefabDom patch;
+ m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
+ m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
+
+ CreateLink(instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(patch));
+
+ // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
+ m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
}
return AZ::Success();
@@ -335,33 +424,9 @@ namespace AzToolsFramework
}
void PrefabPublicHandler::CreateLink(
- const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
- UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded)
+ Instance& sourceInstance, TemplateId targetTemplateId,
+ UndoSystem::URSequencePoint* undoBatch, PrefabDom patch, const bool isUndoRedoSupportNeeded)
{
- AZ::EntityId containerEntityId = sourceInstance.GetContainerEntityId();
- AZ::Entity* containerEntity = GetEntityById(containerEntityId);
- Prefab::PrefabDom containerEntityDomBefore;
- m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
-
- AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
- AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
-
- // Set the transform (translation, rotation) of the container entity
- GenerateContainerEntityTransform(topLevelEntities, containerEntityTranslation, containerEntityRotation);
-
- // Set container entity to be child of common root
- AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, commonRootEntityId);
-
- AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
- AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
-
- PrefabDom containerEntityDomAfter;
- m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
-
- PrefabDom patch;
- m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
- m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
-
LinkId linkId;
if (isUndoRedoSupportNeeded)
{
@@ -377,9 +442,6 @@ namespace AzToolsFramework
}
sourceInstance.SetLinkId(linkId);
-
- // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
- m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
}
void PrefabPublicHandler::RemoveLink(
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
index d88086dda9..5ad5b4a9cf 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
@@ -68,20 +68,32 @@ namespace AzToolsFramework
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
+
+ /**
+ * Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch.
+ * The container will be parented to parentId, moved to the average transform of the future direct children and its cache will be updated.
+ * This helper function won't support undo/redo, update the templates or create any links. All that needs to be done by the caller.
+ *
+ * \param containerEntityId The container to apply the changes to.
+ * \param parentEntityId The id of the entity the container should be parented to.
+ * \param childEntities A list of entities that will subsequently be parented to this container.
+ * \return The PrefabDom containing the patches that should be stored in the parent link.
+ */
+ PrefabDom ApplyContainerTransformAndGeneratePatch(
+ AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities);
/**
* Creates a link between the templates of an instance and its parent.
*
- * \param topLevelEntities The list of entities that are immediate children to the container entity of the instance.
* \param sourceInstance The instance that corresponds to the source template of the link.
* \param targetInstance The id of the target template.
* \param undoBatch The undo batch to set as parent for this create link action.
- * \param commonRootEntityId The id of the entity that the source instance should be parented under.
+ * \param patch The patch to store in the newly created link dom.
* \param isUndoRedoSupportNeeded The flag indicating whether the link should be created with undo/redo support or not.
*/
void CreateLink(
- const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
- UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded = true);
+ Instance& sourceInstance, TemplateId targetTemplateId, UndoSystem::URSequencePoint* undoBatch,
+ PrefabDom patch, const bool isUndoRedoSupportNeeded = true);
/**
* Removes the link between template of the sourceInstance and the template corresponding to targetTemplateId.
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
index bc7afbf085..3edc190fb7 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
@@ -93,28 +93,12 @@ namespace AzToolsFramework
EditorContextMenuBus::Handler::BusConnect();
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
AZ::Interface::Register(this);
-
- bool prefabWipFeaturesEnabled = false;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(
- prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
-
- if (prefabWipFeaturesEnabled)
- {
- AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
- }
+ AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
}
PrefabIntegrationManager::~PrefabIntegrationManager()
{
- bool prefabWipFeaturesEnabled = false;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(
- prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
-
- if (prefabWipFeaturesEnabled)
- {
- AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
- }
-
+ AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
AZ::Interface::Unregister(this);
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
EditorContextMenuBus::Handler::BusDisconnect();
@@ -137,66 +121,63 @@ namespace AzToolsFramework
void PrefabIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu) const
{
- bool prefabWipFeaturesEnabled = false;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(
- prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
-
AzToolsFramework::EntityIdList selectedEntities;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
selectedEntities, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
- if (prefabWipFeaturesEnabled)
+ bool prefabWipFeaturesEnabled = false;
+ AzFramework::ApplicationRequests::Bus::BroadcastResult(
+ prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
+
+ // Create Prefab
{
- // Create Prefab
+ if (!selectedEntities.empty())
{
- if (!selectedEntities.empty())
+ // Hide if the only selected entity is the Level Container
+ if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
{
- // Hide if the only selected entity is the Level Container
- if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
+ bool layerInSelection = false;
+
+ for (AZ::EntityId entityId : selectedEntities)
{
- bool layerInSelection = false;
-
- for (AZ::EntityId entityId : selectedEntities)
- {
- if (!layerInSelection)
- {
- AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
- layerInSelection, entityId,
- &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
-
- if (layerInSelection)
- {
- break;
- }
- }
- }
-
- // Layers can't be in prefabs.
if (!layerInSelection)
{
- QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
- createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
+ AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
+ layerInSelection, entityId,
+ &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
- QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
- ContextMenu_CreatePrefab(selectedEntities);
- });
+ if (layerInSelection)
+ {
+ break;
+ }
}
}
+
+ // Layers can't be in prefabs.
+ if (!layerInSelection)
+ {
+ QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
+ createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
+
+ QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
+ ContextMenu_CreatePrefab(selectedEntities);
+ });
+ }
}
}
-
- // Instantiate Prefab
- {
- QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
- instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
-
- QObject::connect(
- instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
- }
-
- menu->addSeparator();
}
+ // Instantiate Prefab
+ {
+ QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab..."));
+ instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene."));
+
+ QObject::connect(
+ instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiatePrefab(); });
+ }
+
+ menu->addSeparator();
+
bool itemWasShown = false;
// Edit/Save Prefab
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
index ee95412376..8e91dc945d 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
@@ -304,4 +305,24 @@ namespace AzToolsFramework
return entityContextId;
}
+
+ //! Maps a mouse interaction event to a ClickDetector event.
+ //! @note Function only cares about up or down events, all other events are mapped to Nil (ignored).
+ inline AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction(
+ const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
+ {
+ if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
+ {
+ if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
+ {
+ return AzFramework::ClickDetector::ClickEvent::Down;
+ }
+
+ if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
+ {
+ return AzFramework::ClickDetector::ClickEvent::Up;
+ }
+ }
+ return AzFramework::ClickDetector::ClickEvent::Nil;
+ }
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp
index 2e467caa4c..531cffb561 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.cpp
@@ -14,6 +14,7 @@
#include
#include
+#include
#include
@@ -27,8 +28,11 @@ namespace AzToolsFramework
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
- if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
- mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
+ m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
+
+ const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
+ const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
+ if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Move)
{
if (m_leftMouseDown)
{
@@ -58,8 +62,7 @@ namespace AzToolsFramework
}
}
- if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
- mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
+ if (clickOutcome == AzFramework::ClickDetector::ClickOutcome::Release)
{
if (m_leftMouseUp)
{
@@ -77,6 +80,8 @@ namespace AzToolsFramework
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
+ m_cursorState.Update();
+
if (m_boxSelectRegion)
{
debugDisplay.DepthTestOff();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h
index 7f50b16325..c115220755 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorBoxSelect.h
@@ -14,6 +14,8 @@
#include
#include
+#include
+#include
#include
#include
@@ -26,49 +28,49 @@ namespace AzFramework
namespace AzToolsFramework
{
- /// Utility to provide box select (click and drag) support for viewport types.
- /// Users can override the mouse event callbacks and display scene function to customize behavior.
+ //! Utility to provide box select (click and drag) support for viewport types.
+ //! Users can override the mouse event callbacks and display scene function to customize behavior.
class EditorBoxSelect
{
public:
EditorBoxSelect() = default;
- /// Return if a box select action is currently taking place.
+ //! Return if a box select action is currently taking place.
bool Active() const { return m_boxSelectRegion.has_value(); }
- /// Update the box select for various mouse events.
- /// Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
+ //! Update the box select for various mouse events.
+ //! Call HandleMouseInteraction from type/system implementing MouseViewportRequests interface.
void HandleMouseInteraction(
const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
- /// Responsible for drawing the 2d box representing the selection in screen space.
+ //! Responsible for drawing the 2d box representing the selection in screen space.
void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
- /// Custom drawing behavior to happen during a box select.
+ //! Custom drawing behavior to happen during a box select.
void DisplayScene(
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay);
- /// Set the left mouse down callback.
+ //! Set the left mouse down callback.
void InstallLeftMouseDown(
const AZStd::function& leftMouseDown);
- /// Set the mouse move callback.
+ //! Set the mouse move callback.
void InstallMouseMove(
const AZStd::function& mouseMove);
- /// Set the left mouse up callback.
+ //! Set the left mouse up callback.
void InstallLeftMouseUp(
const AZStd::function& leftMouseUp);
- /// Set the display scene callback.
+ //! Set the display scene callback.
void InstallDisplayScene(
const AZStd::function& displayScene);
- /// Return the box select region.
- /// If a box selection is being made, return the current rectangle representing the area.
- /// If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
+ //! Return the box select region.
+ //! If a box selection is being made, return the current rectangle representing the area.
+ //! If there is currently no active box select, then the Maybe type will be empty (there will be no region/area).
const AZStd::optional& BoxRegion() const { return m_boxSelectRegion; }
- /// Return the active modifiers from the previous frame.
+ //! Return the active modifiers from the previous frame.
ViewportInteraction::KeyboardModifiers PreviousModifiers() const { return m_previousModifiers; }
private:
@@ -79,7 +81,9 @@ namespace AzToolsFramework
AZStd::function m_displayScene;
- AZStd::optional m_boxSelectRegion; ///< Maybe/optional value to store box select region while active.
- ViewportInteraction::KeyboardModifiers m_previousModifiers; ///< Modifier keys active on the previous frame.
+ AZStd::optional m_boxSelectRegion; //!< Maybe/optional value to store box select region while active.
+ ViewportInteraction::KeyboardModifiers m_previousModifiers; //!< Modifier keys active on the previous frame.
+ AzFramework::ClickDetector m_clickDetector; //!< Utility type to detect if a mouse click or move has occurred.
+ AzFramework::CursorState m_cursorState; //!< Utility type to track the current cursor position (and movement/delta).
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
index 6e49f7c601..91644dc6ac 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
@@ -1782,22 +1782,7 @@ namespace AzToolsFramework
m_cachedEntityIdUnderCursor = m_editorHelpers->HandleMouseInteraction(cameraState, mouseInteraction);
- const AzFramework::ClickDetector::ClickEvent selectClickEvent = [&mouseInteraction] {
- if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left())
- {
- if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down)
- {
- return AzFramework::ClickDetector::ClickEvent::Down;
- }
-
- if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up)
- {
- return AzFramework::ClickDetector::ClickEvent::Up;
- }
- }
- return AzFramework::ClickDetector::ClickEvent::Nil;
- }();
-
+ const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction);
m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates);
const auto clickOutcome = m_clickDetector.DetectClick(selectClickEvent, m_cursorState.CursorDelta());
diff --git a/Code/Framework/Tests/CameraInputTests.cpp b/Code/Framework/Tests/CameraInputTests.cpp
new file mode 100644
index 0000000000..6fe9837c22
--- /dev/null
+++ b/Code/Framework/Tests/CameraInputTests.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+namespace UnitTest
+{
+ class CameraInputFixture : public AllocatorsTestFixture
+ {
+ public:
+ AzFramework::Camera m_camera;
+ AzFramework::Camera m_targetCamera;
+ AZStd::shared_ptr m_cameraSystem;
+
+ bool HandleEventAndUpdate(const AzFramework::InputEvent& event)
+ {
+ constexpr float deltaTime = 0.01666f; // 60fps
+ const bool consumed = m_cameraSystem->HandleEvents(event);
+ m_camera = m_cameraSystem->StepCamera(m_targetCamera, deltaTime);
+ return consumed;
+ }
+
+ void SetUp() override
+ {
+ AllocatorsTestFixture::SetUp();
+
+ AzFramework::ReloadCameraKeyBindings();
+
+ m_cameraSystem = AZStd::make_shared();
+
+ auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Right);
+ auto firstPersonTranslateCamera = AZStd::make_shared(AzFramework::LookTranslation);
+
+ auto orbitCamera = AZStd::make_shared();
+ auto orbitRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left);
+ auto orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation);
+
+ orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera);
+ orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera);
+
+ m_cameraSystem->m_cameras.AddCamera(firstPersonRotateCamera);
+ m_cameraSystem->m_cameras.AddCamera(firstPersonTranslateCamera);
+ m_cameraSystem->m_cameras.AddCamera(orbitCamera);
+ }
+
+ void TearDown() override
+ {
+ m_cameraSystem->m_cameras.Clear();
+ m_cameraSystem.reset();
+
+ AllocatorsTestFixture::TearDown();
+ }
+ };
+
+ TEST_F(CameraInputFixture, BeginEndOrbitCameraConsumesCorrectEvents)
+ {
+ // set initial mouse position
+ const bool consumed1 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(5, 5)});
+ // begin orbit camera
+ const bool consumed2 = HandleEventAndUpdate(
+ AzFramework::DiscreteInputEvent{AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began});
+ // begin listening for orbit rotate (click detector) - event is not consumed
+ const bool consumed3 = HandleEventAndUpdate(
+ AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began});
+ // begin orbit rotate (mouse has moved sufficient distance to initiate)
+ const bool consumed4 = HandleEventAndUpdate(AzFramework::CursorEvent{AzFramework::ScreenPoint(10, 10)});
+ // end orbit (mouse up) - event is not consumed
+ const bool consumed5 = HandleEventAndUpdate(
+ AzFramework::DiscreteInputEvent{AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended});
+
+ const auto allConsumed = AZStd::vector{consumed1, consumed2, consumed3, consumed4, consumed5};
+
+ using ::testing::ElementsAre;
+ EXPECT_THAT(allConsumed, ElementsAre(false, true, false, true, false));
+ }
+} // namespace UnitTest
diff --git a/Code/Framework/Tests/ClickDetectorTests.cpp b/Code/Framework/Tests/ClickDetectorTests.cpp
index 7e6f9634c8..64f06ee66c 100644
--- a/Code/Framework/Tests/ClickDetectorTests.cpp
+++ b/Code/Framework/Tests/ClickDetectorTests.cpp
@@ -139,4 +139,21 @@ namespace UnitTest
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
}
+
+ // if the click detector registers a mouse down event, but then all intermediate calls are ignored
+ // (another system may start intercepting events and swallowing them) then when we do receive a mouse
+ // up event we should ensure we take into account the current delta - if the delta is large, then the
+ // outcome will be release
+ TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoringMouseMovesBeforeMouseUpWithLargeDelta)
+ {
+ using ::testing::Eq;
+
+ const ClickDetector::ClickOutcome downOutcome =
+ m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
+ const ClickDetector::ClickOutcome upOutcome =
+ m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(50, 50));
+
+ EXPECT_THAT(downOutcome, Eq(ClickDetector::ClickOutcome::Nil));
+ EXPECT_THAT(upOutcome, Eq(ClickDetector::ClickOutcome::Release));
+ }
} // namespace UnitTest
diff --git a/Code/Framework/Tests/frameworktests_files.cmake b/Code/Framework/Tests/frameworktests_files.cmake
index e249cf6e64..197bcc9fce 100644
--- a/Code/Framework/Tests/frameworktests_files.cmake
+++ b/Code/Framework/Tests/frameworktests_files.cmake
@@ -17,6 +17,7 @@ set(FILES
BinToTextEncode.cpp
ComponentAddRemove.cpp
ComponentAdapterTests.cpp
+ CameraInputTests.cpp
ClickDetectorTests.cpp
CursorStateTests.cpp
EntityContext.cpp
diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp
index 85c40f2092..f72801a4d3 100644
--- a/Code/Sandbox/Editor/EditorViewportWidget.cpp
+++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp
@@ -457,15 +457,6 @@ void EditorViewportWidget::Update()
return;
}
- static bool sentOnWindowCreated = false;
- if (!sentOnWindowCreated && windowHandle()->isActive())
- {
- sentOnWindowCreated = true;
- AzFramework::WindowSystemNotificationBus::Broadcast(
- &AzFramework::WindowSystemNotificationBus::Handler::OnWindowCreated,
- reinterpret_cast(winId()));
- }
-
m_updatingCameraPosition = true;
if (!ed_useNewCameraSystem)
{
diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.cpp b/Code/Sandbox/Editor/ModernViewportCameraController.cpp
index af161af493..83ab2ef0b5 100644
--- a/Code/Sandbox/Editor/ModernViewportCameraController.cpp
+++ b/Code/Sandbox/Editor/ModernViewportCameraController.cpp
@@ -97,17 +97,38 @@ namespace SandboxEditor
AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect();
}
+ // should the camera system respond to this particular event
+ static bool ShouldHandle(const AzFramework::ViewportControllerPriority priority, const bool exclusive)
+ {
+ // ModernViewportCameraControllerInstance receives events at all priorities, it should only respond
+ // to normal priority events if it is not in 'exclusive' mode and when in 'exclusive' mode it should
+ // only respond to the highest priority events
+ return !exclusive && priority == AzFramework::ViewportControllerPriority::Normal ||
+ exclusive && priority == AzFramework::ViewportControllerPriority::Highest;
+ }
+
bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
{
AzFramework::WindowSize windowSize;
AzFramework::WindowRequestBus::EventResult(
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
- return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
+ if (ShouldHandle(event.m_priority, m_cameraSystem.m_cameras.Exclusive()))
+ {
+ return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
+ }
+
+ return false;
}
void ModernViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
{
+ // only update for a single priority (normal is the default)
+ if (event.m_priority != AzFramework::ViewportControllerPriority::Normal)
+ {
+ return;
+ }
+
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
{
m_updatingTransform = true;
diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.h b/Code/Sandbox/Editor/ModernViewportCameraController.h
index 066c8efaa8..39e3c9cbb3 100644
--- a/Code/Sandbox/Editor/ModernViewportCameraController.h
+++ b/Code/Sandbox/Editor/ModernViewportCameraController.h
@@ -22,7 +22,9 @@
namespace SandboxEditor
{
class ModernViewportCameraControllerInstance;
- class ModernViewportCameraController : public AzFramework::MultiViewportController
+ class ModernViewportCameraController
+ : public AzFramework::MultiViewportController<
+ ModernViewportCameraControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>
{
public:
using CameraListBuilder = AZStd::function;
diff --git a/Code/Tools/ProjectManager/Resources/ArrowDownLine.svg b/Code/Tools/ProjectManager/Resources/ArrowDownLine.svg
new file mode 100644
index 0000000000..8418431f11
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/ArrowDownLine.svg
@@ -0,0 +1,3 @@
+
diff --git a/Code/Tools/ProjectManager/Resources/ArrowUpLine.svg b/Code/Tools/ProjectManager/Resources/ArrowUpLine.svg
new file mode 100644
index 0000000000..d7f26fdad5
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/ArrowUpLine.svg
@@ -0,0 +1,3 @@
+
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
index 5737a188de..3c221d6055 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
@@ -58,13 +58,6 @@ namespace O3DE::ProjectManager
hLayout->addWidget(m_gemListView);
hLayout->addWidget(m_gemInspector);
-
-
- // Select the first entry after everything got correctly sized
- QTimer::singleShot(100, [=]{
- QModelIndex firstModelIndex = m_gemListView->model()->index(0,0);
- m_gemListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
- });
}
QVector GemCatalogScreen::GenerateTestData()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp
index 729935fc8e..5b7127bdbe 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp
@@ -32,21 +32,36 @@ namespace O3DE::ProjectManager
{
switch (platform)
{
- case O3DE::ProjectManager::GemInfo::Android:
+ case Android:
return "Android";
- case O3DE::ProjectManager::GemInfo::iOS:
+ case iOS:
return "iOS";
- case O3DE::ProjectManager::GemInfo::Linux:
+ case Linux:
return "Linux";
- case O3DE::ProjectManager::GemInfo::macOS:
+ case macOS:
return "macOS";
- case O3DE::ProjectManager::GemInfo::Windows:
+ case Windows:
return "Windows";
default:
return "";
}
}
+ QString GemInfo::GetTypeString(Type type)
+ {
+ switch (type)
+ {
+ case Asset:
+ return "Asset";
+ case Code:
+ return "Code";
+ case Tool:
+ return "Tool";
+ default:
+ return "";
+ }
+ }
+
bool GemInfo::IsPlatformSupported(Platform platform) const
{
return (m_platforms & platform);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
index 7ee619702f..28b2fab451 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
@@ -36,6 +36,16 @@ namespace O3DE::ProjectManager
Q_DECLARE_FLAGS(Platforms, Platform)
static QString GetPlatformString(Platform platform);
+ enum Type
+ {
+ Asset = 1 << 0,
+ Code = 1 << 1,
+ Tool = 1 << 2,
+ NumTypes = 3
+ };
+ Q_DECLARE_FLAGS(Types, Type)
+ static QString GetTypeString(Type type);
+
GemInfo() = default;
GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded);
bool IsPlatformSupported(Platform platform) const;
@@ -50,6 +60,7 @@ namespace O3DE::ProjectManager
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
QString m_summary;
Platforms m_platforms;
+ Types m_types; //! Asset and/or Code and/or Tool
QStringList m_features;
QString m_directoryLink;
QString m_documentationLink;
@@ -62,3 +73,4 @@ namespace O3DE::ProjectManager
} // namespace O3DE::ProjectManager
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms)
+Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Types)
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
index 1112c656f3..addf59783d 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
@@ -10,7 +10,8 @@
*
*/
-#include "GemModel.h"
+#include
+#include
namespace O3DE::ProjectManager
{
@@ -32,8 +33,11 @@ namespace O3DE::ProjectManager
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
item->setData(gemInfo.m_name, RoleName);
+ const QString uuidString = gemInfo.m_uuid.ToString().c_str();
+ item->setData(uuidString, RoleUuid);
item->setData(gemInfo.m_creator, RoleCreator);
- item->setData(static_cast(gemInfo.m_platforms), RolePlatforms);
+ item->setData(aznumeric_cast(gemInfo.m_platforms), RolePlatforms);
+ item->setData(aznumeric_cast(gemInfo.m_types), RoleTypes);
item->setData(gemInfo.m_summary, RoleSummary);
item->setData(gemInfo.m_isAdded, RoleIsAdded);
@@ -48,6 +52,8 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_features, RoleFeatures);
appendRow(item);
+
+ m_uuidToNameMap[uuidString] = gemInfo.m_displayName;
}
void GemModel::Clear()
@@ -65,11 +71,21 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleCreator).toString();
}
+ QString GemModel::GetUuidString(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleUuid).toString();
+ }
+
GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex)
{
return static_cast(modelIndex.data(RolePlatforms).toInt());
}
+ GemInfo::Types GemModel::GetTypes(const QModelIndex& modelIndex)
+ {
+ return static_cast(modelIndex.data(RoleTypes).toInt());
+ }
+
QString GemModel::GetSummary(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleSummary).toString();
@@ -90,9 +106,35 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleDocLink).toString();
}
+ AZ::Outcome GemModel::FindGemNameByUuidString(const QString& uuidString) const
+ {
+ const auto iterator = m_uuidToNameMap.find(uuidString);
+ if (iterator != m_uuidToNameMap.end())
+ {
+ return AZ::Success(iterator.value());
+ }
+
+ return AZ::Failure();
+ }
+
QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex)
{
- return modelIndex.data(RoleDependingGems).toStringList();
+ QStringList result = modelIndex.data(RoleDependingGems).toStringList();
+ if (result.isEmpty())
+ {
+ return {};
+ }
+
+ for (QString& dependingGemString : result)
+ {
+ AZ::Outcome gemNameOutcome = FindGemNameByUuidString(dependingGemString);
+ if (gemNameOutcome.IsSuccess())
+ {
+ dependingGemString = gemNameOutcome.GetValue();
+ }
+ }
+
+ return result;
}
QStringList GemModel::GetConflictingGems(const QModelIndex& modelIndex)
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
index fba65e7009..76211b1f22 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
@@ -13,7 +13,8 @@
#pragma once
#if !defined(Q_MOC_RUN)
-#include "GemInfo.h"
+#include
+#include
#include
#include
#include
@@ -33,14 +34,18 @@ namespace O3DE::ProjectManager
void AddGem(const GemInfo& gemInfo);
void Clear();
+ AZ::Outcome FindGemNameByUuidString(const QString& uuidString) const;
+ QStringList GetDependingGems(const QModelIndex& modelIndex);
+
static QString GetName(const QModelIndex& modelIndex);
static QString GetCreator(const QModelIndex& modelIndex);
+ static QString GetUuidString(const QModelIndex& modelIndex);
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
+ static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
static QString GetSummary(const QModelIndex& modelIndex);
static bool IsAdded(const QModelIndex& modelIndex);
static QString GetDirectoryLink(const QModelIndex& modelIndex);
static QString GetDocLink(const QModelIndex& modelIndex);
- static QStringList GetDependingGems(const QModelIndex& modelIndex);
static QStringList GetConflictingGems(const QModelIndex& modelIndex);
static QString GetVersion(const QModelIndex& modelIndex);
static QString GetLastUpdated(const QModelIndex& modelIndex);
@@ -51,6 +56,7 @@ namespace O3DE::ProjectManager
enum UserRole
{
RoleName = Qt::UserRole,
+ RoleUuid,
RoleCreator,
RolePlatforms,
RoleSummary,
@@ -63,8 +69,10 @@ namespace O3DE::ProjectManager
RoleLastUpdated,
RoleBinarySize,
RoleFeatures,
+ RoleTypes
};
+ QHash m_uuidToNameMap;
QItemSelectionModel* m_selectionModel = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.cpp b/Code/Tools/ProjectManager/Source/LinkWidget.cpp
index fddc4cd8c9..a6308f6c62 100644
--- a/Code/Tools/ProjectManager/Source/LinkWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/LinkWidget.cpp
@@ -27,7 +27,12 @@ namespace O3DE::ProjectManager
void LinkLabel::mousePressEvent([[maybe_unused]] QMouseEvent* event)
{
- QDesktopServices::openUrl(m_url);
+ if (m_url.isValid())
+ {
+ QDesktopServices::openUrl(m_url);
+ }
+
+ emit clicked();
}
void LinkLabel::enterEvent([[maybe_unused]] QEvent* event)
diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.h b/Code/Tools/ProjectManager/Source/LinkWidget.h
index 7055dce2af..b3a34cd63a 100644
--- a/Code/Tools/ProjectManager/Source/LinkWidget.h
+++ b/Code/Tools/ProjectManager/Source/LinkWidget.h
@@ -26,10 +26,16 @@ namespace O3DE::ProjectManager
class LinkLabel
: public QLabel
{
+ Q_OBJECT // AUTOMOC
+
public:
- LinkLabel(const QString& text, const QUrl& url = {}, QWidget* parent = nullptr);
+ LinkLabel(const QString& text = {}, const QUrl& url = {}, QWidget* parent = nullptr);
void SetUrl(const QUrl& url);
+
+ signals:
+ void clicked();
+
private:
void mousePressEvent(QMouseEvent* event) override;
void enterEvent(QEvent* event) override;
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index e925c81032..2c2c143845 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -426,7 +426,7 @@ namespace O3DE::ProjectManager
{
// required
gemInfo.m_name = Py_To_String(data["Name"]);
- gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
+ gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
// optional
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
@@ -437,7 +437,8 @@ namespace O3DE::ProjectManager
{
for (auto dependency : data["Dependencies"])
{
- gemInfo.m_dependingGemUuids.push_back(Py_To_String(dependency["Uuid"]));
+ const AZ::Uuid uuid = Py_To_String(dependency["Uuid"]);
+ gemInfo.m_dependingGemUuids.push_back(uuid.ToString().c_str());
}
}
if (data.contains("Tags"))
diff --git a/Code/Tools/ProjectManager/project_manager.qrc b/Code/Tools/ProjectManager/project_manager.qrc
index 3c23bc24ff..f36633142f 100644
--- a/Code/Tools/ProjectManager/project_manager.qrc
+++ b/Code/Tools/ProjectManager/project_manager.qrc
@@ -9,6 +9,8 @@
Resources/iOS.svg
Resources/Linux.svg
Resources/macOS.svg
+ Resources/ArrowDownLine.svg
+ Resources/ArrowUpLine.svg
Resources/Backgrounds/FirstTimeBackgroundImage.jpg
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
index 3dc14814de..d2818f3653 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
@@ -41,18 +41,6 @@ namespace AZ
static AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler* g_fbxImporter = nullptr;
static AZStd::vector 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 +52,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());
@@ -125,7 +114,6 @@ namespace AZ
extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env)
{
AZ::Environment::Attach(static_cast(env));
- AZ::SceneAPI::FbxSceneBuilder::Initialize();
}
extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context)
{
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
index 155209f1b5..a43f1e16b8 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
@@ -10,12 +10,16 @@
*
*/
+#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
#include
#include
#include
-#include
namespace AZ
{
@@ -23,10 +27,25 @@ namespace AZ
{
namespace FbxSceneImporter
{
- const char* FbxImportRequestHandler::s_extension = ".fbx";
+ void SceneImporterSettings::Reflect(AZ::ReflectContext* context)
+ {
+ if (auto serializeContext = azrtti_cast(context); serializeContext)
+ {
+ serializeContext->Class()
+ ->Version(1)
+ ->Field("SupportedFileTypeExtensions", &SceneImporterSettings::m_supportedFileTypeExtensions);
+ }
+ }
void FbxImportRequestHandler::Activate()
{
+ auto settingsRegistry = AZ::SettingsRegistry::Get();
+
+ if (settingsRegistry)
+ {
+ settingsRegistry->GetObject(m_settings, "/O3DE/SceneAPI/AssetImporter");
+ }
+
BusConnect();
}
@@ -37,21 +56,29 @@ namespace AZ
void FbxImportRequestHandler::Reflect(ReflectContext* context)
{
+ SceneImporterSettings::Reflect(context);
+
SerializeContext* serializeContext = azrtti_cast(context);
if (serializeContext)
{
- serializeContext->Class()->Version(1);
+ serializeContext->Class()->Version(1)->Attribute(
+ AZ::Edit::Attributes::SystemComponentTags,
+ AZStd::vector({AssetBuilderSDK::ComponentTags::AssetBuilder}));
+
}
}
void FbxImportRequestHandler::GetSupportedFileExtensions(AZStd::unordered_set& 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
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h
index 8b33051f1e..12c7c6f877 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h
@@ -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 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
diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthModule.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthModule.cpp
index 9f027613b6..ccf71cb89e 100644
--- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthModule.cpp
+++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthModule.cpp
@@ -39,4 +39,4 @@ namespace AWSClientAuth
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
-AZ_DECLARE_MODULE_CLASS(AWSClientAuth_c74f2756f5874c0d8d29646dfc9cb0ad, AWSClientAuth::AWSClientAuthModule)
+AZ_DECLARE_MODULE_CLASS(Gem_AWSClientAuth, AWSClientAuth::AWSClientAuthModule)
diff --git a/Gems/AWSClientAuth/cdk/cognito/cognito_user_pool.py b/Gems/AWSClientAuth/cdk/cognito/cognito_user_pool.py
index a903217f40..f0a2acf208 100755
--- a/Gems/AWSClientAuth/cdk/cognito/cognito_user_pool.py
+++ b/Gems/AWSClientAuth/cdk/cognito/cognito_user_pool.py
@@ -76,7 +76,7 @@ class CognitoUserPool:
scope,
'CognitoUserPoolId',
description="Cognito User pool id",
- value=self._user_pool.attr_provider_name)
+ value=self._user_pool.ref)
core.CfnOutput(
scope,
diff --git a/Gems/AWSMetrics/Code/Source/AWSMetricsModule.cpp b/Gems/AWSMetrics/Code/Source/AWSMetricsModule.cpp
index 4967202483..f180e3e248 100644
--- a/Gems/AWSMetrics/Code/Source/AWSMetricsModule.cpp
+++ b/Gems/AWSMetrics/Code/Source/AWSMetricsModule.cpp
@@ -32,4 +32,4 @@ namespace AWSMetrics
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
-AZ_DECLARE_MODULE_CLASS(AWSMetrics_cc6fc7a18fc047039a369a26100fcbbe, AWSMetrics::AWSMetricsModule)
+AZ_DECLARE_MODULE_CLASS(Gem_AWSMetrics, AWSMetrics::AWSMetricsModule)
diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingBus.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingBus.h
index b8deb50cc5..9f6b6e629f 100644
--- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingBus.h
+++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingBus.h
@@ -13,8 +13,14 @@
#pragma once
#include
+#include
#include
+namespace AssetBuilderSDK
+{
+ struct JobProduct;
+}
+
namespace ImageProcessingAtom
{
class ImageProcessingRequests
@@ -35,4 +41,39 @@ namespace ImageProcessingAtom
virtual IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) = 0;
};
using ImageProcessingRequestBus = AZ::EBus;
+
+ class ImageBuilderRequests
+ : public AZ::EBusTraits
+ {
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // EBusTraits overrides
+ static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+ static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+ /////////////////////////////////////////////////////////////////////////
+
+ //! Create an image object
+ virtual IImageObjectPtr CreateImage(
+ AZ::u32 width,
+ AZ::u32 height,
+ AZ::u32 maxMipCount,
+ EPixelFormat pixelFormat) = 0;
+
+ //! Convert an image and save its products to the specified folder
+ virtual AZStd::vector ConvertImageObject(
+ IImageObjectPtr imageObject,
+ const AZStd::string& presetName,
+ const AZStd::string& platformName,
+ const AZStd::string& outputDir,
+ const AZ::Data::AssetId& sourceAssetId,
+ const AZStd::string& sourceAssetName) = 0;
+
+ //! Return whether the specified platform is supported by the image builder
+ virtual bool DoesSupportPlatform(const AZStd::string& platformId) = 0;
+
+ //! Return whether the specified preset requires an image to be square and a power of 2
+ virtual bool IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName) = 0;
+ };
+
+ using ImageBuilderRequestBus = AZ::EBus;
} // namespace ImageProcessingAtom
diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingEditorBus.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingEditorBus.h
index acd1d7a2da..bf5289bc45 100644
--- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingEditorBus.h
+++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/ImageProcessingEditorBus.h
@@ -13,8 +13,6 @@
#include
-class QString;
-
namespace ImageProcessingAtomEditor
{
class ImageProcessingEditorRequests
diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp
index 59c799a601..34d18a26eb 100644
--- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp
+++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp
@@ -88,11 +88,13 @@ namespace ImageProcessingAtom
m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler());
ImageProcessingRequestBus::Handler::BusConnect();
+ ImageBuilderRequestBus::Handler::BusConnect();
}
void BuilderPluginComponent::Deactivate()
{
ImageProcessingRequestBus::Handler::BusDisconnect();
+ ImageBuilderRequestBus::Handler::BusDisconnect();
m_imageBuilder.BusDisconnect();
BuilderSettingManager::DestroyInstance();
CPixelFormats::DestroyInstance();
@@ -146,6 +148,78 @@ namespace ImageProcessingAtom
return image;
}
+ IImageObjectPtr BuilderPluginComponent::CreateImage(
+ AZ::u32 width,
+ AZ::u32 height,
+ AZ::u32 maxMipCount,
+ EPixelFormat pixelFormat)
+ {
+ IImageObjectPtr image(IImageObject::CreateImage(width, height, maxMipCount, pixelFormat));
+ return image;
+ }
+
+ AZStd::vector BuilderPluginComponent::ConvertImageObject(
+ IImageObjectPtr imageObject,
+ const AZStd::string& presetName,
+ const AZStd::string& platformName,
+ const AZStd::string& outputDir,
+ const AZ::Data::AssetId& sourceAssetId,
+ const AZStd::string& sourceAssetName)
+ {
+ AZStd::vector outProducts;
+
+ AZStd::string_view presetFilePath;
+ const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &presetFilePath);
+ if (preset == nullptr)
+ {
+ AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
+ return outProducts;
+ }
+
+ AZStd::unique_ptr desc = AZStd::make_unique();
+ TextureSettings& textureSettings = desc->m_textureSetting;
+ textureSettings.m_preset = preset->m_uuid;
+ desc->m_inputImage = imageObject;
+ desc->m_presetSetting = *preset;
+ desc->m_isPreview = false;
+ desc->m_platform = platformName;
+ desc->m_filePath = presetFilePath;
+ desc->m_isStreaming = BuilderSettingManager::Instance()->GetBuilderSetting(platformName)->m_enableStreaming;
+ desc->m_imageName = sourceAssetName;
+ desc->m_outputFolder = outputDir;
+ desc->m_sourceAssetId = sourceAssetId;
+
+ // Create an image convert process
+ ImageConvertProcess process(AZStd::move(desc));
+ process.ProcessAll();
+ bool result = process.IsSucceed();
+ if (result)
+ {
+ process.GetAppendOutputProducts(outProducts);
+ }
+
+ return outProducts;
+ }
+
+ bool BuilderPluginComponent::DoesSupportPlatform(const AZStd::string& platformId)
+ {
+ return ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformId);
+ }
+
+ bool BuilderPluginComponent::IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName)
+ {
+ AZStd::string_view filePath;
+ const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &filePath);
+ if (preset == nullptr)
+ {
+ AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
+ return false;
+ }
+
+ const PixelFormatInfo* info = CPixelFormats::GetInstance().GetPixelFormatInfo(preset->m_pixelFormat);
+ return info->bSquarePow2;
+ }
+
void ImageBuilderWorker::ShutDown()
{
// it is important to note that this will be called on a different thread than your process job thread
diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h
index fd099eb08a..a88ad3f587 100644
--- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h
+++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.h
@@ -47,6 +47,7 @@ namespace ImageProcessingAtom
class BuilderPluginComponent
: public AZ::Component
, protected ImageProcessingRequestBus::Handler
+ , protected ImageBuilderRequestBus::Handler
{
public:
AZ_COMPONENT(BuilderPluginComponent, "{A227F803-D2E4-406E-93EC-121EF45A64A1}")
@@ -71,6 +72,24 @@ namespace ImageProcessingAtom
IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override;
////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ // ImageBuilderRequestBus interface implementation
+ IImageObjectPtr CreateImage(
+ AZ::u32 width,
+ AZ::u32 height,
+ AZ::u32 maxMipCount,
+ EPixelFormat pixelFormat) override;
+ AZStd::vector ConvertImageObject(
+ IImageObjectPtr imageObject,
+ const AZStd::string& presetName,
+ const AZStd::string& platformName,
+ const AZStd::string& outputDir,
+ const AZ::Data::AssetId& sourceAssetId,
+ const AZStd::string& sourceAssetName) override;
+ bool DoesSupportPlatform(const AZStd::string& platformId) override;
+ bool IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName) override;
+ ////////////////////////////////////////////////////////////////////////
+
private:
BuilderPluginComponent(const BuilderPluginComponent&) = delete;
diff --git a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt
index 7d82ca5869..a06aa79d24 100644
--- a/Gems/Atom/Asset/Shader/Code/CMakeLists.txt
+++ b/Gems/Atom/Asset/Shader/Code/CMakeLists.txt
@@ -98,7 +98,6 @@ ly_add_target(
Gem::Atom_RPI.Edit
RUNTIME_DEPENDENCIES
3rdParty::DirectXShaderCompilerDxc
- 3rdParty::DirectXShaderCompilerDxcAz
3rdParty::SPIRVCross
3rdParty::azslc
)
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
index fb4d370621..bc2e810f84 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
@@ -118,7 +118,7 @@ namespace AZ
// Register Shader Asset Builder
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder";
- shaderAssetBuilderDescriptor.m_version = 99; // ATOM-15276
+ shaderAssetBuilderDescriptor.m_version = 100; // ATOM-14298
// .shader file changes trigger rebuilds
shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid();
@@ -133,7 +133,7 @@ namespace AZ
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update
// ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder".
- shaderVariantAssetBuilderDescriptor.m_version = 20; // ATOM-15276
+ shaderVariantAssetBuilderDescriptor.m_version = 21; // ATOM-14298
shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid();
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
index e3bdb28046..012a229fe8 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
@@ -123,6 +123,12 @@ namespace AZ
m_windowHandle = m_nativeWindow->GetWindowHandle();
}
+ else
+ {
+ // Disable default scene creation for non-games projects
+ // This can be manually overridden via the DefaultWindowBus.
+ m_createDefaultScene = false;
+ }
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
TickBus::Handler::BusConnect();
@@ -351,6 +357,17 @@ namespace AZ
scene->AddRenderPipeline(brdfTexturePipeline);
}
+ // Send notification when the scene and its pipeline are ready.
+ // Use the first created pipeline's scene as our default scene for now to allow
+ // consumers waiting on scene availability to initialize.
+ if (!m_defaultSceneReady)
+ {
+ m_defaultScene = scene;
+ Render::Bootstrap::NotificationBus::Broadcast(
+ &Render::Bootstrap::NotificationBus::Handler::OnBootstrapSceneReady, m_defaultScene.get());
+ m_defaultSceneReady = true;
+ }
+
return true;
}
@@ -364,9 +381,6 @@ namespace AZ
{
m_renderPipelineId = pipeline->GetId();
}
-
- // Send notification when the scene and its pipeline are ready
- Render::Bootstrap::NotificationBus::Broadcast(&Render::Bootstrap::NotificationBus::Handler::OnBootstrapSceneReady, m_defaultScene.get());
}
void BootstrapSystemComponent::DestroyDefaultScene()
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
index 7323a54221..65390ff153 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
@@ -125,6 +125,7 @@ namespace AZ
Data::Instance m_brdfTexture;
bool m_createDefaultScene = true;
+ bool m_defaultSceneReady = false;
// Maps AZ scenes to RPI scene weak pointers to allow looking up a ScenePtr instead of a raw Scene*
AZStd::unordered_map> m_azSceneToAtomSceneMap;
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader
index 7964e3c84a..a0e9708468 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.shader
@@ -31,8 +31,7 @@
},
"CompilerHints" : {
- "DisableOptimizations" : true,
- "DxcGenerateDebugInfo" : true
+ "DisableOptimizations" : false
},
"ProgramSettings":
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/DetailMapsCommonFunctor.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/DetailMapsCommonFunctor.lua
index 15e4b4f416..e1a3dd6f29 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/DetailMapsCommonFunctor.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/DetailMapsCommonFunctor.lua
@@ -35,16 +35,16 @@ end
function Process(context)
local isFeatureEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableDetailLayer")
- local blendMaskTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.blendDetailMask")
+ local blendMaskTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.blendDetailMask")
local blendMaskTextureEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableDetailMaskTexture")
context:SetShaderOptionValue_bool("o_detail_blendMask_useTexture", isFeatureEnabled and blendMaskTextureEnabled and blendMaskTexture ~= nil)
local baseColorDetailEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableBaseColor")
- local baseColorDetailTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.baseColorDetailMap")
+ local baseColorDetailTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.baseColorDetailMap")
context:SetShaderOptionValue_bool("o_detail_baseColor_useTexture", isFeatureEnabled and baseColorDetailEnabled and baseColorDetailTexture ~= nil)
local normalDetailEnabled = context:GetMaterialPropertyValue_bool("detailLayerGroup.enableNormals")
- local normalDetailTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.normalDetailMap")
+ local normalDetailTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.normalDetailMap")
context:SetShaderOptionValue_bool("o_detail_normal_useTexture", isFeatureEnabled and normalDetailEnabled and normalDetailTexture ~= nil)
end
@@ -78,7 +78,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("detailUV.rotateDegrees", mainVisibility)
context:SetMaterialPropertyVisibility("detailUV.scale", mainVisibility)
- local blendMaskTexture = context:GetMaterialPropertyValue_image("detailLayerGroup.blendDetailMask")
+ local blendMaskTexture = context:GetMaterialPropertyValue_Image("detailLayerGroup.blendDetailMask")
if(nil == blendMaskTexture) then
context:SetMaterialPropertyVisibility("detailLayerGroup.enableDetailMaskTexture", MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility("detailLayerGroup.blendDetailMaskUv", MaterialPropertyVisibility_Hidden)
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_WrinkleMaps.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_WrinkleMaps.lua
index d77918f521..9e1bc3763a 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_WrinkleMaps.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin_WrinkleMaps.lua
@@ -65,8 +65,8 @@ function Process(context)
for i=1,MAX_WRINKLE_LAYER_COUNT do
if(i <= count) then
- isBaseColorTextureMissing = isBaseColorEnabled and nil == context:GetMaterialPropertyValue_image("wrinkleLayers.baseColorMap" .. i)
- isNormalTextureMissing = isNormalEnabled and nil == context:GetMaterialPropertyValue_image("wrinkleLayers.normalMap" .. i)
+ isBaseColorTextureMissing = isBaseColorEnabled and nil == context:GetMaterialPropertyValue_Image("wrinkleLayers.baseColorMap" .. i)
+ isNormalTextureMissing = isNormalEnabled and nil == context:GetMaterialPropertyValue_Image("wrinkleLayers.normalMap" .. i)
context:SetShaderOptionValue_bool("o_wrinkleLayers_baseColor_useTexture" .. i, not isBaseColorTextureMissing)
context:SetShaderOptionValue_bool("o_wrinkleLayers_normal_useTexture" .. i, not isNormalTextureMissing)
else
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
index e2119dcf12..a2854e8902 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
@@ -23,11 +23,6 @@
"displayName": "UVs",
"description": "Properties for configuring UV transforms for the entire material, including the blend masks."
},
- {
- "id": "subsurfaceScattering",
- "displayName": "Subsurface Scattering",
- "description": "Properties for configuring subsurface scattering effects."
- },
{
// Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader
"id": "irradiance",
@@ -204,7 +199,7 @@
"displayName": "Debug Draw Mode",
"description": "Enables various debug view features.",
"type": "Enum",
- "enumValues": [ "None", "BlendMaskValues", "DepthMaps" ],
+ "enumValues": [ "None", "BlendSource", "DepthMaps" ],
"defaultValue": "None",
"connection": {
"type": "ShaderOption",
@@ -300,6 +295,28 @@
}
],
"blend": [
+ {
+ "id": "enableLayer2",
+ "displayName": "Enable Layer 2",
+ "description": "Whether to enable layer 2.",
+ "type": "Bool",
+ "defaultValue": false,
+ "connection": {
+ "type": "ShaderOption",
+ "id": "o_layer2_enabled"
+ }
+ },
+ {
+ "id": "enableLayer3",
+ "displayName": "Enable Layer 3",
+ "description": "Whether to enable layer 3.",
+ "type": "Bool",
+ "defaultValue": false,
+ "connection": {
+ "type": "ShaderOption",
+ "id": "o_layer3_enabled"
+ }
+ },
{
"id": "blendSource",
"displayName": "Blend Source",
@@ -467,183 +484,6 @@
"step": 0.1
}
],
- "subsurfaceScattering": [
- {
- "id": "enableSubsurfaceScattering",
- "displayName": "Subsurface Scattering",
- "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility",
- "type": "Bool",
- "defaultValue": false,
- "connection": {
- "type": "ShaderOption",
- "id": "o_enableSubsurfaceScattering"
- }
- },
- {
- "id": "subsurfaceScatterFactor",
- "displayName": " Factor",
- "description": "Strength factor for scaling percentage of subsurface scattering effect applied",
- "type": "float",
- "defaultValue": 1.0,
- "min": 0.0,
- "max": 1.0,
- "connection": {
- "type": "ShaderInput",
- "id": "m_subsurfaceScatteringFactor"
- }
- },
- {
- "id": "influenceMap",
- "displayName": " Influence Map",
- "description": "Use texture map to control the strength of subsurface scattering",
- "type": "Image",
- "connection": {
- "type": "ShaderInput",
- "id": "m_subsurfaceScatteringInfluenceMap"
- }
- },
- {
- "id": "useInfluenceMap",
- "displayName": " Use Influence Map",
- "description": "Whether to use the texture map as influence mask.",
- "type": "Bool",
- "defaultValue": true
- },
- {
- "id": "influenceMapUv",
- "displayName": " UV",
- "description": "Influence map UV set",
- "type": "Enum",
- "enumIsUv": true,
- "defaultValue": "Tiled",
- "connection": {
- "type": "ShaderInput",
- "id": "m_subsurfaceScatteringInfluenceMapUvIndex"
- }
- },
- {
- "id": "scatterColor",
- "displayName": " Scatter color",
- "description": "Color of volume light traveled through",
- "type": "Color",
- "defaultValue": [ 1.0, 0.27, 0.13 ]
- },
- {
- "id": "scatterDistance",
- "displayName": " Scatter distance",
- "description": "How far light traveled inside the volume",
- "type": "float",
- "defaultValue": 8,
- "min": 0.0,
- "softMax": 20.0
- },
- {
- "id": "quality",
- "displayName": " Quality",
- "description": "How much percent of sample will be used for each pixel, more samples improve quality and reduce artifacts, especially when the scatter distance is relatively large, but slow down computation time, 1.0 = full set 200 samples per pixel",
- "type": "float",
- "defaultValue": 0.4,
- "min": 0.2,
- "max": 1.0,
- "connection": {
- "type": "ShaderInput",
- "id": "m_subsurfaceScatteringQuality"
- }
- },
- {
- "id": "transmissionMode",
- "displayName": "Transmission",
- "description": "Algorithm used for calculating transmission",
- "type": "Enum",
- "enumValues": [ "None", "ThickObject", "ThinObject" ],
- "defaultValue": "None",
- "connection": {
- "type": "ShaderOption",
- "id": "o_transmission_mode"
- }
- },
- {
- "id": "thickness",
- "displayName": " Thickness",
- "description": "Normalized global thickness, the maxima between this value (multiplied by thickness map if enabled) and thickness from shadow map (if applicable) will be used as final thickness of pixel",
- "type": "float",
- "defaultValue": 0.5,
- "min": 0.0,
- "max": 1.0
- },
- {
- "id": "thicknessMap",
- "displayName": " Thickness Map",
- "description": "Use a greyscale texture for per pixel thickness",
- "type": "Image",
- "connection": {
- "type": "ShaderInput",
- "id": "m_transmissionThicknessMap"
- }
- },
- {
- "id": "useThicknessMap",
- "displayName": " Use Thickness Map",
- "description": "Whether to use the thickness map",
- "type": "Bool",
- "defaultValue": true
- },
- {
- "id": "thicknessMapUv",
- "displayName": " UV",
- "description": "Thickness map UV set",
- "type": "Enum",
- "enumIsUv": true,
- "defaultValue": "Tiled",
- "connection": {
- "type": "ShaderInput",
- "id": "m_transmissionThicknessMapUvIndex"
- }
- },
- {
- "id": "transmissionTint",
- "displayName": " Transmission Tint",
- "description": "Color of the volume light travelling through",
- "type": "Color",
- "defaultValue": [ 1.0, 0.8, 0.6 ]
- },
- {
- "id": "transmissionPower",
- "displayName": " Power",
- "description": "How much transmitted light scatter radially ",
- "type": "float",
- "defaultValue": 6.0,
- "min": 0.0,
- "softMax": 20.0
- },
- {
- "id": "transmissionDistortion",
- "displayName": " Distortion",
- "description": "How much light direction distorted towards surface normal",
- "type": "float",
- "defaultValue": 0.1,
- "min": 0.0,
- "max": 1.0
- },
- {
- "id": "transmissionAttenuation",
- "displayName": " Attenuation",
- "description": "How fast transmitted light fade with thickness",
- "type": "float",
- "defaultValue": 4.0,
- "min": 0.0,
- "softMax": 20.0
- },
- {
- "id": "transmissionScale",
- "displayName": " Scale",
- "description": "Strength of transmission",
- "type": "float",
- "defaultValue": 3.0,
- "min": 0.0,
- "softMax": 20.0
- }
- ],
"irradiance": [
// Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader
{
@@ -2845,22 +2685,9 @@
}
},
{
- // Preprocess & build parameter set for subsurface scattering and translucency
- "type": "HandleSubsurfaceScatteringParameters",
+ "type": "Lua",
"args": {
- "mode": "subsurfaceScattering.transmissionMode",
- "scale" : "subsurfaceScattering.transmissionScale",
- "power" : "subsurfaceScattering.transmissionPower",
- "distortion" : "subsurfaceScattering.transmissionDistortion",
- "attenuation" : "subsurfaceScattering.transmissionAttenuation",
- "tintColor" : "subsurfaceScattering.transmissionTint",
- "thickness" : "subsurfaceScattering.thickness",
- "enabled": "subsurfaceScattering.enableSubsurfaceScattering",
- "scatterDistanceColor" : "subsurfaceScattering.scatterColor",
- "scatterDistanceIntensity" : "subsurfaceScattering.scatterDistance",
- "scatterDistanceShaderInput" : "m_scatterDistance",
- "parametersShaderInput" : "m_transmissionParams",
- "tintThickenssShaderInput" : "m_transmissionTintThickness"
+ "file": "StandardMultilayerPBR_LayerEnable.lua"
}
},
{
@@ -2875,12 +2702,6 @@
"file": "StandardMultilayerPBR_Parallax.lua"
}
},
- {
- "type": "Lua",
- "args": {
- "file": "StandardPBR_SubsurfaceState.lua"
- }
- },
//##############################################################################################
// Layer 1 Functors
//##############################################################################################
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli
index ba0eaf2ac1..d2314efefe 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Common.azsli
@@ -42,7 +42,7 @@ COMMON_SRG_INPUTS_PARALLAX(prefix)
ShaderResourceGroup MaterialSrg : SRG_PerMaterial
{
- Texture2D m_blendMaskTexture;
+ Texture2D m_blendMaskTexture;
uint m_blendMaskUvIndex;
// Auto-generate material SRG fields for common inputs for each layer
@@ -91,29 +91,14 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
MipFilter = Linear;
};
- // Parameters for subsurface scattering
- float m_subsurfaceScatteringFactor;
- float m_subsurfaceScatteringQuality;
- float3 m_scatterDistance;
- Texture2D m_subsurfaceScatteringInfluenceMap;
- uint m_subsurfaceScatteringInfluenceMapUvIndex;
-
- // Parameters for transmission
-
- // Elements of m_transmissionParams:
- // Thick object mode: (attenuation coefficient, power, distortion, scale)
- // Thin object mode: (float3 scatter distance, scale)
- float4 m_transmissionParams;
-
- // (float3 TintColor, thickness)
- float4 m_transmissionTintThickness;
- Texture2D m_transmissionThicknessMap;
- uint m_transmissionThicknessMapUvIndex;
}
// ------ Shader Options ----------------------------------------
-enum class DebugDrawMode { None, BlendMaskValues, DepthMaps };
+option bool o_layer2_enabled;
+option bool o_layer3_enabled;
+
+enum class DebugDrawMode { None, BlendSource, DepthMaps };
option DebugDrawMode o_debugDrawMode;
enum class BlendMaskSource { TextureMap, VertexColors, Fallback };
@@ -127,6 +112,10 @@ option bool o_blendMask_isBound;
// ------ Blend Utilities ----------------------------------------
+// This is mainly used to pass extra data to the GetDepth callback function during the parallax depth search.
+// But since we have it, we use it in some other functions as well rather than passing it around.
+static float3 s_blendMaskFromVertexStream;
+
//! Returns the BlendMaskSource that will actually be used when rendering (not necessarily the same BlendMaskSource specified by the user)
BlendMaskSource GetFinalBlendMaskSource()
{
@@ -151,40 +140,84 @@ BlendMaskSource GetFinalBlendMaskSource()
}
}
-//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
-float3 GetBlendMaskValues(float2 uv, float3 vertexBlendMask)
+//! Return the raw blend source values directly from the blend mask or vertex colors, depending on the available data and configuration.
+//! layer1 is an implicit base layer
+//! layer2 is weighted by r
+//! layer3 is weighted by g
+//! b is reserved for perhaps a dedicated puddle layer
+float3 GetBlendSourceValues(float2 uv)
{
- float3 blendMaskValues;
+ float3 blendSourceValues = float3(0,0,0);
- switch(GetFinalBlendMaskSource())
+ if(o_layer2_enabled || o_layer3_enabled)
{
- case BlendMaskSource::TextureMap:
- blendMaskValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb;
- break;
- case BlendMaskSource::VertexColors:
- blendMaskValues = vertexBlendMask;
- break;
- case BlendMaskSource::Fallback:
- blendMaskValues = float3(1,1,1);
- break;
+ switch(GetFinalBlendMaskSource())
+ {
+ case BlendMaskSource::TextureMap:
+ blendSourceValues = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, uv).rgb;
+ break;
+ case BlendMaskSource::VertexColors:
+ blendSourceValues = s_blendMaskFromVertexStream;
+ break;
+ }
+
+ if(!o_layer2_enabled)
+ {
+ blendSourceValues.r = 0.0;
+ }
+
+ if(!o_layer3_enabled)
+ {
+ blendSourceValues.g = 0.0;
+ }
}
- blendMaskValues = blendMaskValues / (blendMaskValues.r + blendMaskValues.g + blendMaskValues.b);
-
- return blendMaskValues;
+ return blendSourceValues;
}
-float BlendLayers(float layer1, float layer2, float layer3, float3 blendMaskValues)
+//! Return the final blend mask values to be used for rendering, based on the available data and configuration.
+//! @return The blend weights for each layer.
+//! Even though layer1 not explicitly specified in the blend source data, it is explicitly included with the returned values.
+//! layer1 = r
+//! layer2 = g
+//! layer3 = b
+float3 GetBlendWeights(float2 uv)
{
- return dot(float3(layer1, layer2, layer3), blendMaskValues);
+ float3 blendWeights;
+
+ if(o_layer2_enabled || o_layer3_enabled)
+ {
+ float3 blendSourceValues = GetBlendSourceValues(uv);
+
+ // Calculate blend weights such that multiplying and adding them with layer data is equivalent
+ // to lerping between each layer.
+ // final = lerp(final, layer1, blendWeights.r)
+ // final = lerp(final, layer2, blendWeights.g)
+ // final = lerp(final, layer3, blendWeights.b)
+
+ blendWeights.b = blendSourceValues.g;
+ blendWeights.g = (1.0 - blendSourceValues.g) * blendSourceValues.r;
+ blendWeights.r = (1.0 - blendSourceValues.g) * (1.0 - blendSourceValues.r);
+ }
+ else
+ {
+ blendWeights = float3(1,0,0);
+ }
+
+ return blendWeights;
}
-float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendMaskValues)
+
+float BlendLayers(float layer1, float layer2, float layer3, float3 blendWeights)
{
- return layer1 * blendMaskValues.r + layer2 * blendMaskValues.g + layer3 * blendMaskValues.b;
+ return dot(float3(layer1, layer2, layer3), blendWeights);
}
-float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendMaskValues)
+float2 BlendLayers(float2 layer1, float2 layer2, float2 layer3, float3 blendWeights)
{
- return layer1 * blendMaskValues.r + layer2 * blendMaskValues.g + layer3 * blendMaskValues.b;
+ return layer1 * blendWeights.r + layer2 * blendWeights.g + layer3 * blendWeights.b;
+}
+float3 BlendLayers(float3 layer1, float3 layer2, float3 layer3, float3 blendWeights)
+{
+ return layer1 * blendWeights.r + layer2 * blendWeights.g + layer3 * blendWeights.b;
}
// ------ Parallax Utilities ----------------------------------------
@@ -203,16 +236,6 @@ bool ShouldHandleParallaxInDepthShaders()
return ShouldHandleParallax() && o_parallax_enablePixelDepthOffset;
}
-// These static values are used to pass extra data to the GetDepth callback function during the parallax depth search.
-static float3 s_blendMaskFromVertexStream;
-
-//! Setup static variables that are needed by the GetDepth callback function
-//! @param vertexBlendMask the blend mask values from the vertex input stream.
-void GetDepth_Setup(float3 vertexBlendMask)
-{
- s_blendMaskFromVertexStream = vertexBlendMask;
-}
-
// Callback function for ParallaxMapping.azsli
DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
{
@@ -231,7 +254,7 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
layerDepthValues.r -= MaterialSrg::m_layer1_m_depthOffset;
}
- if(o_layer2_o_useDepthMap)
+ if(o_layer2_enabled && o_layer2_o_useDepthMap)
{
float2 layerUv = uv;
if(MaterialSrg::m_parallaxUvIndex == 0)
@@ -244,7 +267,7 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
layerDepthValues.g -= MaterialSrg::m_layer2_m_depthOffset;
}
- if(o_layer3_o_useDepthMap)
+ if(o_layer3_enabled && o_layer3_o_useDepthMap)
{
float2 layerUv = uv;
if(MaterialSrg::m_parallaxUvIndex == 0)
@@ -260,8 +283,8 @@ DepthResult GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
// Note, when the blend source is BlendMaskSource::VertexColors, parallax will not be able to blend correctly between layers. It will end up using the same blend mask values
// for every UV position when searching for the intersection. This leads to smearing artifacts at the transition point, but these won't be so noticeable as long as
// you have a small depth factor relative to the size of the blend transition.
- float3 blendMaskValues = GetBlendMaskValues(uv, s_blendMaskFromVertexStream);
+ float3 blendWeights = GetBlendWeights(uv);
- float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendMaskValues);
+ float depth = BlendLayers(layerDepthValues.r, layerDepthValues.g, layerDepthValues.b, blendWeights);
return DepthResultAbsolute(depth);
}
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl
index ae156d7313..178deca8a2 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_DepthPass_WithPS.azsl
@@ -108,7 +108,7 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
- GetDepth_Setup(IN.m_blendMask);
+ s_blendMaskFromVertexStream = IN.m_blendMask;
float depth;
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
index bc32aa1370..580e5206ab 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
@@ -55,7 +55,6 @@ DEFINE_LAYER_OPTIONS(o_layer1_)
DEFINE_LAYER_OPTIONS(o_layer2_)
DEFINE_LAYER_OPTIONS(o_layer3_)
-#include "MaterialInputs/SubsurfaceInput.azsli"
#include "MaterialInputs/TransmissionInput.azsli"
#include "StandardMultilayerPBR_Common.azsli"
@@ -127,6 +126,181 @@ VSOutput ForwardPassVS(VSInput IN)
return OUT;
}
+//! Collects all the raw Standard material inputs for a single layer. See ProcessStandardMaterialInputs().
+struct StandardMaterialInputs
+{
+ COMMON_SRG_INPUTS_BASE_COLOR()
+ COMMON_SRG_INPUTS_ROUGHNESS()
+ COMMON_SRG_INPUTS_METALLIC()
+ COMMON_SRG_INPUTS_SPECULAR_F0()
+ COMMON_SRG_INPUTS_NORMAL()
+ COMMON_SRG_INPUTS_CLEAR_COAT()
+ COMMON_SRG_INPUTS_OCCLUSION()
+ COMMON_SRG_INPUTS_EMISSIVE()
+ // Note parallax is omitted here because that requires special handling.
+
+ bool m_normal_useTexture;
+ bool m_baseColor_useTexture;
+ bool m_metallic_useTexture;
+ bool m_specularF0_useTexture;
+ bool m_roughness_useTexture;
+ bool m_emissiveEnabled;
+ bool m_emissive_useTexture;
+ bool m_diffuseOcclusion_useTexture;
+ bool m_specularOcclusion_useTexture;
+ bool m_clearCoatEnabled;
+ bool m_clearCoat_factor_useTexture;
+ bool m_clearCoat_roughness_useTexture;
+ bool m_clearCoat_normal_useTexture;
+
+ TextureBlendMode m_baseColorTextureBlendMode;
+
+ float2 m_vertexUv[UvSetCount];
+ float3x3 m_uvMatrix;
+ float m_normal;
+ float3 m_tangents[UvSetCount];
+ float3 m_bitangents[UvSetCount];
+
+ sampler m_sampler;
+
+ bool m_isFrontFace;
+};
+
+//! Holds the final processed material inputs, after all flags have been checked, textures have been sampled, factors have been applied, etc.
+//! This data is ready to be copied into a Surface and/or LightingData struct for the lighting system to consume.
+class ProcessedMaterialInputs
+{
+ float3 m_normalTS; //!< Normal in tangent-space
+ float3 m_baseColor;
+ float3 m_specularF0Factor;
+ float m_metallic;
+ float m_roughness;
+ float3 m_emissiveLighting;
+ float m_diffuseAmbientOcclusion;
+ float m_specularOcclusion;
+ ClearCoatSurfaceData m_clearCoat;
+
+ void InitializeToZero()
+ {
+ m_normalTS = float3(0,0,0);
+ m_baseColor = float3(0,0,0);
+ m_specularF0Factor = float3(0,0,0);
+ m_metallic = 0.0f;
+ m_roughness = 0.0f;
+ m_emissiveLighting = float3(0,0,0);
+ m_diffuseAmbientOcclusion = 0;
+ m_specularOcclusion = 0;
+ m_clearCoat.InitializeToZero();
+ }
+};
+
+//! Processes the set of Standard material inputs for a single layer.
+//! The FILL_STANDARD_MATERIAL_INPUTS() macro below can be used to fill the StandardMaterialInputs struct.
+ProcessedMaterialInputs ProcessStandardMaterialInputs(StandardMaterialInputs inputs)
+{
+ ProcessedMaterialInputs result;
+
+ float2 transformedUv[UvSetCount];
+ transformedUv[0] = mul(inputs.m_uvMatrix, float3(inputs.m_vertexUv[0], 1.0)).xy;
+ transformedUv[1] = inputs.m_vertexUv[1];
+
+ float3x3 normalUvMatrix = inputs.m_normalMapUvIndex == 0 ? inputs.m_uvMatrix : CreateIdentity3x3();
+ result.m_normalTS = GetNormalInputTS(inputs.m_normalMap, inputs.m_sampler, transformedUv[inputs.m_normalMapUvIndex], inputs.m_flipNormalX, inputs.m_flipNormalY, normalUvMatrix, inputs.m_normal_useTexture, inputs.m_normalFactor);
+
+ float3 sampledBaseColor = GetBaseColorInput(inputs.m_baseColorMap, inputs.m_sampler, transformedUv[inputs.m_baseColorMapUvIndex], inputs.m_baseColor.rgb, inputs.m_baseColor_useTexture);
+ result.m_baseColor = BlendBaseColor(sampledBaseColor, inputs.m_baseColor.rgb, inputs.m_baseColorFactor, inputs.m_baseColorTextureBlendMode, inputs.m_baseColor_useTexture);
+ result.m_specularF0Factor = GetSpecularInput(inputs.m_specularF0Map, inputs.m_sampler, transformedUv[inputs.m_specularF0MapUvIndex], inputs.m_specularF0Factor, inputs.m_specularF0_useTexture);
+ result.m_metallic = GetMetallicInput(inputs.m_metallicMap, inputs.m_sampler, transformedUv[inputs.m_metallicMapUvIndex], inputs.m_metallicFactor, inputs.m_metallic_useTexture);
+ result.m_roughness = GetRoughnessInput(inputs.m_roughnessMap, MaterialSrg::m_sampler, transformedUv[inputs.m_roughnessMapUvIndex], inputs.m_roughnessFactor, inputs.m_roughnessLowerBound, inputs.m_roughnessUpperBound, inputs.m_roughness_useTexture);
+
+ result.m_emissiveLighting = GetEmissiveInput(inputs.m_emissiveMap, inputs.m_sampler, transformedUv[inputs.m_emissiveMapUvIndex], inputs.m_emissiveIntensity, inputs.m_emissiveColor.rgb, inputs.m_emissiveEnabled, inputs.m_emissive_useTexture);
+ result.m_diffuseAmbientOcclusion = GetOcclusionInput(inputs.m_diffuseOcclusionMap, inputs.m_sampler, transformedUv[inputs.m_diffuseOcclusionMapUvIndex], inputs.m_diffuseOcclusionFactor, inputs.m_diffuseOcclusion_useTexture);
+ result.m_specularOcclusion = GetOcclusionInput(inputs.m_specularOcclusionMap, MaterialSrg::m_sampler, transformedUv[inputs.m_specularOcclusionMapUvIndex], inputs.m_specularOcclusionFactor, inputs.m_specularOcclusion_useTexture);
+
+ result.m_clearCoat.InitializeToZero();
+ if(inputs.m_clearCoatEnabled)
+ {
+ float3x3 clearCoatUvMatrix = inputs.m_clearCoatNormalMapUvIndex == 0 ? inputs.m_uvMatrix : CreateIdentity3x3();
+
+ GetClearCoatInputs(inputs.m_clearCoatInfluenceMap, transformedUv[inputs.m_clearCoatInfluenceMapUvIndex], inputs.m_clearCoatFactor, inputs.m_clearCoat_factor_useTexture,
+ inputs.m_clearCoatRoughnessMap, transformedUv[inputs.m_clearCoatRoughnessMapUvIndex], inputs.m_clearCoatRoughness, inputs.m_clearCoat_roughness_useTexture,
+ inputs.m_clearCoatNormalMap, transformedUv[inputs.m_clearCoatNormalMapUvIndex], inputs.m_normal, inputs.m_clearCoat_normal_useTexture, inputs.m_clearCoatNormalStrength,
+ clearCoatUvMatrix, inputs.m_tangents[inputs.m_clearCoatNormalMapUvIndex], inputs.m_bitangents[inputs.m_clearCoatNormalMapUvIndex],
+ inputs.m_sampler, inputs.m_isFrontFace,
+ result.m_clearCoat.factor, result.m_clearCoat.roughness, result.m_clearCoat.normal);
+ }
+
+ return result;
+}
+
+//! Fills a StandardMaterialInputs struct with data from the MaterialSrg, shader options, and local vertex data.
+#define FILL_STANDARD_MATERIAL_INPUTS(inputs, srgLayerPrefix, optionsLayerPrefix, blendWeight) \
+ inputs.m_sampler = MaterialSrg::m_sampler; \
+ inputs.m_vertexUv = IN.m_uv; \
+ inputs.m_uvMatrix = srgLayerPrefix##m_uvMatrix; \
+ inputs.m_normal = IN.m_normal; \
+ inputs.m_tangents = tangents; \
+ inputs.m_bitangents = bitangents; \
+ inputs.m_isFrontFace = isFrontFace; \
+ \
+ inputs.m_normalMapUvIndex = srgLayerPrefix##m_normalMapUvIndex; \
+ inputs.m_normalMap = srgLayerPrefix##m_normalMap; \
+ inputs.m_flipNormalX = srgLayerPrefix##m_flipNormalX; \
+ inputs.m_flipNormalY = srgLayerPrefix##m_flipNormalY; \
+ inputs.m_normal_useTexture = optionsLayerPrefix##o_normal_useTexture; \
+ inputs.m_normalFactor = srgLayerPrefix##m_normalFactor * blendWeight; \
+ inputs.m_baseColorMap = srgLayerPrefix##m_baseColorMap; \
+ inputs.m_baseColorMapUvIndex = srgLayerPrefix##m_baseColorMapUvIndex; \
+ inputs.m_baseColor = srgLayerPrefix##m_baseColor; \
+ inputs.m_baseColor_useTexture = optionsLayerPrefix##o_baseColor_useTexture; \
+ inputs.m_baseColorFactor = srgLayerPrefix##m_baseColorFactor; \
+ inputs.m_baseColorTextureBlendMode = optionsLayerPrefix##o_baseColorTextureBlendMode; \
+ inputs.m_metallicMap = srgLayerPrefix##m_metallicMap; \
+ inputs.m_metallicMapUvIndex = srgLayerPrefix##m_metallicMapUvIndex; \
+ inputs.m_metallicFactor = srgLayerPrefix##m_metallicFactor; \
+ inputs.m_metallic_useTexture = optionsLayerPrefix##o_metallic_useTexture; \
+ inputs.m_specularF0Map = srgLayerPrefix##m_specularF0Map; \
+ inputs.m_specularF0MapUvIndex = srgLayerPrefix##m_specularF0MapUvIndex; \
+ inputs.m_specularF0Factor = srgLayerPrefix##m_specularF0Factor; \
+ inputs.m_specularF0_useTexture = optionsLayerPrefix##o_specularF0_useTexture; \
+ inputs.m_roughnessMap = srgLayerPrefix##m_roughnessMap; \
+ inputs.m_roughnessMapUvIndex = srgLayerPrefix##m_roughnessMapUvIndex; \
+ inputs.m_roughnessFactor = srgLayerPrefix##m_roughnessFactor; \
+ inputs.m_roughnessLowerBound = srgLayerPrefix##m_roughnessLowerBound; \
+ inputs.m_roughnessUpperBound = srgLayerPrefix##m_roughnessUpperBound; \
+ inputs.m_roughness_useTexture = optionsLayerPrefix##o_roughness_useTexture; \
+ \
+ inputs.m_emissiveMap = srgLayerPrefix##m_emissiveMap; \
+ inputs.m_emissiveMapUvIndex = srgLayerPrefix##m_emissiveMapUvIndex; \
+ inputs.m_emissiveIntensity = srgLayerPrefix##m_emissiveIntensity; \
+ inputs.m_emissiveColor = srgLayerPrefix##m_emissiveColor; \
+ inputs.m_emissiveEnabled = optionsLayerPrefix##o_emissiveEnabled; \
+ inputs.m_emissive_useTexture = optionsLayerPrefix##o_emissive_useTexture; \
+ \
+ inputs.m_diffuseOcclusionMap = srgLayerPrefix##m_diffuseOcclusionMap; \
+ inputs.m_diffuseOcclusionMapUvIndex = srgLayerPrefix##m_diffuseOcclusionMapUvIndex; \
+ inputs.m_diffuseOcclusionFactor = srgLayerPrefix##m_diffuseOcclusionFactor; \
+ inputs.m_diffuseOcclusion_useTexture = optionsLayerPrefix##o_diffuseOcclusion_useTexture; \
+ \
+ inputs.m_specularOcclusionMap = srgLayerPrefix##m_specularOcclusionMap; \
+ inputs.m_specularOcclusionMapUvIndex = srgLayerPrefix##m_specularOcclusionMapUvIndex; \
+ inputs.m_specularOcclusionFactor = srgLayerPrefix##m_specularOcclusionFactor; \
+ inputs.m_specularOcclusion_useTexture = optionsLayerPrefix##o_specularOcclusion_useTexture; \
+ \
+ inputs.m_clearCoatEnabled = o_clearCoat_feature_enabled && optionsLayerPrefix##o_clearCoat_enabled; \
+ inputs.m_clearCoatInfluenceMap = srgLayerPrefix##m_clearCoatInfluenceMap; \
+ inputs.m_clearCoatInfluenceMapUvIndex = srgLayerPrefix##m_clearCoatInfluenceMapUvIndex; \
+ inputs.m_clearCoatFactor = srgLayerPrefix##m_clearCoatFactor; \
+ inputs.m_clearCoat_factor_useTexture = optionsLayerPrefix##o_clearCoat_factor_useTexture; \
+ inputs.m_clearCoatRoughnessMap = srgLayerPrefix##m_clearCoatRoughnessMap; \
+ inputs.m_clearCoatRoughnessMapUvIndex = srgLayerPrefix##m_clearCoatRoughnessMapUvIndex; \
+ inputs.m_clearCoatRoughness = srgLayerPrefix##m_clearCoatRoughness; \
+ inputs.m_clearCoat_roughness_useTexture = optionsLayerPrefix##o_clearCoat_roughness_useTexture; \
+ inputs.m_clearCoatNormalMap = srgLayerPrefix##m_clearCoatNormalMap; \
+ inputs.m_clearCoatNormalMapUvIndex = srgLayerPrefix##m_clearCoatNormalMapUvIndex; \
+ inputs.m_clearCoat_normal_useTexture = optionsLayerPrefix##o_clearCoat_normal_useTexture; \
+ inputs.m_clearCoatNormalStrength = srgLayerPrefix##m_clearCoatNormalStrength;
+
// ---------- Pixel Shader ----------
@@ -134,6 +308,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
{
depthNDC = IN.m_position.z;
+ s_blendMaskFromVertexStream = IN.m_blendMask;
+
// ------- Tangents & Bitangets -------
// We support two UV streams, but only a single stream of tangent/bitangent. So for UV[1+] we generated the tangent/bitangent in screen-space.
@@ -156,15 +332,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// ------- Debug Modes -------
- if(o_debugDrawMode == DebugDrawMode::BlendMaskValues)
+ if(o_debugDrawMode == DebugDrawMode::BlendSource)
{
- float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
- return DebugOutput(blendMaskValues);
+ float3 blendSource = GetBlendSourceValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
+ return DebugOutput(blendSource);
}
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
{
- GetDepth_Setup(IN.m_blendMask);
float depth = GetNormalizedDepth(-MaterialSrg::m_displacementMax, -MaterialSrg::m_displacementMin, IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
return DebugOutput(float3(depth,depth,depth));
}
@@ -173,11 +348,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
bool displacementIsClipped = false;
- // Parallax mapping's non uniform uv transformations break screen space subsurface scattering, disable it when subsurface scatteirng is enabled
if(ShouldHandleParallax())
{
- GetDepth_Setup(IN.m_blendMask);
-
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
@@ -198,108 +370,86 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
}
}
- Surface surface;
- surface.position = IN.m_worldPosition;
-
- // ------- Setup the per-layer UV transforms -------
-
- float2 uvLayer1[UvSetCount];
- float2 uvLayer2[UvSetCount];
- float2 uvLayer3[UvSetCount];
-
- // Only UV0 will be applied transforms from each layer.
- uvLayer1[0] = mul(MaterialSrg::m_layer1_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
- uvLayer2[0] = mul(MaterialSrg::m_layer2_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
- uvLayer3[0] = mul(MaterialSrg::m_layer3_m_uvMatrix, float3(IN.m_uv[0], 1.0)).xy;
- uvLayer1[1] = IN.m_uv[1];
- uvLayer2[1] = IN.m_uv[1];
- uvLayer3[1] = IN.m_uv[1];
-
// ------- Calculate Layer Blend Mask Values -------
// Now that any parallax has been calculated, we calculate the blend factors for any layers that are impacted by the parallax.
- float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
+ float3 blendWeights = GetBlendWeights(IN.m_uv[MaterialSrg::m_blendMaskUvIndex]);
- // ------- Normal -------
+ // ------- Layer 1 (base layer) -----------
+
+ ProcessedMaterialInputs lightingInputLayer1;
+ {
+ StandardMaterialInputs inputs;
+ FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer1_, o_layer1_, blendWeights.r)
+ lightingInputLayer1 = ProcessStandardMaterialInputs(inputs);
+ }
- float3 layer1_normalFactor = MaterialSrg::m_layer1_m_normalFactor * blendMaskValues.r;
- float3 layer2_normalFactor = MaterialSrg::m_layer2_m_normalFactor * blendMaskValues.g;
- float3 layer3_normalFactor = MaterialSrg::m_layer3_m_normalFactor * blendMaskValues.b;
- float3x3 layer1_uvMatrix = MaterialSrg::m_layer1_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer1_m_uvMatrix : CreateIdentity3x3();
- float3x3 layer2_uvMatrix = MaterialSrg::m_layer2_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer2_m_uvMatrix : CreateIdentity3x3();
- float3x3 layer3_uvMatrix = MaterialSrg::m_layer3_m_normalMapUvIndex == 0 ? MaterialSrg::m_layer3_m_uvMatrix : CreateIdentity3x3();
- float3 layer1_normalTS = GetNormalInputTS(MaterialSrg::m_layer1_m_normalMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_normalMapUvIndex], MaterialSrg::m_layer1_m_flipNormalX, MaterialSrg::m_layer1_m_flipNormalY, layer1_uvMatrix, o_layer1_o_normal_useTexture, layer1_normalFactor);
- float3 layer2_normalTS = GetNormalInputTS(MaterialSrg::m_layer2_m_normalMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_normalMapUvIndex], MaterialSrg::m_layer2_m_flipNormalX, MaterialSrg::m_layer2_m_flipNormalY, layer2_uvMatrix, o_layer2_o_normal_useTexture, layer2_normalFactor);
- float3 layer3_normalTS = GetNormalInputTS(MaterialSrg::m_layer3_m_normalMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_normalMapUvIndex], MaterialSrg::m_layer3_m_flipNormalX, MaterialSrg::m_layer3_m_flipNormalY, layer3_uvMatrix, o_layer3_o_normal_useTexture, layer3_normalFactor);
+ // ----------- Layer 2 -----------
+
+ ProcessedMaterialInputs lightingInputLayer2;
+ if(o_layer2_enabled)
+ {
+ StandardMaterialInputs inputs;
+ FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer2_, o_layer2_, blendWeights.g)
+ lightingInputLayer2 = ProcessStandardMaterialInputs(inputs);
+ }
+ else
+ {
+ lightingInputLayer2.InitializeToZero();
+ }
- float3 normalTS = ReorientTangentSpaceNormal(layer1_normalTS, layer2_normalTS);
- normalTS = ReorientTangentSpaceNormal(normalTS, layer3_normalTS);
+ // ----------- Layer 3 -----------
+
+ ProcessedMaterialInputs lightingInputLayer3;
+ if(o_layer3_enabled)
+ {
+ StandardMaterialInputs inputs;
+ FILL_STANDARD_MATERIAL_INPUTS(inputs, MaterialSrg::m_layer3_, o_layer3_, blendWeights.b)
+ lightingInputLayer3 = ProcessStandardMaterialInputs(inputs);
+ }
+ else
+ {
+ lightingInputLayer3.InitializeToZero();
+ }
+
+ // ------- Combine all layers ---------
+
+ Surface surface;
+ surface.position = IN.m_worldPosition;
+ surface.transmission.InitializeToZero();
+
+ // ------- Combine Normals ---------
+
+ float3 normalTS = lightingInputLayer1.m_normalTS;
+ if(o_layer2_enabled)
+ {
+ normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer2.m_normalTS);
+ }
+ if(o_layer3_enabled)
+ {
+ normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS);
+ }
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
-
- // ------- Base Color -------
-
- float2 layer1_baseColorUv = uvLayer1[MaterialSrg::m_layer1_m_baseColorMapUvIndex];
- float2 layer2_baseColorUv = uvLayer2[MaterialSrg::m_layer2_m_baseColorMapUvIndex];
- float2 layer3_baseColorUv = uvLayer3[MaterialSrg::m_layer3_m_baseColorMapUvIndex];
+
+ // ------- Combine Albedo, roughness, specular, roughness ---------
- float3 layer1_sampledColor = GetBaseColorInput(MaterialSrg::m_layer1_m_baseColorMap, MaterialSrg::m_sampler, layer1_baseColorUv, MaterialSrg::m_layer1_m_baseColor.rgb, o_layer1_o_baseColor_useTexture);
- float3 layer2_sampledColor = GetBaseColorInput(MaterialSrg::m_layer2_m_baseColorMap, MaterialSrg::m_sampler, layer2_baseColorUv, MaterialSrg::m_layer2_m_baseColor.rgb, o_layer2_o_baseColor_useTexture);
- float3 layer3_sampledColor = GetBaseColorInput(MaterialSrg::m_layer3_m_baseColorMap, MaterialSrg::m_sampler, layer3_baseColorUv, MaterialSrg::m_layer3_m_baseColor.rgb, o_layer3_o_baseColor_useTexture);
- float3 layer1_baseColor = BlendBaseColor(layer1_sampledColor, MaterialSrg::m_layer1_m_baseColor.rgb, MaterialSrg::m_layer1_m_baseColorFactor, o_layer1_o_baseColorTextureBlendMode, o_layer1_o_baseColor_useTexture);
- float3 layer2_baseColor = BlendBaseColor(layer2_sampledColor, MaterialSrg::m_layer2_m_baseColor.rgb, MaterialSrg::m_layer2_m_baseColorFactor, o_layer2_o_baseColorTextureBlendMode, o_layer2_o_baseColor_useTexture);
- float3 layer3_baseColor = BlendBaseColor(layer3_sampledColor, MaterialSrg::m_layer3_m_baseColor.rgb, MaterialSrg::m_layer3_m_baseColorFactor, o_layer3_o_baseColorTextureBlendMode, o_layer3_o_baseColor_useTexture);
- float3 baseColor = BlendLayers(layer1_baseColor, layer2_baseColor, layer3_baseColor, blendMaskValues);
+ float3 baseColor = BlendLayers(lightingInputLayer1.m_baseColor, lightingInputLayer2.m_baseColor, lightingInputLayer3.m_baseColor, blendWeights);
+ float3 specularF0Factor = BlendLayers(lightingInputLayer1.m_specularF0Factor, lightingInputLayer2.m_specularF0Factor, lightingInputLayer3.m_specularF0Factor, blendWeights);
+ float3 metallic = BlendLayers(lightingInputLayer1.m_metallic, lightingInputLayer2.m_metallic, lightingInputLayer3.m_metallic, blendWeights);
if(o_parallax_highlightClipping && displacementIsClipped)
{
ApplyParallaxClippingHighlight(baseColor);
}
- // ------- Metallic -------
-
- float metallic = 0;
- if(!o_enableSubsurfaceScattering) // If subsurface scattering is enabled skip texture lookup for metallic, as this quantity won't be used anyway
- {
- float layer1_metallic = GetMetallicInput(MaterialSrg::m_layer1_m_metallicMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_metallicMapUvIndex], MaterialSrg::m_layer1_m_metallicFactor, o_layer1_o_metallic_useTexture);
- float layer2_metallic = GetMetallicInput(MaterialSrg::m_layer2_m_metallicMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_metallicMapUvIndex], MaterialSrg::m_layer2_m_metallicFactor, o_layer2_o_metallic_useTexture);
- float layer3_metallic = GetMetallicInput(MaterialSrg::m_layer3_m_metallicMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_metallicMapUvIndex], MaterialSrg::m_layer3_m_metallicFactor, o_layer3_o_metallic_useTexture);
- metallic = BlendLayers(layer1_metallic, layer2_metallic, layer3_metallic, blendMaskValues);
- }
-
- // ------- Specular -------
-
- float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
- float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
- float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
- float specularF0Factor = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
-
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
- // ------- Roughness -------
-
- float layer1_roughness = GetRoughnessInput(MaterialSrg::m_layer1_m_roughnessMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_roughnessMapUvIndex], MaterialSrg::m_layer1_m_roughnessFactor, MaterialSrg::m_layer1_m_roughnessLowerBound, MaterialSrg::m_layer1_m_roughnessUpperBound, o_layer1_o_roughness_useTexture);
- float layer2_roughness = GetRoughnessInput(MaterialSrg::m_layer2_m_roughnessMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_roughnessMapUvIndex], MaterialSrg::m_layer2_m_roughnessFactor, MaterialSrg::m_layer2_m_roughnessLowerBound, MaterialSrg::m_layer2_m_roughnessUpperBound, o_layer2_o_roughness_useTexture);
- float layer3_roughness = GetRoughnessInput(MaterialSrg::m_layer3_m_roughnessMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_roughnessMapUvIndex], MaterialSrg::m_layer3_m_roughnessFactor, MaterialSrg::m_layer3_m_roughnessLowerBound, MaterialSrg::m_layer3_m_roughnessUpperBound, o_layer3_o_roughness_useTexture);
- surface.roughnessLinear = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
-
+ surface.roughnessLinear = BlendLayers(lightingInputLayer1.m_roughness, lightingInputLayer2.m_roughness, lightingInputLayer3.m_roughness, blendWeights);
surface.CalculateRoughnessA();
-
- // ------- Subsurface -------
-
- float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
- float surfaceScatteringFactor = GetSubsurfaceInput(MaterialSrg::m_subsurfaceScatteringInfluenceMap, MaterialSrg::m_sampler, subsurfaceUv, MaterialSrg::m_subsurfaceScatteringFactor);
-
- // ------- Transmission -------
-
- float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
- float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
- surface.transmission.tint = transmissionTintThickness.rgb;
- surface.transmission.thickness = transmissionTintThickness.w;
- surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
- // ------- Lighting Data -------
-
+ // ------- Init and Combine Lighting Data -------
+
LightingData lightingData;
// Light iterator
@@ -308,88 +458,22 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// Directional light shadow coordinates
lightingData.shadowCoords = IN.m_shadowCoords;
-
- // ------- Emissive -------
- float3 layer1_emissive = GetEmissiveInput(MaterialSrg::m_layer1_m_emissiveMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_emissiveMapUvIndex], MaterialSrg::m_layer1_m_emissiveIntensity, MaterialSrg::m_layer1_m_emissiveColor.rgb, o_layer1_o_emissiveEnabled, o_layer1_o_emissive_useTexture);
- float3 layer2_emissive = GetEmissiveInput(MaterialSrg::m_layer2_m_emissiveMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_emissiveMapUvIndex], MaterialSrg::m_layer2_m_emissiveIntensity, MaterialSrg::m_layer2_m_emissiveColor.rgb, o_layer2_o_emissiveEnabled, o_layer2_o_emissive_useTexture);
- float3 layer3_emissive = GetEmissiveInput(MaterialSrg::m_layer3_m_emissiveMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_emissiveMapUvIndex], MaterialSrg::m_layer3_m_emissiveIntensity, MaterialSrg::m_layer3_m_emissiveColor.rgb, o_layer3_o_emissiveEnabled, o_layer3_o_emissive_useTexture);
- lightingData.emissiveLighting = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
+ lightingData.emissiveLighting = BlendLayers(lightingInputLayer1.m_emissiveLighting, lightingInputLayer2.m_emissiveLighting, lightingInputLayer3.m_emissiveLighting, blendWeights);
+ lightingData.specularOcclusion = BlendLayers(lightingInputLayer1.m_specularOcclusion, lightingInputLayer2.m_specularOcclusion, lightingInputLayer3.m_specularOcclusion, blendWeights);
+ lightingData.diffuseAmbientOcclusion = BlendLayers(lightingInputLayer1.m_diffuseAmbientOcclusion, lightingInputLayer2.m_diffuseAmbientOcclusion, lightingInputLayer3.m_diffuseAmbientOcclusion, blendWeights);
- // ------- Occlusion -------
-
- float layer1_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer1_m_diffuseOcclusionFactor, o_layer1_o_diffuseOcclusion_useTexture);
- float layer2_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer2_m_diffuseOcclusionFactor, o_layer2_o_diffuseOcclusion_useTexture);
- float layer3_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer3_m_diffuseOcclusionFactor, o_layer3_o_diffuseOcclusion_useTexture);
- lightingData.diffuseAmbientOcclusion = BlendLayers(layer1_diffuseAmbientOcclusion, layer2_diffuseAmbientOcclusion, layer3_diffuseAmbientOcclusion, blendMaskValues);
+ lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
- float layer1_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer1_m_specularOcclusionFactor, o_layer1_o_specularOcclusion_useTexture);
- float layer2_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer2_m_specularOcclusionFactor, o_layer2_o_specularOcclusion_useTexture);
- float layer3_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer3_m_specularOcclusionFactor, o_layer3_o_specularOcclusion_useTexture);
- lightingData.specularOcclusion = BlendLayers(layer1_specularOcclusion, layer2_specularOcclusion, layer3_specularOcclusion, blendMaskValues);
-
- // ------- Clearcoat -------
+ // ------- Combine Clearcoat -------
if(o_clearCoat_feature_enabled)
{
- // --- Layer 1 ---
-
- float layer1_clearCoatFactor = 0.0f;
- float layer1_clearCoatRoughness = 0.0f;
- float3 layer1_clearCoatNormal = float3(0.0, 0.0, 0.0);
- if(o_layer1_o_clearCoat_enabled)
- {
- float3x3 layer1_uvMatrix = MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer1_m_uvMatrix : CreateIdentity3x3();
-
- GetClearCoatInputs(MaterialSrg::m_layer1_m_clearCoatInfluenceMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer1_m_clearCoatFactor, o_layer1_o_clearCoat_factor_useTexture,
- MaterialSrg::m_layer1_m_clearCoatRoughnessMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer1_m_clearCoatRoughness, o_layer1_o_clearCoat_roughness_useTexture,
- MaterialSrg::m_layer1_m_clearCoatNormalMap, uvLayer1[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer1_o_clearCoat_normal_useTexture, MaterialSrg::m_layer1_m_clearCoatNormalStrength,
- layer1_uvMatrix, tangents[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex],
- MaterialSrg::m_sampler, isFrontFace,
- layer1_clearCoatFactor, layer1_clearCoatRoughness, layer1_clearCoatNormal);
- }
-
- // --- Layer 2 ---
-
- float layer2_clearCoatFactor = 0.0f;
- float layer2_clearCoatRoughness = 0.0f;
- float3 layer2_clearCoatNormal = float3(0.0, 0.0, 0.0);
- if(o_layer2_o_clearCoat_enabled)
- {
- float3x3 layer2_uvMatrix = MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer2_m_uvMatrix : CreateIdentity3x3();
-
- GetClearCoatInputs(MaterialSrg::m_layer2_m_clearCoatInfluenceMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer2_m_clearCoatFactor, o_layer2_o_clearCoat_factor_useTexture,
- MaterialSrg::m_layer2_m_clearCoatRoughnessMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer2_m_clearCoatRoughness, o_layer2_o_clearCoat_roughness_useTexture,
- MaterialSrg::m_layer2_m_clearCoatNormalMap, uvLayer2[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer2_o_clearCoat_normal_useTexture, MaterialSrg::m_layer2_m_clearCoatNormalStrength,
- layer2_uvMatrix, tangents[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex],
- MaterialSrg::m_sampler, isFrontFace,
- layer2_clearCoatFactor, layer2_clearCoatRoughness, layer2_clearCoatNormal);
- }
-
- // --- Layer 3 ---
-
- float layer3_clearCoatFactor = 0.0f;
- float layer3_clearCoatRoughness = 0.0f;
- float3 layer3_clearCoatNormal = float3(0.0, 0.0, 0.0);
- if(o_layer3_o_clearCoat_enabled)
- {
- float3x3 layer3_uvMatrix = MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_layer3_m_uvMatrix : CreateIdentity3x3();
-
- GetClearCoatInputs(MaterialSrg::m_layer3_m_clearCoatInfluenceMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_layer3_m_clearCoatFactor, o_layer3_o_clearCoat_factor_useTexture,
- MaterialSrg::m_layer3_m_clearCoatRoughnessMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_layer3_m_clearCoatRoughness, o_layer3_o_clearCoat_roughness_useTexture,
- MaterialSrg::m_layer3_m_clearCoatNormalMap, uvLayer3[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex], IN.m_normal, o_layer3_o_clearCoat_normal_useTexture, MaterialSrg::m_layer3_m_clearCoatNormalStrength,
- layer3_uvMatrix, tangents[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex],
- MaterialSrg::m_sampler, isFrontFace,
- layer3_clearCoatFactor, layer3_clearCoatRoughness, layer3_clearCoatNormal);
- }
-
- // --- Blend Layers ---
-
- surface.clearCoat.factor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
- surface.clearCoat.roughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
+ surface.clearCoat.factor = BlendLayers(lightingInputLayer1.m_clearCoat.factor, lightingInputLayer2.m_clearCoat.factor, lightingInputLayer3.m_clearCoat.factor, blendWeights);
+ surface.clearCoat.roughness = BlendLayers(lightingInputLayer1.m_clearCoat.roughness, lightingInputLayer2.m_clearCoat.roughness, lightingInputLayer3.m_clearCoat.roughness, blendWeights);
// [GFX TODO][ATOM-14592] This is not the right way to blend the normals. We need to use ReorientTangentSpaceNormal(), and that requires GetClearCoatInputs() to return the normal in TS instead of WS.
- surface.clearCoat.normal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
+ surface.clearCoat.normal = BlendLayers(lightingInputLayer1.m_clearCoat.normal, lightingInputLayer2.m_clearCoat.normal, lightingInputLayer3.m_clearCoat.normal, blendWeights);
surface.clearCoat.normal = normalize(surface.clearCoat.normal);
// manipulate base layer f0 if clear coat is enabled
@@ -409,11 +493,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
-
- // ------- Multiscatter -------
-
- lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
-
+
// ------- Lighting Calculation -------
// Apply Decals
@@ -426,17 +506,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
ApplyIBL(surface, lightingData);
// Finalize Lighting
- lightingData.FinalizeLighting(surface.transmission.tint);
+ lightingData.FinalizeLighting(0);
const float alpha = 1.0;
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
- // Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961
- uint factorAndQuality = dot(round(float2(saturate(surfaceScatteringFactor), MaterialSrg::m_subsurfaceScatteringQuality) * 255), float2(256, 1));
- lightingOutput.m_diffuseColor.w = factorAndQuality * (o_enableSubsurfaceScattering ? 1.0 : -1.0);
-
+ lightingOutput.m_diffuseColor.w = -1; // Disable subsurface scattering
return lightingOutput;
}
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_LayerEnable.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_LayerEnable.lua
new file mode 100644
index 0000000000..f60aac6149
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_LayerEnable.lua
@@ -0,0 +1,49 @@
+--------------------------------------------------------------------------------------
+--
+-- 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.
+--
+--
+----------------------------------------------------------------------------------------------------
+
+-- This functor hides the properties for disabled material layers.
+
+function GetMaterialPropertyDependencies()
+ return {
+ "blend.enableLayer2",
+ "blend.enableLayer3"
+ }
+end
+
+function SetLayerVisibility(context, layerNamePrefix, isVisible)
+
+ local visibility = MaterialPropertyGroupVisibility_Enabled
+ if(not isVisible) then
+ visibility = MaterialPropertyGroupVisibility_Hidden
+ end
+
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "baseColor", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "metallic", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "roughness", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "specularF0", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "normal", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "clearCoat", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "occlusion", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "emissive", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "parallax", visibility)
+ context:SetMaterialPropertyGroupVisibility(layerNamePrefix .. "uv", visibility)
+end
+
+function ProcessEditor(context)
+ local enableLayer2 = context:GetMaterialPropertyValue_bool("blend.enableLayer2")
+ local enableLayer3 = context:GetMaterialPropertyValue_bool("blend.enableLayer3")
+
+ SetLayerVisibility(context, "layer2_", context:GetMaterialPropertyValue_bool("blend.enableLayer2"))
+ SetLayerVisibility(context, "layer3_", context:GetMaterialPropertyValue_bool("blend.enableLayer3"))
+end
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua
index 119dfed436..bd56292229 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua
@@ -24,7 +24,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("parallax.enable")
- local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
context:SetShaderOptionValue_bool("o_useDepthMap", enable and textureMap ~= nil)
end
@@ -37,7 +37,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Hidden)
end
- local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
local visibility = MaterialPropertyVisibility_Enabled
if(not enable or textureMap == nil) then
visibility = MaterialPropertyVisibility_Hidden
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl
index c76dd15975..02ccd78735 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl
@@ -107,7 +107,7 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, float3(0, 0, 0) };
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, 1);
- GetDepth_Setup(IN.m_blendMask);
+ s_blendMaskFromVertexStream = IN.m_blendMask;
float depthNDC;
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ClearCoatState.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ClearCoatState.lua
index 8289291ef4..ffa00d7efd 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ClearCoatState.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ClearCoatState.lua
@@ -34,7 +34,7 @@ function GetShaderOptionDependencies()
end
function UpdateUseTextureState(context, clearCoatEnabled, textureMapPropertyName, useTexturePropertyName, shaderOptionName)
- local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
+ local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
context:SetShaderOptionValue_bool(shaderOptionName, clearCoatEnabled and useTextureMap and textureMap ~= nil)
end
@@ -50,7 +50,7 @@ end
-- Note this logic matches that of the UseTextureFunctor class.
function UpdateTextureDependentPropertyVisibility(context, textureMapPropertyName, useTexturePropertyName, uvPropertyName)
- local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
+ local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTexture = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
if(textureMap == nil) then
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_EmissiveState.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_EmissiveState.lua
index a8ac2e8a4a..7ee5876adb 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_EmissiveState.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_EmissiveState.lua
@@ -22,7 +22,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("emissive.enable")
- local textureMap = context:GetMaterialPropertyValue_image("emissive.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("emissive.textureMap")
local useTextureMap = context:GetMaterialPropertyValue_bool("emissive.useTexture")
context:SetShaderOptionValue_bool("o_emissiveEnabled", enable)
@@ -47,7 +47,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("emissive.textureMapUv", mainVisibility)
if(enable) then
- local textureMap = context:GetMaterialPropertyValue_image("emissive.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("emissive.textureMap")
local useTextureMap = context:GetMaterialPropertyValue_bool("emissive.useTexture")
if(textureMap == nil) then
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua
index 6cc595d712..541b1ac1ce 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua
@@ -90,7 +90,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("opacity.textureMap", MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Hidden)
else
- local textureMap = context:GetMaterialPropertyValue_image("opacity.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("opacity.textureMap")
if(nil == textureMap) then
context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Disabled)
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua
index 0287e1105e..e6689da327 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua
@@ -22,7 +22,7 @@ end
function Process(context)
local enable = context:GetMaterialPropertyValue_bool("parallax.enable")
- local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
context:SetShaderOptionValue_bool("o_parallax_feature_enabled", enable)
context:SetShaderOptionValue_bool("o_useDepthMap", enable and textureMap ~= nil)
end
@@ -36,7 +36,7 @@ function ProcessEditor(context)
context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Hidden)
end
- local textureMap = context:GetMaterialPropertyValue_image("parallax.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap")
local visibility = MaterialPropertyVisibility_Enabled
if(not enable or textureMap == nil) then
visibility = MaterialPropertyVisibility_Hidden
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Roughness.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Roughness.lua
index 4887bc47e8..222e69cd3d 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Roughness.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Roughness.lua
@@ -21,13 +21,13 @@ function GetShaderOptionDependencies()
end
function Process(context)
- local textureMap = context:GetMaterialPropertyValue_image("roughness.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("roughness.textureMap")
local useTexture = context:GetMaterialPropertyValue_bool("roughness.useTexture")
context:SetShaderOptionValue_bool("o_roughness_useTexture", useTexture and textureMap ~= nil)
end
function ProcessEditor(context)
- local textureMap = context:GetMaterialPropertyValue_image("roughness.textureMap")
+ local textureMap = context:GetMaterialPropertyValue_Image("roughness.textureMap")
local useTexture = context:GetMaterialPropertyValue_bool("roughness.useTexture")
if(nil == textureMap) then
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_SubsurfaceState.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_SubsurfaceState.lua
index fb07ac89a3..d8a69ba355 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_SubsurfaceState.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_SubsurfaceState.lua
@@ -35,7 +35,7 @@ TransmissionMode_ThickObject = 1
TransmissionMode_ThinObject = 2
function UpdateUseTextureState(context, subsurfaceScatteringEnabled, textureMapPropertyName, useTexturePropertyName, shaderOptionName)
- local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
+ local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
context:SetShaderOptionValue_bool(shaderOptionName, subsurfaceScatteringEnabled and useTextureMap and textureMap ~= nil)
end
@@ -53,7 +53,7 @@ function UpdateTextureDependentPropertyVisibility(context, featureEnabled, textu
context:SetMaterialPropertyVisibility(useTexturePropertyName, MaterialPropertyVisibility_Hidden)
context:SetMaterialPropertyVisibility(uvPropertyName, MaterialPropertyVisibility_Hidden)
else
- local textureMap = context:GetMaterialPropertyValue_image(textureMapPropertyName)
+ local textureMap = context:GetMaterialPropertyValue_Image(textureMapPropertyName)
local useTextureMap = context:GetMaterialPropertyValue_bool(useTexturePropertyName)
if(textureMap == nil) then
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
index bb63d27df0..1a74a68e96 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
@@ -43,7 +43,6 @@ class Surface
};
-
// Specular Anti-Aliasing technique from this paper:
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
void Surface::ApplySpecularAA()
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl
index a5d761d815..c96828e23f 100644
--- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl
@@ -91,7 +91,7 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
{
for (int x = -extent; x <= extent; ++x)
{
- float3 downsampledNormal = PassSrg::m_downsampledNormal.Load(int3(probeIrradianceCoords, 0), int2(x, y)).rgb;
+ float3 downsampledNormal = PassSrg::m_downsampledNormal.Load(int3(probeIrradianceCoords + int2(x, y), 0)).rgb;
downsampledNormal = downsampledNormal * 2.0f - 1.0f;
float normalDot = dot(downsampledNormal, normal);
@@ -100,10 +100,10 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
if (normalDot > NormalMatchTolerance)
{
// the normals are almost identical, if the depth is within the tolerance we can optimize by just taking this sample
- float downsampledDepth = PassSrg::m_downsampledDepth.Load(int3(probeIrradianceCoords, 0), int2(x, y)).r;
+ float downsampledDepth = PassSrg::m_downsampledDepth.Load(int3(probeIrradianceCoords + int2(x, y), 0)).r;
if (abs(depth - downsampledDepth) <= DepthTolerance)
{
- float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords,0), int2(x, y)).rgb;
+ float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords + int2(x, y),0)).rgb;
probeIrradiance = saturate(probeIrradiance);
return probeIrradiance;
}
@@ -115,7 +115,7 @@ float3 SampleProbeIrradiance(uint2 probeIrradianceCoords, float depth, float3 no
}
}
- float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords, 0), closestOffset).rgb;
+ float3 probeIrradiance = PassSrg::m_downsampledProbeIrradiance.Load(int3(probeIrradianceCoords + closestOffset, 0)).rgb;
probeIrradiance = saturate(probeIrradiance);
return probeIrradiance;
}
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl
index f10fc67da5..d2e73927e0 100644
--- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl
@@ -70,8 +70,8 @@ PSOutput MainPS(VSOutput IN)
{
for (uint x = 0; x < ImageScale; ++x)
{
- float depth = PassSrg::m_depth.Load(int3(screenCoords, 0), int2(x, y)).r;
- float4 encodedNormal = PassSrg::m_normal.Load(int3(screenCoords, 0), int2(x, y));
+ float depth = PassSrg::m_depth.Load(int3(screenCoords + int2(x, y), 0)).r;
+ float4 encodedNormal = PassSrg::m_normal.Load(int3(screenCoords + int2(x, y), 0));
// take the closest depth sample to ensure we're getting the normal closest to the viewer
// (larger depth value due to reverse depth)
diff --git a/Gems/Atom/Feature/Common/Assets/Textures/DefaultBlendMask_layers.png b/Gems/Atom/Feature/Common/Assets/Textures/DefaultBlendMask_layers.png
index d1606516af..5e60261dd7 100644
--- a/Gems/Atom/Feature/Common/Assets/Textures/DefaultBlendMask_layers.png
+++ b/Gems/Atom/Feature/Common/Assets/Textures/DefaultBlendMask_layers.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f74ffab6ee15906158d27cbd2e5556e8fcdfd7820c0d0fd4b403de8a7af81662
-size 5651
+oid sha256:6660fa05dbf1e90298472fb41d99fff80a80de64ee88d17af4d0df3bdafb1ff6
+size 52877
diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp
index dbbf666967..8397dcf9b3 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp
@@ -77,12 +77,16 @@ namespace AZ
}
};
+ // If PBR material properties aren't in use, fall back to legacy properties. Don't do that if some PBR material properties are set, though.
+ bool anyPBRInUse = false;
+
handleTexture("specularF0", SceneAPI::DataTypes::IMaterialData::TextureMapType::Specular);
handleTexture("normal", SceneAPI::DataTypes::IMaterialData::TextureMapType::Normal);
AZStd::optional useColorMap = materialData.GetUseColorMap();
// If the useColorMap property exists, this is a PBR material and the color should be set to baseColor.
if (useColorMap.has_value())
{
+ anyPBRInUse = true;
handleTexture("baseColor", SceneAPI::DataTypes::IMaterialData::TextureMapType::BaseColor);
}
else
@@ -97,17 +101,19 @@ namespace AZ
AZStd::optional baseColor = materialData.GetBaseColor();
if (baseColor.has_value())
{
+ anyPBRInUse = true;
sourceData.m_properties["baseColor"]["color"].m_value = toColor(baseColor.value());
}
sourceData.m_properties["opacity"]["factor"].m_value = materialData.GetOpacity();
- auto applyOptionalPropertiesFunc = [&sourceData](const auto& propertyGroup, const auto& propertyName, const auto& propertyOptional)
+ auto applyOptionalPropertiesFunc = [&sourceData, &anyPBRInUse](const auto& propertyGroup, const auto& propertyName, const auto& propertyOptional)
{
// Only set PBR settings if they were specifically set in the scene's data.
// Otherwise, leave them unset so the data driven default properties are used.
if (propertyOptional.has_value())
{
+ anyPBRInUse = true;
sourceData.m_properties[propertyGroup][propertyName].m_value = propertyOptional.value();
}
};
@@ -127,6 +133,13 @@ namespace AZ
handleTexture("ambientOcclusion", SceneAPI::DataTypes::IMaterialData::TextureMapType::AmbientOcclusion);
applyOptionalPropertiesFunc("ambientOcclusion", "useTexture", materialData.GetUseAOMap());
+
+ if (!anyPBRInUse)
+ {
+ // If it doesn't have the useColorMap property, then it's a non-PBR material and the baseColor
+ // texture needs to be set to the diffuse color.
+ sourceData.m_properties["baseColor"]["color"].m_value = toColor(materialData.GetDiffuseColor());
+ }
return true;
}
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/Platform/Windows/Vulkan_Traits_Windows.h b/Gems/Atom/RHI/Vulkan/Code/Source/Platform/Windows/Vulkan_Traits_Windows.h
index c7c9902115..c1314aaf66 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/Platform/Windows/Vulkan_Traits_Windows.h
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/Platform/Windows/Vulkan_Traits_Windows.h
@@ -11,7 +11,7 @@
*/
#pragma once
-#define AZ_TRAIT_ATOM_SHADERBUILDER_DXC "Builders/DirectXShaderCompilerAz/dxc.exe"
+#define AZ_TRAIT_ATOM_SHADERBUILDER_DXC "Builders/DirectXShaderCompiler/dxc.exe"
#define AZ_TRAIT_ATOM_VULKAN_DISABLE_DUAL_SOURCE_BLENDING 0
#define AZ_TRAIT_ATOM_VULKAN_DLL "vulkan.dll"
#define AZ_TRAIT_ATOM_VULKAN_DLL_1 "vulkan-1.dll"
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h
index 44de79ff22..396ba14810 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h
@@ -329,6 +329,8 @@ namespace AZ
bool SetMaterialPropertySoftMaxValue(const char* name, Type value);
bool SetMaterialPropertyDescription(const char* name, const char* description);
+
+ bool SetMaterialPropertyGroupVisibility(const char* name, MaterialPropertyGroupVisibility visibility);
private:
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h
new file mode 100644
index 0000000000..b74e330665
--- /dev/null
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h
@@ -0,0 +1,100 @@
+/*
+* 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
+#include
+#include
+
+namespace AZ
+{
+ namespace RPI
+ {
+ // Normally we wouldn't want editor-related code mixed in with runtime code, but
+ // since this data can be modified dynamically, keeping it in the runtime makes
+ // the overall material functor design simpler and more user-friendly.
+
+
+ //! Visibility for each material property.
+ //! If the data field is empty, use default as editable.
+ enum class MaterialPropertyVisibility : uint32_t
+ {
+ Enabled, //!< The property is visible and editable
+ Disabled, //!< The property is visible but non-editable
+ Hidden, //!< The property is invisible
+
+ Default = Enabled
+ };
+
+ struct MaterialPropertyRange
+ {
+ MaterialPropertyRange() = default;
+ MaterialPropertyRange(
+ const MaterialPropertyValue& max,
+ const MaterialPropertyValue& min,
+ const MaterialPropertyValue& softMax,
+ const MaterialPropertyValue& softMin
+ )
+ : m_max(max)
+ , m_min(min)
+ , m_softMax(softMax)
+ , m_softMin(softMin)
+ {}
+
+ MaterialPropertyValue m_max;
+ MaterialPropertyValue m_min;
+ MaterialPropertyValue m_softMax;
+ MaterialPropertyValue m_softMin;
+ };
+
+ //! Used by material functors to dynamically control property metadata in tools.
+ //! For example, show/hide a property based on some other 'enable' flag property.
+ struct MaterialPropertyDynamicMetadata
+ {
+ AZ_TYPE_INFO(MaterialPropertyDynamicMetadata, "{A89F215F-3235-499F-896C-9E63ACC1D657}");
+
+ AZ::RPI::MaterialPropertyVisibility m_visibility;
+ AZStd::string m_description;
+ AZ::RPI::MaterialPropertyRange m_propertyRange;
+ };
+
+ //! Visibility for each material property group.
+ enum class MaterialPropertyGroupVisibility : uint32_t
+ {
+ // Note it's helpful to keep these values aligned with MaterialPropertyVisibility in part because in lua it would be easy to accidentally use
+ // MaterialPropertyVisibility instead of MaterialPropertyGroupVisibility resulting in sneaky bugs. Also, if the enums end up being the same in
+ // the future, we could just merge them into one.
+
+ Enabled, //!< The property is visible and editable
+ //Disabled, //!< The property is visible but non-editable (reserved for possible future use, to match MaterialPropertyVisibility)
+ Hidden=2, //!< The property is invisible
+
+ Default = Enabled
+ };
+
+ //! Used by material functors to dynamically control property group metadata in tools.
+ //! For example, show/hide an entire property group based on some 'enable' flag property.
+ struct MaterialPropertyGroupDynamicMetadata
+ {
+ AZ_TYPE_INFO(MaterialPropertyGroupDynamicMetadata, "{F94009F7-48A3-4CE0-AF64-D5A86890ACD4}");
+
+ AZ::RPI::MaterialPropertyGroupVisibility m_visibility;
+ };
+
+ void ReflectMaterialDynamicMetadata(ReflectContext* context);
+
+ } // namespace RPI
+
+ AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyVisibility, "{318B43A2-79E3-4502-8FD0-5815209EA123}");
+ AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyGroupVisibility, "{B803958B-DE64-4FBF-AC00-CF781611BE37}");
+} // namespace AZ
+
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialFunctor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialFunctor.h
index d17c7634a2..83472ade77 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialFunctor.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialFunctor.h
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
namespace AZ
{
@@ -147,6 +148,8 @@ namespace AZ
public:
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const Name& propertyName) const;
const MaterialPropertyDynamicMetadata* GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const;
+
+ const MaterialPropertyGroupDynamicMetadata* GetMaterialPropertyGroupMetadata(const Name& propertyName) const;
//! Get the property value. The type must be one of those in MaterialPropertyValue.
//! Otherwise, a compile error will be reported.
@@ -178,6 +181,8 @@ namespace AZ
bool SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max);
bool SetMaterialPropertySoftMaxValue(const MaterialPropertyIndex& index, const MaterialPropertyValue& max);
+
+ bool SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility);
// [GFX TODO][ATOM-4168] Replace the workaround for unlink-able RPI.Public classes in MaterialFunctor
// const AZStd::vector&, AZStd::unordered_map&, RHI::ConstPtr
@@ -185,18 +190,23 @@ namespace AZ
EditorContext(
const AZStd::vector& propertyValues,
RHI::ConstPtr materialPropertiesLayout,
- AZStd::unordered_map& metadata,
- AZStd::unordered_set& outChangedProperties,
+ AZStd::unordered_map& propertyMetadata,
+ AZStd::unordered_map& propertyGroupMetadata,
+ AZStd::unordered_set& updatedPropertiesOut,
+ AZStd::unordered_set& updatedPropertyGroupsOut,
const MaterialPropertyFlags* materialPropertyDependencies
);
private:
- AZStd::list_iterator> QueryMaterialMetadata(const Name& propertyName) const;
+ MaterialPropertyDynamicMetadata* QueryMaterialPropertyMetadata(const Name& propertyName) const;
+ MaterialPropertyGroupDynamicMetadata* QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const;
const AZStd::vector& m_materialPropertyValues;
RHI::ConstPtr m_materialPropertiesLayout;
- AZStd::unordered_map& m_metadata;
- AZStd::unordered_set& m_outChangedProperties;
+ AZStd::unordered_map& m_propertyMetadata;
+ AZStd::unordered_map& m_propertyGroupMetadata;
+ AZStd::unordered_set& m_updatedPropertiesOut;
+ AZStd::unordered_set& m_updatedPropertyGroupsOut;
const MaterialPropertyFlags* m_materialPropertyDependencies = nullptr;
};
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
index d73ce2334b..fab72d5f96 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
@@ -81,52 +81,6 @@ namespace AZ
AZStd::string GetMaterialPropertyDataTypeString(AZ::TypeId typeId);
- //! Visibility for each material property.
- //! If the data field is empty, use default as editable.
- enum class MaterialPropertyVisibility : uint32_t
- {
- Enabled, //< The property is visible and editable
- Disabled, //< The property is visible but non-editable
- Hidden, //< The property is invisible
-
- Default = Enabled
- };
-
- struct MaterialPropertyRange
- {
- MaterialPropertyRange() = default;
- MaterialPropertyRange(
- const MaterialPropertyValue& max,
- const MaterialPropertyValue& min,
- const MaterialPropertyValue& softMax,
- const MaterialPropertyValue& softMin
- )
- : m_max(max)
- , m_min(min)
- , m_softMax(softMax)
- , m_softMin(softMin)
- {}
-
- MaterialPropertyValue m_max;
- MaterialPropertyValue m_min;
- MaterialPropertyValue m_softMax;
- MaterialPropertyValue m_softMin;
- };
-
- //! Used by material functors to dynamically control property metadata in tools.
- //! For example, show/hide a property based on some other 'enable' flag property.
- //! Normally we wouldn't want editor-related code mixed in with runtime code, but
- //! since this data can be modified dynamically, keeping it in the runtime makes
- //! the overall material functor design simpler and more user-friendly.
- struct MaterialPropertyDynamicMetadata
- {
- AZ_TYPE_INFO(MaterialPropertyDynamicMetadata, "{A89F215F-3235-499F-896C-9E63ACC1D657}");
-
- AZ::RPI::MaterialPropertyVisibility m_visibility;
- AZStd::string m_description;
- AZ::RPI::MaterialPropertyRange m_propertyRange;
- };
-
//! A material property is any data input to a material, like a bool, float, Vector, Image, Buffer, etc.
//! This descriptor defines a single input property, including it's name ID, and how it maps
//! to the shader system.
@@ -171,7 +125,6 @@ namespace AZ
} // namespace RPI
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyOutputType, "{42A6E5E8-0FE6-4D7B-884A-1F478E4ADD97}");
- AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyVisibility, "{318B43A2-79E3-4502-8FD0-5815209EA123}");
AZ_TYPE_INFO_SPECIALIZE(RPI::MaterialPropertyDataType, "{3D903D5C-C6AA-452E-A2F8-8948D30833FF}");
} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/MaterialSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/MaterialSystem.cpp
index e7e04b271d..f1751a02e2 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/MaterialSystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/MaterialSystem.cpp
@@ -32,6 +32,7 @@ namespace AZ
MaterialPropertiesLayout::Reflect(context);
MaterialFunctor::Reflect(context);
LuaMaterialFunctor::Reflect(context);
+ ReflectMaterialDynamicMetadata(context);
}
void MaterialSystem::GetAssetHandlers(AssetHandlerPtrList& assetHandlers)
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
index 7ab3489666..7db5f12560 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
@@ -63,6 +63,7 @@ namespace AZ
behaviorContext->Class();
MaterialPropertyDescriptor::Reflect(behaviorContext);
+ ReflectMaterialDynamicMetadata(behaviorContext);
LuaMaterialFunctorRenderStates::Reflect(behaviorContext);
LuaMaterialFunctorShaderItem::Reflect(behaviorContext);
@@ -255,7 +256,7 @@ namespace AZ
// Specialize for type Image* because that will be more intuitive within Lua.
// The script can then check the result for nil without calling "get()".
- // For example, "GetMaterialPropertyValue_image(name) == nil" rather than "GetMaterialPropertyValue_image(name):get() == nil"
+ // For example, "GetMaterialPropertyValue_Image(name) == nil" rather than "GetMaterialPropertyValue_Image(name):get() == nil"
template<>
Image* LuaMaterialFunctorCommonContext::GetMaterialPropertyValue(const char* name) const
{
@@ -278,7 +279,7 @@ namespace AZ
->Method("GetMaterialPropertyValue_Vector3", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue)
->Method("GetMaterialPropertyValue_Vector4", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue)
->Method("GetMaterialPropertyValue_Color", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue)
- ->Method("GetMaterialPropertyValue_image", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue)
+ ->Method("GetMaterialPropertyValue_Image", &LuaMaterialFunctorRuntimeContext::GetMaterialPropertyValue)
->Method("SetShaderConstant_bool", &LuaMaterialFunctorRuntimeContext::SetShaderConstant)
->Method("SetShaderConstant_int", &LuaMaterialFunctorRuntimeContext::SetShaderConstant)
->Method("SetShaderConstant_uint", &LuaMaterialFunctorRuntimeContext::SetShaderConstant)
@@ -436,7 +437,7 @@ namespace AZ
->Method("GetMaterialPropertyValue_Vector3", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue)
->Method("GetMaterialPropertyValue_Vector4", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue)
->Method("GetMaterialPropertyValue_Color", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue)
- ->Method("GetMaterialPropertyValue_image", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue)
+ ->Method("GetMaterialPropertyValue_Image", &LuaMaterialFunctorEditorContext::GetMaterialPropertyValue)
->Method("SetMaterialPropertyVisibility", &LuaMaterialFunctorEditorContext::SetMaterialPropertyVisibility)
->Method("SetMaterialPropertyDescription", &LuaMaterialFunctorEditorContext::SetMaterialPropertyDescription)
->Method("SetMaterialPropertyMinValue_int", &LuaMaterialFunctorEditorContext::SetMaterialPropertyMinValue)
@@ -451,6 +452,7 @@ namespace AZ
->Method("SetMaterialPropertySoftMaxValue_int", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue)
->Method("SetMaterialPropertySoftMaxValue_uint", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue)
->Method("SetMaterialPropertySoftMaxValue_float", &LuaMaterialFunctorEditorContext::SetMaterialPropertySoftMaxValue)
+ ->Method("SetMaterialPropertyGroupVisibility", &LuaMaterialFunctorEditorContext::SetMaterialPropertyGroupVisibility)
;
}
@@ -524,6 +526,15 @@ namespace AZ
return m_editorContextImpl->SetMaterialPropertySoftMaxValue(index, value);
}
+
+ bool LuaMaterialFunctorEditorContext::SetMaterialPropertyGroupVisibility(const char* name, MaterialPropertyGroupVisibility visibility)
+ {
+ if (m_editorContextImpl)
+ {
+ return m_editorContextImpl->SetMaterialPropertyGroupVisibility(Name{m_propertyNamePrefix + name}, visibility);
+ }
+ return false;
+ }
bool LuaMaterialFunctorEditorContext::SetMaterialPropertyVisibility(const char* name, MaterialPropertyVisibility visibility)
{
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp
new file mode 100644
index 0000000000..5c8f4ccc02
--- /dev/null
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp
@@ -0,0 +1,50 @@
+/*
+* 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
+#include
+
+namespace AZ
+{
+ namespace RPI
+ {
+ void ReflectMaterialDynamicMetadata(ReflectContext* context)
+ {
+ if (auto* serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Enum()
+ ->Value("Enabled", MaterialPropertyVisibility::Enabled)
+ ->Value("Disabled", MaterialPropertyVisibility::Disabled)
+ ->Value("Hidden", MaterialPropertyVisibility::Hidden)
+ ;
+
+ serializeContext->Enum()
+ ->Value("Enabled", MaterialPropertyGroupVisibility::Enabled)
+ ->Value("Hidden", MaterialPropertyGroupVisibility::Hidden)
+ ;
+ }
+
+ if (auto* behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext
+ ->Enum<(int)MaterialPropertyVisibility::Enabled>("MaterialPropertyVisibility_Enabled")
+ ->Enum<(int)MaterialPropertyVisibility::Disabled>("MaterialPropertyVisibility_Disabled")
+ ->Enum<(int)MaterialPropertyVisibility::Hidden>("MaterialPropertyVisibility_Hidden");
+
+ behaviorContext
+ ->Enum<(int)MaterialPropertyGroupVisibility::Enabled>("MaterialPropertyGroupVisibility_Enabled")
+ ->Enum<(int)MaterialPropertyGroupVisibility::Hidden>("MaterialPropertyGroupVisibility_Hidden");
+ }
+ }
+
+ } // namespace RPI
+} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp
index 32772e9dd5..a41ab9eea6 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialFunctor.cpp
@@ -142,25 +142,24 @@ namespace AZ
MaterialFunctor::EditorContext::EditorContext(
const AZStd::vector& propertyValues,
RHI::ConstPtr materialPropertiesLayout,
- AZStd::unordered_map& metadata,
- AZStd::unordered_set& outChangedProperties,
+ AZStd::unordered_map& propertyMetadata,
+ AZStd::unordered_map& propertyGroupMetadata,
+ AZStd::unordered_set& updatedPropertiesOut,
+ AZStd::unordered_set& updatedPropertyGroupsOut,
const MaterialPropertyFlags* materialPropertyDependencies
)
: m_materialPropertyValues(propertyValues)
, m_materialPropertiesLayout(materialPropertiesLayout)
- , m_metadata(metadata)
- , m_outChangedProperties(outChangedProperties)
+ , m_propertyMetadata(propertyMetadata)
+ , m_propertyGroupMetadata(propertyGroupMetadata)
+ , m_updatedPropertiesOut(updatedPropertiesOut)
+ , m_updatedPropertyGroupsOut(updatedPropertyGroupsOut)
, m_materialPropertyDependencies(materialPropertyDependencies)
{}
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const Name& propertyName) const
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
- {
- return nullptr;
- }
- return &(it->second);
+ return QueryMaterialPropertyMetadata(propertyName);
}
const MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyMetadata(const MaterialPropertyIndex& index) const
@@ -168,19 +167,41 @@ namespace AZ
const Name& name = m_materialPropertiesLayout->GetPropertyDescriptor(index)->GetName();
return GetMaterialPropertyMetadata(name);
}
-
- bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
+
+ const MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::GetMaterialPropertyGroupMetadata(const Name& propertyName) const
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ return QueryMaterialPropertyGroupMetadata(propertyName);
+ }
+
+ bool MaterialFunctor::EditorContext::SetMaterialPropertyGroupVisibility(const Name& propertyGroupName, MaterialPropertyGroupVisibility visibility)
+ {
+ MaterialPropertyGroupDynamicMetadata* metadata = QueryMaterialPropertyGroupMetadata(propertyGroupName);
+ if (!metadata)
{
return false;
}
- MaterialPropertyVisibility originValue = it->second.m_visibility;
- it->second.m_visibility = visibility;
- if (originValue != visibility)
+
+ if (metadata->m_visibility != visibility)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_visibility = visibility;
+ m_updatedPropertyGroupsOut.insert(propertyGroupName);
+ }
+
+ return true;
+ }
+
+ bool MaterialFunctor::EditorContext::SetMaterialPropertyVisibility(const Name& propertyName, MaterialPropertyVisibility visibility)
+ {
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
+ {
+ return false;
+ }
+
+ if (metadata->m_visibility != visibility)
+ {
+ metadata->m_visibility = visibility;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -194,17 +215,16 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyDescription(const Name& propertyName, AZStd::string description)
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
{
return false;
}
- AZStd::string origin = it->second.m_description;
- it->second.m_description = description;
- if (origin != description)
+ if (metadata->m_description != description)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_description = description;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -218,18 +238,16 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyMinValue(const Name& propertyName, const MaterialPropertyValue& min)
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
{
return false;
}
- MaterialPropertyValue origin = it->second.m_propertyRange.m_min;
- it->second.m_propertyRange.m_min = min;
-
- if(origin != min)
+ if(metadata->m_propertyRange.m_min != min)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_propertyRange.m_min = min;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -243,18 +261,16 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertyMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
{
return false;
}
- MaterialPropertyValue origin = it->second.m_propertyRange.m_max;
- it->second.m_propertyRange.m_max = max;
-
- if (origin != max)
+ if (metadata->m_propertyRange.m_max != max)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_propertyRange.m_max = max;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -268,18 +284,16 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMinValue(const Name& propertyName, const MaterialPropertyValue& min)
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
{
return false;
}
- MaterialPropertyValue origin = it->second.m_propertyRange.m_softMin;
- it->second.m_propertyRange.m_softMin = min;
-
- if (origin != min)
+ if (metadata->m_propertyRange.m_softMin != min)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_propertyRange.m_softMin = min;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -293,18 +307,16 @@ namespace AZ
bool MaterialFunctor::EditorContext::SetMaterialPropertySoftMaxValue(const Name& propertyName, const MaterialPropertyValue& max)
{
- auto it = QueryMaterialMetadata(propertyName);
- if (it == m_metadata.end())
+ MaterialPropertyDynamicMetadata* metadata = QueryMaterialPropertyMetadata(propertyName);
+ if (!metadata)
{
return false;
}
- MaterialPropertyValue origin = it->second.m_propertyRange.m_softMax;
- it->second.m_propertyRange.m_softMax = max;
-
- if (origin != max)
+ if (metadata->m_propertyRange.m_softMax != max)
{
- m_outChangedProperties.insert(propertyName);
+ metadata->m_propertyRange.m_softMax = max;
+ m_updatedPropertiesOut.insert(propertyName);
}
return true;
@@ -316,15 +328,26 @@ namespace AZ
return SetMaterialPropertySoftMaxValue(name, max);
}
- AZStd::list_iterator> MaterialFunctor::EditorContext::QueryMaterialMetadata(const Name& propertyName) const
+ MaterialPropertyDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyMetadata(const Name& propertyName) const
{
- auto it = m_metadata.find(propertyName);
- if (it == m_metadata.end())
+ auto it = m_propertyMetadata.find(propertyName);
+ if (it == m_propertyMetadata.end())
{
AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property: %s.", propertyName.GetCStr());
}
- return it;
+ return &it->second;
+ }
+
+ MaterialPropertyGroupDynamicMetadata* MaterialFunctor::EditorContext::QueryMaterialPropertyGroupMetadata(const Name& propertyGroupName) const
+ {
+ auto it = m_propertyGroupMetadata.find(propertyGroupName);
+ if (it == m_propertyGroupMetadata.end())
+ {
+ AZ_Error("MaterialFunctor", false, "Couldn't find metadata for material property group: %s.", propertyGroupName.GetCStr());
+ }
+
+ return &it->second;
}
template
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
index 367d95357b..72d658db63 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
@@ -124,12 +124,6 @@ namespace AZ
->Value(ToString(MaterialPropertyOutputType::ShaderOption), MaterialPropertyOutputType::ShaderOption)
;
- serializeContext->Enum()
- ->Value("Enabled", MaterialPropertyVisibility::Enabled)
- ->Value("Disabled", MaterialPropertyVisibility::Disabled)
- ->Value("Hidden", MaterialPropertyVisibility::Hidden)
- ;
-
serializeContext->Enum()
->Value(ToString(MaterialPropertyDataType::Invalid), MaterialPropertyDataType::Invalid)
->Value(ToString(MaterialPropertyDataType::Bool), MaterialPropertyDataType::Bool)
@@ -153,14 +147,6 @@ namespace AZ
;
}
- if (auto* behaviorContext = azrtti_cast(context))
- {
- behaviorContext
- ->Enum<(int)MaterialPropertyVisibility::Enabled>("MaterialPropertyVisibility_Enabled")
- ->Enum<(int)MaterialPropertyVisibility::Disabled>("MaterialPropertyVisibility_Disabled")
- ->Enum<(int)MaterialPropertyVisibility::Hidden>("MaterialPropertyVisibility_Hidden");
- }
-
MaterialPropertyIndex::Reflect(context);
}
diff --git a/Gems/Atom/RPI/Code/Tests/Material/LuaMaterialFunctorTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/LuaMaterialFunctorTests.cpp
index 76fa6bfb0e..3dcbdfce07 100644
--- a/Gems/Atom/RPI/Code/Tests/Material/LuaMaterialFunctorTests.cpp
+++ b/Gems/Atom/RPI/Code/Tests/Material/LuaMaterialFunctorTests.cpp
@@ -748,12 +748,15 @@ namespace UnitTest
MaterialPropertyDataType::UInt, "general.mode",
MaterialPropertyDataType::Float, "general.value",
functorScript);
-
+
AZStd::unordered_set changedPropertyNames;
-
AZStd::unordered_map propertyDynamicMetadata;
propertyDynamicMetadata[Name{"general.mode"}] = {};
propertyDynamicMetadata[Name{"general.value"}] = {};
+
+ AZStd::unordered_set changedPropertyGroupNames;
+ AZStd::unordered_map propertyGroupDynamicMetadata;
+ propertyGroupDynamicMetadata[Name{"general"}] = {};
Ptr functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
@@ -761,7 +764,9 @@ namespace UnitTest
testData.GetMaterial()->GetPropertyValues(),
testData.GetMaterial()->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
+ propertyGroupDynamicMetadata,
changedPropertyNames,
+ changedPropertyGroupNames,
&functor->GetMaterialPropertyDependencies()
);
@@ -814,10 +819,13 @@ namespace UnitTest
functorScript);
AZStd::unordered_set changedPropertyNames;
-
AZStd::unordered_map propertyDynamicMetadata;
propertyDynamicMetadata[Name{"general.units"}] = {};
propertyDynamicMetadata[Name{"general.distance"}] = {};
+
+ AZStd::unordered_set changedPropertyGroupNames;
+ AZStd::unordered_map propertyGroupDynamicMetadata;
+ propertyGroupDynamicMetadata[Name{"general"}] = {};
Ptr functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
@@ -825,7 +833,9 @@ namespace UnitTest
testData.GetMaterial()->GetPropertyValues(),
testData.GetMaterial()->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
+ propertyGroupDynamicMetadata,
changedPropertyNames,
+ changedPropertyGroupNames,
&functor->GetMaterialPropertyDependencies()
);
@@ -845,6 +855,66 @@ namespace UnitTest
EXPECT_EQ(-100.0f, propertyDynamicMetadata[Name{"general.distance"}].m_propertyRange.m_softMin.GetValue());
EXPECT_EQ(100.0f, propertyDynamicMetadata[Name{"general.distance"}].m_propertyRange.m_softMax.GetValue());
}
+
+ TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_EditorContext_SetMaterialPropertyGroupVisibility)
+ {
+ using namespace AZ::RPI;
+
+ const char* functorScript =
+ R"(
+ function GetMaterialPropertyDependencies()
+ return { "general.mode" }
+ end
+
+ function ProcessEditor(context)
+ local mode = context:GetMaterialPropertyValue_uint("general.mode")
+
+ if (mode == 1) then
+ context:SetMaterialPropertyGroupVisibility("otherGroup", MaterialPropertyGroupVisibility_Enabled)
+ else
+ context:SetMaterialPropertyGroupVisibility("otherGroup", MaterialPropertyGroupVisibility_Hidden)
+ end
+ end
+ )";
+
+ TestMaterialData testData;
+ testData.Setup(
+ MaterialPropertyDataType::UInt, "general.mode",
+ MaterialPropertyDataType::Float, "otherGroup.value",
+ functorScript);
+
+ AZStd::unordered_set changedPropertyNames;
+ AZStd::unordered_map propertyDynamicMetadata;
+ propertyDynamicMetadata[Name{"general.mode"}] = {};
+ propertyDynamicMetadata[Name{"otherGroup.value"}] = {};
+
+ AZStd::unordered_set changedPropertyGroupNames;
+ AZStd::unordered_map propertyGroupDynamicMetadata;
+ propertyGroupDynamicMetadata[Name{"general"}] = {};
+ propertyGroupDynamicMetadata[Name{"otherGroup"}] = {};
+
+ Ptr functor = testData.GetMaterialTypeAsset()->GetMaterialFunctors()[0];
+
+ AZ::RPI::MaterialFunctor::EditorContext context = AZ::RPI::MaterialFunctor::EditorContext(
+ testData.GetMaterial()->GetPropertyValues(),
+ testData.GetMaterial()->GetMaterialPropertiesLayout(),
+ propertyDynamicMetadata,
+ propertyGroupDynamicMetadata,
+ changedPropertyNames,
+ changedPropertyGroupNames,
+ &functor->GetMaterialPropertyDependencies()
+ );
+
+ testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{0u});
+ functor->Process(context);
+ EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"general"}].m_visibility);
+ EXPECT_EQ(MaterialPropertyGroupVisibility::Hidden, propertyGroupDynamicMetadata[Name{"otherGroup"}].m_visibility);
+
+ testData.GetMaterial()->SetPropertyValue(testData.GetMaterialPropertyIndex(), MaterialPropertyValue{1u});
+ functor->Process(context);
+ EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"general"}].m_visibility);
+ EXPECT_EQ(MaterialPropertyGroupVisibility::Enabled, propertyGroupDynamicMetadata[Name{"otherGroup"}].m_visibility);
+ }
TEST_F(LuaMaterialFunctorTests, LuaMaterialFunctor_RuntimeContext_SetRenderStates)
{
diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp
index 5a81ebb74d..d32c285780 100644
--- a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp
+++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertySerializerTests.cpp
@@ -29,6 +29,7 @@ namespace JsonSerializationTests
{
AZ::RPI::MaterialTypeSourceData::Reflect(context.get());
AZ::RPI::MaterialPropertyDescriptor::Reflect(context.get());
+ AZ::RPI::ReflectMaterialDynamicMetadata(context.get());
}
void Reflect(AZStd::unique_ptr& context)
diff --git a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake
index f05f153bb7..3a4e1cacc6 100644
--- a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake
+++ b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake
@@ -55,6 +55,7 @@ set(FILES
Include/Atom/RPI.Reflect/Material/MaterialAsset.h
Include/Atom/RPI.Reflect/Material/MaterialAssetCreatorCommon.h
Include/Atom/RPI.Reflect/Material/MaterialAssetCreator.h
+ Include/Atom/RPI.Reflect/Material/MaterialDynamicMetadata.h
Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h
Include/Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h
Include/Atom/RPI.Reflect/Material/MaterialPropertyValue.h
@@ -140,6 +141,7 @@ set(FILES
Source/RPI.Reflect/Material/MaterialAssetCreatorCommon.cpp
Source/RPI.Reflect/Material/MaterialAssetCreator.cpp
Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp
+ Source/RPI.Reflect/Material/MaterialDynamicMetadata.cpp
Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp
Source/RPI.Reflect/Material/MaterialPropertiesLayout.cpp
Source/RPI.Reflect/Material/MaterialTypeAsset.cpp
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material
index b2a3eac890..d9a4aabe2a 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material
@@ -4,6 +4,10 @@
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
+ "blend": {
+ "enableLayer2": true,
+ "enableLayer3": true
+ },
"layer1_baseColor": {
"color": [
0.3495536744594574,
@@ -134,8 +138,14 @@
"enable": true
},
"uv": {
- "offsetU": -0.2800000011920929,
- "rotateDegrees": 39.599998474121097
+ "center": [
+ 0.10000000149011612,
+ 0.20000000298023225
+ ],
+ "offsetU": 0.23000000417232514,
+ "offsetV": -0.23999999463558198,
+ "rotateDegrees": 39.599998474121097,
+ "scale": 1.100000023841858
}
}
-}
+}
\ No newline at end of file
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer2Off.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer2Off.material
new file mode 100644
index 0000000000..d91cfb34eb
--- /dev/null
+++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer2Off.material
@@ -0,0 +1,11 @@
+{
+ "description": "",
+ "materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
+ "parentMaterial": "TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material",
+ "propertyLayoutVersion": 3,
+ "properties": {
+ "blend": {
+ "enableLayer2": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer3Off.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer3Off.material
new file mode 100644
index 0000000000..3ee48df612
--- /dev/null
+++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures_Layer3Off.material
@@ -0,0 +1,11 @@
+{
+ "description": "",
+ "materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
+ "parentMaterial": "TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material",
+ "propertyLayoutVersion": 3,
+ "properties": {
+ "blend": {
+ "enableLayer3": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material
index e7903a8c91..0bf4177db9 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material
@@ -4,6 +4,10 @@
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
+ "blend": {
+ "enableLayer2": true,
+ "enableLayer3": true
+ },
"layer1_baseColor": {
"textureMap": "TestData/Textures/cc0/bark1_col.jpg"
},
@@ -30,6 +34,7 @@
"layer2_parallax": {
"enable": true,
"factor": 0.05299999937415123,
+ "offset": -0.024000000208616258,
"textureMap": "TestData/Textures/cc0/Rock030_2K_Displacement.jpg"
},
"layer2_roughness": {
@@ -49,4 +54,4 @@
"pdo": true
}
}
-}
+}
\ No newline at end of file
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMaskValues.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material
similarity index 86%
rename from Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMaskValues.material
rename to Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material
index 94a1ec6a30..cdd21212c9 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendMaskValues.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/003_Debug_BlendSource.material
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"general": {
- "debugDrawMode": "BlendMaskValues"
+ "debugDrawMode": "BlendSource"
}
}
}
diff --git a/Gems/Atom/TestData/TestData/Objects/PaintedPlane.fbx b/Gems/Atom/TestData/TestData/Objects/PaintedPlane.fbx
new file mode 100644
index 0000000000..be30ca4639
--- /dev/null
+++ b/Gems/Atom/TestData/TestData/Objects/PaintedPlane.fbx
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:053a7cd73b37c815900f87abd524830e6f23eee75d3b72fb866e86498d528159
+size 36156
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h
index b17a25a675..17ca1c8d04 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h
@@ -38,8 +38,8 @@ namespace AtomToolsFramework
Count
};
- // Configures the initial state, data type, attributes, and values that describe
- // the dynamic property and how it is presented
+ //! Configures the initial state, data type, attributes, and values that describe
+ //! the dynamic property and how it is presented
struct DynamicPropertyConfig
{
AZ_TYPE_INFO(DynamicPropertyConfig, "{9CA40E92-7F03-42BE-B6AA-51F30EE5796C}");
@@ -98,7 +98,7 @@ namespace AtomToolsFramework
//! Returns true if the property has a valid value.
bool IsValid() const;
- //! Returns the ID of the property.
+ //! Returns the ID of the property.
const AZ::Name GetId() const;
//! Returns the current property visibility.
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h
index e76837137a..d9b626f631 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h
@@ -44,6 +44,17 @@ namespace AtomToolsFramework
const AZStd::string& groupDescription,
QWidget* groupWidget) = 0;
+ //! Sets the visibility of a specific property group. This impacts both the header and the widget.
+ virtual void SetGroupVisible(const AZStd::string& groupNameId, bool visible) = 0;
+
+ //! Returns whether a specific property is visible.
+ //! Note this follows the same rules as QWidget::isVisible(), meaning a group could be not visible due to the widget's parents being not visible.
+ virtual bool IsGroupVisible(const AZStd::string& groupNameId) const = 0;
+
+ //! Returns whether a specific property is explicitly hidden.
+ //! Note this follows the same rules as QWidget::isHidden(), meaning a group that is hidden will not become visible automatically when the parent becomes visible.
+ virtual bool IsGroupHidden(const AZStd::string& groupNameId) const = 0;
+
//! Calls Refresh for a specific InspectorGroupWidget, allowing for non-destructive UI changes
virtual void RefreshGroup(const AZStd::string& groupNameId) = 0;
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h
index 5fb0b731d6..5e41121b37 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h
@@ -57,6 +57,10 @@ namespace AtomToolsFramework
const AZStd::string& groupDescription,
QWidget* groupWidget) override;
+ void SetGroupVisible(const AZStd::string& groupNameId, bool visible) override;
+ bool IsGroupVisible(const AZStd::string& groupNameId) const override;
+ bool IsGroupHidden(const AZStd::string& groupNameId) const override;
+
void RefreshGroup(const AZStd::string& groupNameId) override;
void RebuildGroup(const AZStd::string& groupNameId) override;
@@ -79,6 +83,13 @@ namespace AtomToolsFramework
private:
QVBoxLayout* m_layout = nullptr;
QScopedPointer m_ui;
- AZStd::unordered_map> m_groups;
+
+ struct GroupWidgetPair
+ {
+ InspectorGroupHeaderWidget* m_header;
+ QWidget* m_panel;
+ };
+
+ AZStd::unordered_map m_groups;
};
} // namespace AtomToolsFramework
diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp
index 0259120d9b..097a819e49 100644
--- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp
+++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp
@@ -74,7 +74,7 @@ namespace AtomToolsFramework
groupWidget->setParent(m_ui->m_propertyContent);
m_layout->addWidget(groupWidget);
- m_groups[groupNameId] = AZStd::make_pair(groupHeader, groupWidget);
+ m_groups[groupNameId] = {groupHeader, groupWidget};
connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupNameId](QMouseEvent* event) {
OnHeaderClicked(groupNameId, event);
@@ -91,6 +91,38 @@ namespace AtomToolsFramework
CollapseGroup(groupNameId);
}
}
+
+ void InspectorWidget::SetGroupVisible(const AZStd::string& groupNameId, bool visible)
+ {
+ auto groupItr = m_groups.find(groupNameId);
+ if (groupItr != m_groups.end())
+ {
+ groupItr->second.m_header->setVisible(visible);
+ groupItr->second.m_panel->setVisible(visible && groupItr->second.m_header->IsExpanded());
+ }
+ }
+
+ bool InspectorWidget::IsGroupVisible(const AZStd::string& groupNameId) const
+ {
+ auto groupItr = m_groups.find(groupNameId);
+ if (groupItr != m_groups.end())
+ {
+ return groupItr->second.m_header->isVisible();
+ }
+
+ return false;
+ }
+
+ bool InspectorWidget::IsGroupHidden(const AZStd::string& groupNameId) const
+ {
+ auto groupItr = m_groups.find(groupNameId);
+ if (groupItr != m_groups.end())
+ {
+ return groupItr->second.m_header->isHidden();
+ }
+
+ return false;
+ }
void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId)
{
@@ -129,8 +161,8 @@ namespace AtomToolsFramework
auto groupItr = m_groups.find(groupNameId);
if (groupItr != m_groups.end())
{
- groupItr->second.first->SetExpanded(true);
- groupItr->second.second->setVisible(true);
+ groupItr->second.m_header->SetExpanded(true);
+ groupItr->second.m_panel->setVisible(true);
}
}
@@ -139,23 +171,23 @@ namespace AtomToolsFramework
auto groupItr = m_groups.find(groupNameId);
if (groupItr != m_groups.end())
{
- groupItr->second.first->SetExpanded(false);
- groupItr->second.second->setVisible(false);
+ groupItr->second.m_header->SetExpanded(false);
+ groupItr->second.m_panel->setVisible(false);
}
}
bool InspectorWidget::IsGroupExpanded(const AZStd::string& groupNameId) const
{
auto groupItr = m_groups.find(groupNameId);
- return groupItr != m_groups.end() ? groupItr->second.first->IsExpanded() : false;
+ return groupItr != m_groups.end() ? groupItr->second.m_header->IsExpanded() : false;
}
void InspectorWidget::ExpandAll()
{
for (auto& groupPair : m_groups)
{
- groupPair.second.first->SetExpanded(true);
- groupPair.second.second->setVisible(true);
+ groupPair.second.m_header->SetExpanded(true);
+ groupPair.second.m_panel->setVisible(true);
}
}
@@ -163,8 +195,8 @@ namespace AtomToolsFramework
{
for (auto& groupPair : m_groups)
{
- groupPair.second.first->SetExpanded(false);
- groupPair.second.second->setVisible(false);
+ groupPair.second.m_header->SetExpanded(false);
+ groupPair.second.m_panel->setVisible(false);
}
}
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentNotificationBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentNotificationBus.h
index 3c3c77a628..80e8054ec5 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentNotificationBus.h
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentNotificationBus.h
@@ -18,6 +18,7 @@
#include
#include
+#include
namespace MaterialEditor
{
@@ -77,6 +78,12 @@ namespace MaterialEditor
//! @param documentId unique id of material document for which the notification is sent
//! @param property object containing the property value and configuration that was modified
virtual void OnDocumentPropertyConfigModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {}
+
+ //! Signal that the property group visibility has been changed.
+ //! @param documentId unique id of material document for which the notification is sent
+ //! @param groupId id of the group that changed
+ //! @param visible whether the property group is visible
+ virtual void OnDocumentPropertyGroupVisibilityChanged([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AZ::Name& groupId, [[maybe_unused]] bool visible) {}
};
using MaterialDocumentNotificationBus = AZ::EBus;
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentRequestBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentRequestBus.h
index dad21a6348..c71d500d8c 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentRequestBus.h
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Document/MaterialDocumentRequestBus.h
@@ -19,6 +19,7 @@
#include
#include
+#include
namespace AZ
{
@@ -67,6 +68,10 @@ namespace MaterialEditor
//! Returns a property object
//! If the document is not open or the id can't be found, an invalid property is returned.
virtual const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const = 0;
+
+ //! Returns whether a property group is visible
+ //! If the document is not open or the id can't be found, returns false.
+ virtual bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const = 0;
//! Modify material property value
virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0;
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp
index 288530a4e4..fec70763dd 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp
@@ -117,6 +117,24 @@ namespace MaterialEditor
const AtomToolsFramework::DynamicProperty& property = it->second;
return property;
}
+
+ bool MaterialDocument::IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const
+ {
+ if (!IsOpen())
+ {
+ AZ_Error("MaterialDocument", false, "Material document is not open.");
+ return false;
+ }
+
+ const auto it = m_propertyGroupVisibility.find(propertyGroupFullName);
+ if (it == m_propertyGroupVisibility.end())
+ {
+ AZ_Error("MaterialDocument", false, "Material document property group could not be found: '%s'.", propertyGroupFullName.GetCStr());
+ return false;
+ }
+
+ return it->second;
+ }
void MaterialDocument::SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value)
{
@@ -153,8 +171,12 @@ namespace MaterialEditor
Recompile();
- AZStd::unordered_set changedPropertyNames = RunEditorMaterialFunctors(dirtyFlags);
- for (const Name& changedPropertyName : changedPropertyNames)
+ EditorMaterialFunctorResult result = RunEditorMaterialFunctors(dirtyFlags);
+ for (const Name& changedPropertyGroupName : result.m_updatedPropertyGroups)
+ {
+ MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyGroupVisibilityChanged, m_id, changedPropertyGroupName, IsPropertyGroupVisible(changedPropertyGroupName));
+ }
+ for (const Name& changedPropertyName : result.m_updatedProperties)
{
MaterialDocumentNotificationBus::Broadcast(&MaterialDocumentNotificationBus::Events::OnDocumentPropertyConfigModified, m_id, GetProperty(changedPropertyName));
}
@@ -782,6 +804,12 @@ namespace MaterialEditor
return true;
});
+ // Populate the property group visibility map
+ for (MaterialTypeSourceData::GroupDefinition& group : m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder())
+ {
+ m_propertyGroupVisibility[AZ::Name{group.m_nameId}] = true;
+ }
+
// Adding properties for material type and parent as part of making dynamic
// properties and the inspector more general purpose.
// This allows the read only properties to appear in the inspector like any
@@ -914,16 +942,26 @@ namespace MaterialEditor
}
}
- AZStd::unordered_set MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags)
+ MaterialDocument::EditorMaterialFunctorResult MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags)
{
- AZStd::unordered_set changedPropertyNames;
+ EditorMaterialFunctorResult result;
+
AZStd::unordered_map propertyDynamicMetadata;
+ AZStd::unordered_map propertyGroupDynamicMetadata;
for (auto& propertyPair : m_properties)
{
AtomToolsFramework::DynamicProperty& property = propertyPair.second;
AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig());
}
+ for (auto& groupPair : m_propertyGroupVisibility)
+ {
+ AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}];
+ bool visible = groupPair.second;
+ metadata.m_visibility = visible ?
+ AZ::RPI::MaterialPropertyGroupVisibility::Enabled : AZ::RPI::MaterialPropertyGroupVisibility::Hidden;
+ }
+
for (AZ::RPI::Ptr& functor : m_editorFunctors)
{
const AZ::RPI::MaterialPropertyFlags& materialPropertyDependencies = functor->GetMaterialPropertyDependencies();
@@ -935,7 +973,9 @@ namespace MaterialEditor
m_materialInstance->GetPropertyValues(),
m_materialInstance->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
- changedPropertyNames,
+ propertyGroupDynamicMetadata,
+ result.m_updatedProperties,
+ result.m_updatedPropertyGroups,
&materialPropertyDependencies
);
functor->Process(context);
@@ -950,7 +990,13 @@ namespace MaterialEditor
property.SetConfig(propertyConfig);
}
- return changedPropertyNames;
+ for (auto& updatedPropertyGroup : result.m_updatedPropertyGroups)
+ {
+ bool visible = propertyGroupDynamicMetadata[updatedPropertyGroup].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled;
+ m_propertyGroupVisibility[updatedPropertyGroup] = visible;
+ }
+
+ return result;
}
} // namespace MaterialEditor
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h
index 3959e45ad7..42f48c95cd 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h
@@ -56,6 +56,7 @@ namespace MaterialEditor
const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const override;
const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const override;
const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const override;
+ bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override;
void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) override;
bool Open(AZStd::string_view loadPath) override;
bool Rebuild() override;
@@ -79,11 +80,14 @@ namespace MaterialEditor
// Predicate for evaluating properties
using PropertyFilterFunction = AZStd::function;
- // Map of documenmt's property
+ // Map of document's properties
using PropertyMap = AZStd::unordered_map;
// Map of raw property values for undo/redo comparison and storage
using PropertyValueMap = AZStd::unordered_map;
+
+ // Map of document's property group visibility flags
+ using PropertyGroupVisibilityMap = AZStd::unordered_map;
// Function to be bound for undo and redo
using UndoRedoFunction = AZStd::function;
@@ -119,10 +123,16 @@ namespace MaterialEditor
void RestorePropertyValues(const PropertyValueMap& propertyValues);
+ struct EditorMaterialFunctorResult
+ {
+ AZStd::unordered_set m_updatedProperties;
+ AZStd::unordered_set m_updatedPropertyGroups;
+ };
+
// Run editor material functor to update editor metadata.
// @param dirtyFlags indicates which properties have changed, and thus which MaterialFunctors need to be run.
- // @return names for the set of properties that have been changed or need update.
- AZStd::unordered_set RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags);
+ // @return names for the set of properties and groups that have been changed or need update.
+ EditorMaterialFunctorResult RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags);
// Unique id of this material document
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
@@ -153,6 +163,9 @@ namespace MaterialEditor
// Collection of all material's properties
PropertyMap m_properties;
+
+ // Collection of all material's property groups
+ PropertyGroupVisibilityMap m_propertyGroupVisibility;
// Material functors that run in editor. See MaterialFunctor.h for details.
AZStd::vector> m_editorFunctors;
@@ -175,7 +188,7 @@ namespace MaterialEditor
int m_undoHistoryIndex = 0;
AZStd::any m_invalidValue;
-
+
AtomToolsFramework::DynamicProperty m_invalidProperty;
};
} // namespace MaterialEditor
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp
index 55e098962a..706d365027 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp
@@ -198,6 +198,11 @@ namespace MaterialEditor
&group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId),
[this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); });
AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget);
+
+ bool isGroupVisible = false;
+ MaterialDocumentRequestBus::EventResult(
+ isGroupVisible, m_documentId, &MaterialDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupNameId});
+ SetGroupVisible(groupNameId, isGroupVisible);
}
}
@@ -221,8 +226,7 @@ namespace MaterialEditor
}
}
- void MaterialInspector::OnDocumentPropertyConfigModified(
- const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property)
+ void MaterialInspector::OnDocumentPropertyConfigModified(const AZ::Uuid&, const AtomToolsFramework::DynamicProperty& property)
{
for (auto& groupPair : m_groups)
{
@@ -234,20 +238,23 @@ namespace MaterialEditor
if (reflectedProperty.GetVisibility() != property.GetVisibility())
{
reflectedProperty.SetConfig(property.GetConfig());
- AtomToolsFramework::InspectorRequestBus::Event(
- documentId, &AtomToolsFramework::InspectorRequestBus::Events::RebuildGroup, groupPair.first);
+ RebuildGroup(groupPair.first);
}
else
{
reflectedProperty.SetConfig(property.GetConfig());
- AtomToolsFramework::InspectorRequestBus::Event(
- documentId, &AtomToolsFramework::InspectorRequestBus::Events::RefreshGroup, groupPair.first);
+ RefreshGroup(groupPair.first);
}
return;
}
}
}
}
+
+ void MaterialInspector::OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid&, const AZ::Name& groupId, bool visible)
+ {
+ SetGroupVisible(groupId.GetStringView(), visible);
+ }
void MaterialInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode)
{
diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h
index f53e93a2f9..4080430ff5 100644
--- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h
+++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h
@@ -60,6 +60,7 @@ namespace MaterialEditor
void OnDocumentOpened(const AZ::Uuid& documentId) override;
void OnDocumentPropertyValueModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
void OnDocumentPropertyConfigModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override;
+ void OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid& documentId, const AZ::Name& groupId, bool visible) override;
// AzToolsFramework::IPropertyEditorNotify overrides...
void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;
diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl
index e7e743adda..23eb79650a 100644
--- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl
+++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl
@@ -269,13 +269,13 @@ namespace AZ
{
ImGui::BeginChild(heapMemoryId.c_str());
ImGui::SetScrollY(scrollingY);
- ImGui::End();
+ ImGui::EndChild();
}
{
ImGui::BeginChild(scopesId.c_str());
ImGui::SetScrollX(scrollingX);
- ImGui::End();
+ ImGui::EndChild();
}
ImGui::PopStyleVar(3);
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp
index 7f54e386fc..31d69569db 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp
@@ -296,15 +296,20 @@ namespace AZ
void MaterialPropertyInspector::RunEditorMaterialFunctors()
{
AZStd::unordered_set changedPropertyNames;
+ AZStd::unordered_set changedPropertyGroupNames;
// Convert editor property configuration data into material property meta data so that it can be used to execute functors
AZStd::unordered_map propertyDynamicMetadata;
- for (auto& group : m_groups)
+ AZStd::unordered_map propertyGroupDynamicMetadata;
+ for (auto& groupPair : m_groups)
{
- for (auto& property : group.second.m_properties)
- {
- AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig());
- }
+ AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}];
+
+ // It's significant that we check IsGroupHidden rather than IsGroupVisisble, because it follows the same rules as QWidget::isHidden().
+ // We don't care whether the widget and all its parents are visible, we only care about whether the group was hidden within the context
+ // of the material property inspector.
+ metadata.m_visibility = IsGroupHidden(groupPair.first) ?
+ AZ::RPI::MaterialPropertyGroupVisibility::Hidden : AZ::RPI::MaterialPropertyGroupVisibility::Enabled;
}
for (AZ::RPI::Ptr& functor : m_editorFunctors)
@@ -318,7 +323,9 @@ namespace AZ
m_materialInstance->GetPropertyValues(),
m_materialInstance->GetMaterialPropertiesLayout(),
propertyDynamicMetadata,
+ propertyGroupDynamicMetadata,
changedPropertyNames,
+ changedPropertyGroupNames,
&materialPropertyDependencies
);
functor->Process(context);
@@ -327,9 +334,16 @@ namespace AZ
m_dirtyPropertyFlags.reset();
// Apply any changes to material property meta data back to the editor property configurations
- for (auto& group : m_groups)
+ for (auto& groupPair : m_groups)
{
- for (auto& property : group.second.m_properties)
+ AZ::Name groupName{groupPair.first};
+
+ if (changedPropertyGroupNames.find(groupName) != changedPropertyGroupNames.end())
+ {
+ SetGroupVisible(groupPair.first, propertyGroupDynamicMetadata[groupName].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled);
+ }
+
+ for (auto& property : groupPair.second.m_properties)
{
AtomToolsFramework::DynamicPropertyConfig propertyConfig = property.GetConfig();
diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp
index 0bbfe17801..31884d4c94 100644
--- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp
+++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp
@@ -54,34 +54,15 @@ namespace Multiplayer
}
}
- static AZStd::vector GetEntitiesFromInstance(AZStd::unique_ptr& instance)
- {
- AZStd::vector result;
-
- instance->GetNestedEntities([&result](const AZStd::unique_ptr& entity) {
- result.emplace_back(entity.get());
- return true;
- });
-
- if (instance->HasContainerEntity())
- {
- auto containerEntityReference = instance->GetContainerEntity();
- result.emplace_back(&containerEntityReference->get());
- }
-
- return result;
- }
-
- void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab)
+ static AZStd::unique_ptr LoadInstanceFromPrefab(const PrefabDom& prefab)
{
using namespace AzToolsFramework::Prefab;
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr sourceInstance(aznew Instance());
- if (!PrefabDomUtils::LoadInstanceFromPrefabDom(*sourceInstance, prefab,
- PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId))
+ if (!PrefabDomUtils::LoadInstanceFromPrefabDom(*sourceInstance, prefab, PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId))
{
- PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
+ PrefabDomValueConstReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
AZStd::string errorMessage("NetworkPrefabProcessor: Failed to Load Prefab Instance from given Prefab Dom.");
if (sourceReference.has_value() && sourceReference->get().IsString() && sourceReference->get().GetStringLength() != 0)
@@ -90,6 +71,38 @@ namespace Multiplayer
errorMessage += AZStd::string::format("Prefab Source: %.*s", AZ_STRING_ARG(source));
}
AZ_Error("NetworkPrefabProcessor", false, errorMessage.c_str());
+ return nullptr;
+ }
+ return sourceInstance;
+ }
+
+ static void GatherNetEntities(
+ AzToolsFramework::Prefab::Instance* instance,
+ AZStd::vector>& output)
+ {
+ instance->GetEntities([instance, &output](AZStd::unique_ptr& prefabEntity)
+ {
+ if (prefabEntity->FindComponent())
+ {
+ output.push_back(AZStd::make_pair(prefabEntity.get(), instance));
+ }
+ return true;
+ });
+
+ instance->GetNestedInstances([&output](AZStd::unique_ptr& nestedInstance)
+ {
+ GatherNetEntities(nestedInstance.get(), output);
+ });
+ }
+
+ void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab)
+ {
+ using namespace AzToolsFramework::Prefab;
+
+ // convert Prefab DOM into Prefab Instance.
+ AZStd::unique_ptr sourceInstance = LoadInstanceFromPrefab(prefab);
+ if (!sourceInstance)
+ {
return;
}
@@ -105,36 +118,37 @@ namespace Multiplayer
auto&& [object, networkSpawnable] =
ProcessedObjectStore::Create(uniqueName, context.GetSourceUuid(), AZStd::move(serializer));
- // grab all nested entities from the Instance as source entities.
- AZStd::vector sourceEntities = GetEntitiesFromInstance(sourceInstance);
- AZStd::vector networkedEntityIds;
- networkedEntityIds.reserve(sourceEntities.size());
+ // Grab all net entities with their corresponding Instances to handle nested prefabs correctly
+ AZStd::vector> netEntities;
+ GatherNetEntities(sourceInstance.get(), netEntities);
- for (auto* sourceEntity : sourceEntities)
- {
- if (sourceEntity->FindComponent())
- {
- networkedEntityIds.push_back(sourceEntity->GetId());
- }
- }
-
- if (networkedEntityIds.empty())
+ if (netEntities.empty())
{
// No networked entities in the prefab, no need to do anything in this processor.
return;
}
+ // Instance container for net entities
AZStd::unique_ptr networkInstance(aznew Instance());
+ // Create an asset for our future network spawnable: this allows us to put references to the asset in the components
AZ::Data::Asset networkSpawnableAsset;
networkSpawnableAsset.Create(networkSpawnable->GetId());
networkSpawnableAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
- for (size_t entityIndex = 0; entityIndex < networkedEntityIds.size(); ++entityIndex)
- {
- AZ::EntityId entityId = networkedEntityIds[entityIndex];
+ // Each spawnable has a root meta-data entity at position 0, so starting net indices from 1
+ size_t netEntitiesIndexCounter = 1;
+
+ for (auto& entityInstancePair : netEntities)
+ {
+ AZ::Entity* prefabEntity = entityInstancePair.first;
+ Instance* instance = entityInstancePair.second;
+
+ AZ::EntityId entityId = prefabEntity->GetId();
+ AZ::Entity* netEntity = instance->DetachEntity(entityId).release();
+ AZ_Assert(netEntity, "Unable to detach entity %s [%s] from the source prefab instance",
+ prefabEntity->GetName().c_str(), entityId.ToString().c_str());
- AZ::Entity* netEntity = sourceInstance->DetachEntity(entityId).release();
// Net entity will need a new ID to avoid IDs collision
netEntity->SetId(AZ::Entity::MakeId());
networkInstance->AddEntity(*netEntity);
@@ -143,17 +157,21 @@ namespace Multiplayer
AZ::Entity* breadcrumbEntity = aznew AZ::Entity(entityId, netEntity->GetName());
breadcrumbEntity->SetRuntimeActiveByDefault(netEntity->IsRuntimeActiveByDefault());
+ // Marker component is responsible to spawning entities based on the index.
NetBindMarkerComponent* netBindMarkerComponent = breadcrumbEntity->CreateComponent();
- // Each spawnable has a root meta-data entity at position 0, so starting net indices from 1
- netBindMarkerComponent->SetNetEntityIndex(entityIndex + 1);
+ netBindMarkerComponent->SetNetEntityIndex(netEntitiesIndexCounter);
netBindMarkerComponent->SetNetworkSpawnableAsset(networkSpawnableAsset);
+
+ // Copy the transform component from the original entity to have the correct transform and parent-child relationship
AzFramework::TransformComponent* transformComponent = netEntity->FindComponent();
breadcrumbEntity->CreateComponent