Merge branch 'stabilization/2110' into Atom/santorac/MaterialEditorHandlesMissingTextures

This commit is contained in:
santorac
2021-11-17 12:15:57 -08:00
249 changed files with 3564 additions and 2053 deletions
@@ -0,0 +1,44 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <aws/cognito-identity/CognitoIdentityClient.h>
#include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
#include <aws/identity-management/auth/PersistentCognitoIdentityProvider.h>
namespace AWSClientAuth
{
//! Cognito Caching Credentials Provider implementation that is derived from AWS Native SDK.
//! For use with authenticated credentials.
class AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider
: public Aws::Auth::CognitoCachingCredentialsProvider
{
public:
AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider(
const std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider>& identityRepository,
const std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient>& cognitoIdentityClient = nullptr);
protected:
Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome GetCredentialsFromCognito() const override;
};
//! Cognito Caching Credentials Provider implementation that is eventually derived from AWS Native SDK.
//! For use with anonymous credentials.
class AWSClientAuthCachingAnonymousCredsProvider : public AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider
{
public:
AWSClientAuthCachingAnonymousCredsProvider(
const std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider>& identityRepository,
const std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient>& cognitoIdentityClient = nullptr);
protected:
Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome GetCredentialsFromCognito() const override;
};
} // namespace AWSClientAuth
@@ -9,6 +9,7 @@
#pragma once
#include <Authorization/AWSCognitoAuthorizationBus.h>
#include <Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h>
#include <Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h>
#include <Authentication/AuthenticationProviderBus.h>
#include <Credential/AWSCredentialBus.h>
@@ -51,8 +52,8 @@ namespace AWSClientAuth
std::shared_ptr<AWSClientAuthPersistentCognitoIdentityProvider> m_persistentCognitoIdentityProvider;
std::shared_ptr<AWSClientAuthPersistentCognitoIdentityProvider> m_persistentAnonymousCognitoIdentityProvider;
std::shared_ptr<Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider> m_cognitoCachingCredentialsProvider;
std::shared_ptr<Aws::Auth::CognitoCachingAnonymousCredentialsProvider> m_cognitoCachingAnonymousCredentialsProvider;
std::shared_ptr<AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider> m_cognitoCachingCredentialsProvider;
std::shared_ptr<AWSClientAuthCachingAnonymousCredsProvider> m_cognitoCachingAnonymousCredentialsProvider;
AZStd::string m_cognitoIdentityPoolId;
AZStd::string m_formattedCognitoUserPoolId;
@@ -0,0 +1,122 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h>
#include <AzCore/Debug/Trace.h>
#include <aws/cognito-identity/CognitoIdentityClient.h>
#include <aws/cognito-identity/model/GetCredentialsForIdentityRequest.h>
#include <aws/cognito-identity/model/GetIdRequest.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
#include <aws/identity-management/auth/PersistentCognitoIdentityProvider.h>
namespace AWSClientAuth
{
static const char* AUTH_LOG_TAG = "AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider";
static const char* ANON_LOG_TAG = "AWSClientAuthCachingAnonymousCredsProvider";
// Modification of https://github.com/aws/aws-sdk-cpp/blob/main/aws-cpp-sdk-identity-management/source/auth/CognitoCachingCredentialsProvider.cpp#L92
// to work around account ID requirement. Account id is not required for call to succeed and is not set unless provided.
// see: https://github.com/aws/aws-sdk-cpp/issues/1448
Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome FetchCredsFromCognito(
const Aws::CognitoIdentity::CognitoIdentityClient& cognitoIdentityClient,
Aws::Auth::PersistentCognitoIdentityProvider& identityRepository,
const char* logTag,
bool includeLogins)
{
auto logins = identityRepository.GetLogins();
Aws::Map<Aws::String, Aws::String> cognitoLogins;
for (auto& login : logins)
{
cognitoLogins[login.first] = login.second.accessToken;
}
if (!identityRepository.HasIdentityId())
{
auto accountId = identityRepository.GetAccountId();
auto identityPoolId = identityRepository.GetIdentityPoolId();
Aws::CognitoIdentity::Model::GetIdRequest getIdRequest;
getIdRequest.SetIdentityPoolId(identityPoolId);
if (!accountId.empty()) // new check
{
getIdRequest.SetAccountId(accountId);
AWS_LOGSTREAM_INFO(logTag, "Identity not found, requesting an id for accountId "
<< accountId << " identity pool id "
<< identityPoolId << " with logins.");
}
else
{
AWS_LOGSTREAM_INFO(
logTag, "Identity not found, requesting an id for identity pool id %s" << identityPoolId << " with logins.");
}
if (includeLogins)
{
getIdRequest.SetLogins(cognitoLogins);
}
auto getIdOutcome = cognitoIdentityClient.GetId(getIdRequest);
if (getIdOutcome.IsSuccess())
{
auto identityId = getIdOutcome.GetResult().GetIdentityId();
AWS_LOGSTREAM_INFO(logTag, "Successfully retrieved identity: " << identityId);
identityRepository.PersistIdentityId(identityId);
}
else
{
AWS_LOGSTREAM_ERROR(
logTag,
"Failed to retrieve identity. Error: " << getIdOutcome.GetError().GetExceptionName() << " "
<< getIdOutcome.GetError().GetMessage());
return Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome(getIdOutcome.GetError());
}
}
Aws::CognitoIdentity::Model::GetCredentialsForIdentityRequest getCredentialsForIdentityRequest;
getCredentialsForIdentityRequest.SetIdentityId(identityRepository.GetIdentityId());
if (includeLogins)
{
getCredentialsForIdentityRequest.SetLogins(cognitoLogins);
}
return cognitoIdentityClient.GetCredentialsForIdentity(getCredentialsForIdentityRequest);
}
AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider::AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider(
const std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider>& identityRepository,
const std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient>& cognitoIdentityClient)
: CognitoCachingCredentialsProvider(identityRepository, cognitoIdentityClient)
{
}
Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome
AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider::GetCredentialsFromCognito() const
{
return FetchCredsFromCognito(*m_cognitoIdentityClient, *m_identityRepository, AUTH_LOG_TAG, true);
}
AWSClientAuthCachingAnonymousCredsProvider::AWSClientAuthCachingAnonymousCredsProvider(
const std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider>& identityRepository,
const std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient>& cognitoIdentityClient)
: AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider(identityRepository, cognitoIdentityClient)
{
}
Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome AWSClientAuthCachingAnonymousCredsProvider::
GetCredentialsFromCognito() const
{
return FetchCredsFromCognito(*m_cognitoIdentityClient, *m_identityRepository, ANON_LOG_TAG, false);
}
} // namespace AWSClientAuth
@@ -8,6 +8,7 @@
#include <AWSClientAuthBus.h>
#include <AWSCoreBus.h>
#include <Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h>
#include <Authorization/AWSCognitoAuthorizationController.h>
#include <ResourceMapping/AWSResourceMappingBus.h>
#include <AWSClientAuthResourceMappingConstants.h>
@@ -38,10 +39,12 @@ namespace AWSClientAuth
auto identityClient = AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIdentityClient();
m_cognitoCachingCredentialsProvider =
std::make_shared<Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider>(m_persistentCognitoIdentityProvider, identityClient);
std::make_shared<AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider>(
m_persistentCognitoIdentityProvider, identityClient);
m_cognitoCachingAnonymousCredentialsProvider =
std::make_shared<Aws::Auth::CognitoCachingAnonymousCredentialsProvider>(m_persistentAnonymousCognitoIdentityProvider, identityClient);
std::make_shared<AWSClientAuthCachingAnonymousCredsProvider>(
m_persistentAnonymousCognitoIdentityProvider, identityClient);
}
AWSCognitoAuthorizationController::~AWSCognitoAuthorizationController()
@@ -65,9 +68,13 @@ namespace AWSClientAuth
AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
m_cognitoIdentityPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoIdentityPoolIdResourceMappingKey);
if (m_awsAccountId.empty() || m_cognitoIdentityPoolId.empty())
if (m_awsAccountId.empty())
{
AZ_TracePrintf("AWSCognitoAuthorizationController", "AWS account id not not configured. Proceeding without it.");
}
if (m_cognitoIdentityPoolId.empty())
{
AZ_Warning("AWSCognitoAuthorizationController", !m_awsAccountId.empty(), "Missing AWS account id not configured.");
AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings.");
return false;
}
@@ -62,6 +62,14 @@ TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Success)
ASSERT_TRUE(m_mockController->m_cognitoIdentityPoolId == AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID);
}
TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Success_GetAWSAccountEmpty)
{
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(2);
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1).WillOnce(testing::Return(""));
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(1);
ASSERT_TRUE(m_mockController->Initialize());
}
TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_WithLogins_Success)
{
AWSClientAuth::AuthenticationTokens tokens(
@@ -121,7 +129,7 @@ TEST_F(AWSCognitoAuthorizationControllerTest, MultipleCalls_UsesCacheCredentials
m_mockController->RequestAWSCredentialsAsync();
}
TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_Fail_GetIdError)
TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_Fail_GetIdError) // fail
{
AWSClientAuth::AuthenticationTokens cognitoTokens(
AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN,
@@ -321,7 +329,7 @@ TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersisted
EXPECT_TRUE(actualCredentialsProvider == m_mockController->m_cognitoCachingAnonymousCredentialsProvider);
}
TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersistedLogins_NoAnonymousCredentials_ResultNullPtr)
TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersistedLogins_NoAnonymousCredentials_ResultNullPtr) // fails
{
Aws::Client::AWSError<Aws::CognitoIdentity::CognitoIdentityErrors> error;
error.SetExceptionName(AWSClientAuthUnitTest::TEST_EXCEPTION);
@@ -431,11 +439,3 @@ TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetResourceNameEmp
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1);
ASSERT_FALSE(m_mockController->Initialize());
}
TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetAWSAccountEmpty)
{
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1);
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1).WillOnce(testing::Return(""));
EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(0);
ASSERT_FALSE(m_mockController->Initialize());
}
@@ -24,6 +24,7 @@ set(FILES
Include/Private/Authorization/AWSCognitoAuthorizationController.h
Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h
Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h
Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h
Include/Private/UserManagement/AWSCognitoUserManagementController.h
Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h
@@ -45,6 +46,7 @@ set(FILES
Source/Authorization/ClientAuthAWSCredentials.cpp
Source/Authorization/AWSCognitoAuthorizationController.cpp
Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.cpp
Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp
Source/UserManagement/AWSCognitoUserManagementController.cpp
)
+16
View File
@@ -65,6 +65,22 @@ them to your `setup.py` file and rerun the `pip install -r requirements.txt`
command.
## Optional Features
Optional features are activated by passing [runtime context variables](https://docs.aws.amazon.com/cdk/latest/guide/context.html). To use multiple optional features together provide one key-value pair at a time:
```
cdk synth --context key1=value1 --context key2=value2 MyStack
```
### Automatic S3 and DynamoDB Cleanup
The S3 bucket and Dynamodb created by the sample will be left behind as the CDK defaults to retaining such storage (both have default policies to retain resources on destroy). To delete
the storage resources created when using CDK destroy, use the following commands to synthesize and destroy the CDK application.
```
cdk synth -c remove_all_storage_on_destroy=true --all
cdk deploy -c remove_all_storage_on_destroy=true --all
cdk destroy --all
```
### Server Access Logging
Server access logging is enabled by default. To disable the feature, use the following commands to synthesize and deploy this CDK application.
```
+9 -1
View File
@@ -86,13 +86,21 @@ class CoreStack(core.Stack):
# Create an S3 bucket for Amazon S3 server access logging
# See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html
if self.node.try_get_context('disable_access_log') != 'true':
# Auto cleanup bucket and data if requested
_remove_storage = self.node.try_get_context('remove_all_storage_on_destroy') == 'true'
_removal_policy = core.RemovalPolicy.DESTROY if _remove_storage else core.RemovalPolicy.RETAIN
self._server_access_logs_bucket = s3.Bucket(
self,
f'{self._project_name}-{self._feature_name}-Access-Log-Bucket',
access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE,
auto_delete_objects = _remove_storage,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE
removal_policy=_removal_policy
)
self._server_access_logs_bucket.grant_read(self._admin_group)
# Export access log bucket name
@@ -126,11 +126,17 @@ class ExampleResources(core.Stack):
core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket")
)
# Auto cleanup bucket and data if requested
_remove_storage = self.node.try_get_context('remove_all_storage_on_destroy') == 'true'
_removal_policy = core.RemovalPolicy.DESTROY if _remove_storage else core.RemovalPolicy.RETAIN
example_bucket = s3.Bucket(
self,
f'{self._project_name}-{self._feature_name}-Example-S3bucket',
auto_delete_objects=_remove_storage,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
removal_policy=_removal_policy,
server_access_logs_bucket=
server_access_logs_bucket if server_access_logs_bucket else None,
server_access_logs_prefix=
@@ -170,6 +176,11 @@ class ExampleResources(core.Stack):
type=dynamo.AttributeType.STRING
)
)
# Auto-delete the table when requested
if self.node.try_get_context('remove_all_storage_on_destroy') == 'true':
demo_table.apply_removal_policy(core.RemovalPolicy.DESTROY)
return demo_table
def __create_outputs(self) -> None:
@@ -7,16 +7,6 @@
"UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}",
"Name": "Albedo",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_basecolor",
"_diff",
"_color",
"_col",
"_albedo",
"_alb",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -29,16 +19,6 @@
"UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}",
"Name": "Albedo",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_col",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
@@ -51,16 +31,6 @@
"UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}",
"Name": "Albedo",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_col",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
@@ -73,16 +43,6 @@
"UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}",
"Name": "Albedo",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_col",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -94,16 +54,6 @@
"UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}",
"Name": "Albedo",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_col",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -7,15 +7,6 @@
"UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}",
"Name": "AlbedoWithCoverage",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1a",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -27,15 +18,6 @@
"UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}",
"Name": "AlbedoWithCoverage",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -46,15 +28,6 @@
"UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}",
"Name": "AlbedoWithCoverage",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -65,15 +38,6 @@
"UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}",
"Name": "AlbedoWithCoverage",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1a",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -84,15 +48,6 @@
"UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}",
"Name": "AlbedoWithCoverage",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC1a",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -7,17 +7,7 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC3",
"IsPowerOf2": true,
"PixelFormat": "ASTC_4x4",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -27,18 +17,8 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -47,18 +27,8 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -67,17 +37,7 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC3",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -86,17 +46,7 @@
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
"Name": "AlbedoWithGenericAlpha",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_diff",
"_color",
"_albedo",
"_alb",
"_basecolor",
"_bc",
"_diffuse"
],
"PixelFormat": "BC3",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -8,12 +8,6 @@
"Name": "AmbientOcclusion",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ao",
"_ambocc",
"_amb",
"_ambientocclusion"
],
"PixelFormat": "BC4"
},
"PlatformsPresets": {
@@ -22,12 +16,6 @@
"Name": "AmbientOcclusion",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ao",
"_ambocc",
"_amb",
"_ambientocclusion"
],
"MaxTextureSize": 2048,
"PixelFormat": "ASTC_4x4"
},
@@ -36,12 +24,6 @@
"Name": "AmbientOcclusion",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ao",
"_ambocc",
"_amb",
"_ambientocclusion"
],
"MaxTextureSize": 2048,
"PixelFormat": "ASTC_4x4"
},
@@ -50,12 +32,6 @@
"Name": "AmbientOcclusion",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ao",
"_ambocc",
"_amb",
"_ambientocclusion"
],
"PixelFormat": "BC4"
},
"provo": {
@@ -63,12 +39,6 @@
"Name": "AmbientOcclusion",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ao",
"_ambocc",
"_amb",
"_ambientocclusion"
],
"PixelFormat": "BC4"
}
}
@@ -8,10 +8,6 @@
"Name": "ConvolvedCubemap",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ccm",
"_convolvedcubemap"
],
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
@@ -35,10 +31,6 @@
"Name": "ConvolvedCubemap",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ccm",
"_convolvedcubemap"
],
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
@@ -61,10 +53,6 @@
"Name": "ConvolvedCubemap",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ccm",
"_convolvedcubemap"
],
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
@@ -87,10 +75,6 @@
"Name": "ConvolvedCubemap",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ccm",
"_convolvedcubemap"
],
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
@@ -113,10 +97,6 @@
"Name": "ConvolvedCubemap",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ccm",
"_convolvedcubemap"
],
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
@@ -6,9 +6,6 @@
"DefaultPreset": {
"UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}",
"Name": "Decal_AlbedoWithOpacity",
"FileMasks": [
"_decal"
],
"PixelFormat": "BC7t",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -21,9 +18,6 @@
"android": {
"UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}",
"Name": "Decal_AlbedoWithOpacity",
"FileMasks": [
"_decal"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
@@ -36,9 +30,6 @@
"ios": {
"UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}",
"Name": "Decal_AlbedoWithOpacity",
"FileMasks": [
"_decal"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
@@ -51,9 +42,6 @@
"mac": {
"UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}",
"Name": "Decal_AlbedoWithOpacity",
"FileMasks": [
"_decal"
],
"PixelFormat": "BC3",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -65,9 +53,6 @@
"provo": {
"UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}",
"Name": "Decal_AlbedoWithOpacity",
"FileMasks": [
"_decal"
],
"PixelFormat": "BC7t",
"IsPowerOf2": true,
"MipMapSetting": {
@@ -8,18 +8,6 @@
"Name": "Displacement",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_displ",
"_disp",
"_dsp",
"_d",
"_dm",
"_displacement",
"_height",
"_hm",
"_ht",
"_h"
],
"PixelFormat": "BC4",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -33,18 +21,6 @@
"Name": "Displacement",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_displ",
"_disp",
"_dsp",
"_d",
"_dm",
"_displacement",
"_height",
"_hm",
"_ht",
"_h"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
@@ -59,18 +35,6 @@
"Name": "Displacement",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_displ",
"_disp",
"_dsp",
"_d",
"_dm",
"_displacement",
"_height",
"_hm",
"_ht",
"_h"
],
"PixelFormat": "ASTC_4x4",
"MaxTextureSize": 2048,
"DiscardAlpha": true,
@@ -84,18 +48,6 @@
"Name": "Displacement",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_displ",
"_disp",
"_dsp",
"_d",
"_dm",
"_displacement",
"_height",
"_hm",
"_ht",
"_h"
],
"PixelFormat": "BC4",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -108,18 +60,6 @@
"Name": "Displacement",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_displ",
"_disp",
"_dsp",
"_d",
"_dm",
"_displacement",
"_height",
"_hm",
"_ht",
"_h"
],
"PixelFormat": "BC4",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -7,13 +7,6 @@
"UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}",
"Name": "Emissive",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_emissive",
"_e",
"_glow",
"_em",
"_emit"
],
"PixelFormat": "BC7",
"DiscardAlpha": true
},
@@ -22,13 +15,6 @@
"UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}",
"Name": "Emissive",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_emissive",
"_e",
"_glow",
"_em",
"_emit"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true
@@ -37,13 +23,6 @@
"UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}",
"Name": "Emissive",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_emissive",
"_e",
"_glow",
"_em",
"_emit"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"DiscardAlpha": true
@@ -52,13 +31,6 @@
"UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}",
"Name": "Emissive",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_emissive",
"_e",
"_glow",
"_em",
"_emit"
],
"PixelFormat": "BC7",
"DiscardAlpha": true
},
@@ -66,13 +38,6 @@
"UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}",
"Name": "Emissive",
"RGB_Weight": "CIEXYZ",
"FileMasks": [
"_emissive",
"_e",
"_glow",
"_em",
"_emit"
],
"PixelFormat": "BC7",
"DiscardAlpha": true
}
@@ -8,11 +8,8 @@
"Name": "Greyscale",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_mask"
],
"PixelFormat": "BC4",
"IsPowerOf2": true,
"Swizzle": "rrr1",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -23,11 +20,8 @@
"Name": "Greyscale",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_mask"
],
"PixelFormat": "ASTC_4x4",
"IsPowerOf2": true,
"Swizzle": "rrr1",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -37,11 +31,8 @@
"Name": "Greyscale",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_mask"
],
"PixelFormat": "ASTC_4x4",
"IsPowerOf2": true,
"Swizzle": "rrr1",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -51,11 +42,8 @@
"Name": "Greyscale",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_mask"
],
"PixelFormat": "BC4",
"IsPowerOf2": true,
"Swizzle": "rrr1",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -65,11 +53,8 @@
"Name": "Greyscale",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_mask"
],
"PixelFormat": "BC4",
"IsPowerOf2": true,
"Swizzle": "rrr1",
"MipMapSetting": {
"MipGenType": "Box"
}
@@ -7,9 +7,6 @@
"UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}",
"Name": "IBLDiffuse",
"Description": "The input cubemap generates an IBL diffuse output cubemap.",
"FileMasks": [
"_ibldiffusecm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -31,9 +28,6 @@
"android": {
"UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}",
"Name": "IBLDiffuse",
"FileMasks": [
"_ibldiffusecm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -54,9 +48,6 @@
"ios": {
"UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}",
"Name": "IBLDiffuse",
"FileMasks": [
"_ibldiffusecm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -77,9 +68,6 @@
"mac": {
"UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}",
"Name": "IBLDiffuse",
"FileMasks": [
"_ibldiffusecm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -100,9 +88,6 @@
"provo": {
"UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}",
"Name": "IBLDiffuse",
"FileMasks": [
"_ibldiffusecm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -8,11 +8,6 @@
"Name": "IBLGlobal",
"Description": "The input cubemap generates IBL specular and diffuse cubemaps.",
"GenerateIBLOnly": true,
"FileMasks": [
"_iblglobalcm",
"_cubemap",
"_cm"
],
"CubemapSettings": {
"GenerateIBLSpecular": true,
"IBLSpecularPreset": "IBLSpecular",
@@ -7,9 +7,6 @@
"UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}",
"Name": "IBLSkybox",
"Description": "The input cubemap generates a skybox, IBL specular, and IBL diffuse output cubemaps.",
"FileMasks": [
"_iblskyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -29,9 +26,6 @@
"android": {
"UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}",
"Name": "IBLSkybox",
"FileMasks": [
"_iblskyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -50,9 +44,6 @@
"ios": {
"UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}",
"Name": "IBLSkybox",
"FileMasks": [
"_iblskyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -71,9 +62,6 @@
"mac": {
"UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}",
"Name": "IBLSkybox",
"FileMasks": [
"_iblskyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -92,9 +80,6 @@
"provo": {
"UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}",
"Name": "IBLSkybox",
"FileMasks": [
"_iblskyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -7,10 +7,6 @@
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -34,10 +30,6 @@
"android": {
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -60,10 +52,6 @@
"ios": {
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -86,10 +74,6 @@
"mac": {
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -112,10 +96,6 @@
"provo": {
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -7,9 +7,6 @@
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -33,9 +30,6 @@
"android": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -58,9 +52,6 @@
"ios": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -83,9 +74,6 @@
"mac": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -108,9 +96,6 @@
"provo": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -7,9 +7,6 @@
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -33,9 +30,6 @@
"android": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -58,9 +52,6 @@
"ios": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -83,9 +74,6 @@
"mac": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -108,9 +96,6 @@
"provo": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -7,9 +7,6 @@
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -33,9 +30,6 @@
"android": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -58,9 +52,6 @@
"ios": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -83,9 +74,6 @@
"mac": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -108,9 +96,6 @@
"provo": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -7,9 +7,6 @@
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -33,9 +30,6 @@
"android": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -58,9 +52,6 @@
"ios": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -83,9 +74,6 @@
"mac": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -108,9 +96,6 @@
"provo": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -0,0 +1,154 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "BuilderSettingManager",
"ClassData": {
"BuildSettings": {
"android": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"ios": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"mac": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"pc": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"linux": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"provo": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": false
}
},
"PresetsByFileMask": {
// albedo
"_basecolor": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_diff": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_diffuse": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_color": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_col": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_albedo": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_alb": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
"_bc": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ],
// normals
"_ddn": [ "Normals" ],
"_normal": [ "Normals" ],
"_normalmap": [ "Normals" ],
"_normals": [ "Normals" ],
"_norm": [ "Normals" ],
"_nor": [ "Normals" ],
"_nrm": [ "Normals" ],
"_nm": [ "Normals" ],
"_n": [ "Normals" ],
"_ddna": [ "NormalsWithSmoothness" ],
"_normala": [ "NormalsWithSmoothness" ],
"_nrma": [ "NormalsWithSmoothness" ],
"_nma": [ "NormalsWithSmoothness" ],
"_na": [ "NormalsWithSmoothness" ],
// refelctance
"_spec": [ "Reflectance" ],
"_specular": [ "Reflectance" ],
"_metallic": [ "Reflectance" ],
"_refl": [ "Reflectance" ],
"_ref": [ "Reflectance" ],
"_rf": [ "Reflectance" ],
"_gloss": [ "Reflectance" ],
"_g": [ "Reflectance" ],
"_f0": [ "Reflectance" ],
"_specf0": [ "Reflectance" ],
"_metal": [ "Reflectance" ],
"_mtl": [ "Reflectance" ],
"_m": [ "Reflectance" ],
"_mt": [ "Reflectance" ],
"_metalness": [ "Reflectance" ],
"_rough": [ "Reflectance" ],
"_roughness": [ "Reflectance" ],
// opacity
"_sss": [ "Opacity" ],
"_trans": [ "Opacity" ],
"_opac": [ "Opacity" ],
"_opacity": [ "Opacity" ],
"_o": [ "Opacity" ],
"_op": [ "Opacity" ],
"_mask": [ "Opacity", "Greyscale" ],
"_msk": [ "Opacity" ],
"_blend": [ "Opacity" ],
// AO
"_ao": [ "AmbientOcclusion" ],
"_ambocc": [ "AmbientOcclusion" ],
"_amb": [ "AmbientOcclusion" ],
"_ambientocclusion": [ "AmbientOcclusion" ],
// emissive
"_emissive": [ "Emissive" ],
"_e": [ "Emissive" ],
"_glow": [ "Emissive" ],
"_em": [ "Emissive" ],
"_emit": [ "Emissive" ],
// displacement
"_displ": [ "Displacement" ],
"_disp": [ "Displacement" ],
"_dsp": [ "Displacement" ],
"_d": [ "Displacement" ],
"_dm": [ "Displacement" ],
"_displacement": [ "Displacement" ],
"_height": [ "Displacement" ],
"_hm": [ "Displacement" ],
"_ht": [ "Displacement" ],
"_h": [ "Displacement" ],
// cubemap
"_ibldiffusecm": [ "IBLDiffuse" ],
"_iblskyboxcm": [ "IBLSkybox" ],
"_iblspecularcm": [ "IBLSpecular" ],
"_iblspecularcm64": [ "IBLSpecularVeryLow" ],
"_iblspecularcm128": [ "IBLSpecularLow" ],
"_iblspecularcm256": [ "IBLSpecular" ],
"_iblspecularcm512": [ "IBLSpecularHigh" ],
"_iblspecularcm1024": [ "IBLSpecularVeryHigh" ],
"_skyboxcm": [ "Skybox" ],
"_ccm": [ "ConvolvedCubemap" ],
"_convolvedcubemap": [ "ConvolvedCubemap" ],
"_iblglobalcm": [ "IBLGlobal" ],
"_cubemap": [ "IBLGlobal" ],
"_cm": [ "IBLGlobal" ],
// lut
"_lut": [ "LUT_RG8" ],
"_lutr32f": [ "LUT_R32F" ],
"_lutrgba8": [ "LUT_RGBA8" ],
"_lutrgba16": [ "LUT_RGBA16" ],
"_lutrgba16f": [ "LUT_RGBA16F" ],
"_lutrg16": [ "LUT_RG16" ],
"_lutrg32f": [ "LUT_RG32F" ],
"_lutrgba32f": [ "LUT_RGBA32F" ],
// layer mask
"_layers": [ "LayerMask" ],
"_rgbmask": [ "LayerMask" ],
// decal
"_decal": [ "Decal_AlbedoWithOpacity" ],
// ui
"_ui": [ "UserInterface_Compressed","UserInterface_Lossless" ]
},
"DefaultPreset": "Albedo",
"DefaultPresetAlpha": "AlbedoWithGenericAlpha"
}
}
@@ -6,7 +6,6 @@
"DefaultPreset": {
"UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}",
"Name": "LUT_R32F",
"FileMasks": ["_lutr32f"],
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32F"
@@ -6,7 +6,6 @@
"DefaultPreset": {
"UUID": "{52470B8B-0798-4E03-B0D3-039D5141CFEC}",
"Name": "LUT_RG32F",
"FileMasks": ["_lutrg32f"],
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32G32F"
@@ -8,9 +8,6 @@
"Name": "LUT_RG8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lut"
],
"PixelFormat": "R8G8"
},
"PlatformsPresets": {
@@ -19,9 +16,6 @@
"Name": "LUT_RG8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lut"
],
"PixelFormat": "R8G8"
},
"ios": {
@@ -29,9 +23,6 @@
"Name": "LUT_RG8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lut"
],
"PixelFormat": "R8G8"
},
"mac": {
@@ -39,9 +30,6 @@
"Name": "LUT_RG8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lut"
],
"PixelFormat": "R8G8"
},
"provo": {
@@ -49,9 +37,6 @@
"Name": "LUT_RG8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lut"
],
"PixelFormat": "R8G8"
}
}
@@ -8,9 +8,6 @@
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"PlatformsPresets": {
@@ -19,9 +16,6 @@
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"ios": {
@@ -29,9 +23,6 @@
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"osx_gl": {
@@ -39,9 +30,6 @@
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
},
"provo": {
@@ -49,9 +37,6 @@
"Name": "LUT_RGBA16",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16"
],
"PixelFormat": "R16G16B16A16"
}
}
@@ -8,9 +8,6 @@
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"PlatformsPresets": {
@@ -19,9 +16,6 @@
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"ios": {
@@ -29,9 +23,6 @@
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"osx_gl": {
@@ -39,9 +30,6 @@
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
},
"provo": {
@@ -49,9 +37,6 @@
"Name": "LUT_RGBA16F",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_lutrgba16f"
],
"PixelFormat": "R16G16B16A16F"
}
}
@@ -6,7 +6,6 @@
"DefaultPreset": {
"UUID": "{AC4C49D4-2C70-425A-8DBF-E7FB2C61CF8D}",
"Name": "LUT_RGBA32F",
"FileMasks": ["_lutrgba32f"],
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "R32G32B32A32F"
@@ -8,10 +8,6 @@
"Name": "LayerMask",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_layers",
"_rgbmask"
],
"PixelFormat": "R8G8B8X8"
},
"PlatformsPresets": {
@@ -20,10 +16,6 @@
"Name": "LayerMask",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_layers",
"_rgbmask"
],
"PixelFormat": "R8G8B8X8"
},
"ios": {
@@ -31,10 +23,6 @@
"Name": "LayerMask",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_layers",
"_rgbmask"
],
"PixelFormat": "R8G8B8X8"
},
"mac": {
@@ -42,10 +30,6 @@
"Name": "LayerMask",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_layers",
"_rgbmask"
],
"PixelFormat": "R8G8B8X8"
},
"provo": {
@@ -53,10 +37,6 @@
"Name": "LayerMask",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_layers",
"_rgbmask"
],
"PixelFormat": "R8G8B8X8"
}
}
@@ -8,17 +8,6 @@
"Name": "Normals",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddn",
"_normal",
"_normalmap",
"_normals",
"_norm",
"_nor",
"_nrm",
"_nm",
"_n"
],
"PixelFormat": "BC5s",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -33,17 +22,6 @@
"Name": "Normals",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddn",
"_normal",
"_normalmap",
"_normals",
"_norm",
"_nor",
"_nrm",
"_nm",
"_n"
],
"PixelFormat": "ASTC_4x4",
"DiscardAlpha": true,
"MaxTextureSize": 1024,
@@ -58,17 +36,6 @@
"Name": "Normals",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddn",
"_normal",
"_normalmap",
"_normals",
"_norm",
"_nor",
"_nrm",
"_nm",
"_n"
],
"PixelFormat": "ASTC_4x4",
"DiscardAlpha": true,
"MaxTextureSize": 1024,
@@ -83,17 +50,6 @@
"Name": "Normals",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddn",
"_normal",
"_normalmap",
"_normals",
"_norm",
"_nor",
"_nrm",
"_nm",
"_n"
],
"PixelFormat": "BC5s",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -107,17 +63,6 @@
"Name": "Normals",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddn",
"_normal",
"_normalmap",
"_normals",
"_norm",
"_nor",
"_nrm",
"_nm",
"_n"
],
"PixelFormat": "BC5s",
"DiscardAlpha": true,
"IsPowerOf2": true,
@@ -8,13 +8,6 @@
"Name": "NormalsWithSmoothness",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddna",
"_normala",
"_nrma",
"_nma",
"_na"
],
"PixelFormat": "BC5s",
"PixelFormatAlpha": "BC4",
"IsPowerOf2": true,
@@ -30,13 +23,6 @@
"Name": "NormalsWithSmoothness",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddna",
"_normala",
"_nrma",
"_nma",
"_na"
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
@@ -52,13 +38,6 @@
"Name": "NormalsWithSmoothness",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddna",
"_normala",
"_nrma",
"_nma",
"_na"
],
"PixelFormat": "ASTC_4x4",
"PixelFormatAlpha": "ASTC_4x4",
"MaxTextureSize": 2048,
@@ -74,13 +53,6 @@
"Name": "NormalsWithSmoothness",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddna",
"_normala",
"_nrma",
"_nma",
"_na"
],
"PixelFormat": "BC5s",
"PixelFormatAlpha": "BC4",
"IsPowerOf2": true,
@@ -95,13 +67,6 @@
"Name": "NormalsWithSmoothness",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_ddna",
"_normala",
"_nrma",
"_nma",
"_na"
],
"PixelFormat": "BC5s",
"PixelFormatAlpha": "BC4",
"IsPowerOf2": true,
@@ -8,19 +8,8 @@
"Name": "Opacity",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_sss",
"_trans",
"_opac",
"_opacity",
"_o",
"_opac",
"_op",
"_mask",
"_msk",
"_blend"
],
"PixelFormat": "BC4",
"Swizzle": "rrr1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -32,19 +21,8 @@
"Name": "Opacity",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_sss",
"_trans",
"_opac",
"_opacity",
"_o",
"_opac",
"_op",
"_mask",
"_msk",
"_blend"
],
"PixelFormat": "ASTC_4x4",
"Swizzle": "rrr1",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
@@ -56,19 +34,8 @@
"Name": "Opacity",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_sss",
"_trans",
"_opac",
"_opacity",
"_o",
"_opac",
"_op",
"_mask",
"_msk",
"_blend"
],
"PixelFormat": "ASTC_4x4",
"Swizzle": "rrr1",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
@@ -80,19 +47,8 @@
"Name": "Opacity",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_sss",
"_trans",
"_opac",
"_opacity",
"_o",
"_opac",
"_op",
"_mask",
"_msk",
"_blend"
],
"PixelFormat": "BC4",
"Swizzle": "rrr1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -103,19 +59,8 @@
"Name": "Opacity",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_sss",
"_trans",
"_opac",
"_opacity",
"_o",
"_opac",
"_op",
"_mask",
"_msk",
"_blend"
],
"PixelFormat": "BC4",
"Swizzle": "rrr1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
@@ -0,0 +1,68 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "BC4",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "ASTC_6x6",
"Swizzle": "rrr1",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "ASTC_6x6",
"Swizzle": "rrr1",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "BC4",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"PixelFormat": "BC4",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -6,9 +6,6 @@
"DefaultPreset": {
"UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}",
"Name": "Skybox",
"FileMasks": [
"_skyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -24,9 +21,6 @@
"android": {
"UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}",
"Name": "Skybox",
"FileMasks": [
"_skyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -41,9 +35,6 @@
"ios": {
"UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}",
"Name": "Skybox",
"FileMasks": [
"_skyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -58,9 +49,6 @@
"mac": {
"UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}",
"Name": "Skybox",
"FileMasks": [
"_skyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -75,9 +63,6 @@
"provo": {
"UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}",
"Name": "Skybox",
"FileMasks": [
"_skyboxcm"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
@@ -9,8 +9,7 @@
"SuppressEngineReduce": true,
"PixelFormat": "R8G8B8A8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [ "_ui" ]
"DestColor": "Linear"
},
"PlatformsPresets": {
"android": {
@@ -9,8 +9,7 @@
"SuppressEngineReduce": true,
"PixelFormat": "R8G8B8A8",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [ "_ui" ]
"DestColor": "Linear"
},
"PlatformsPresets": {
"android": {
@@ -8,6 +8,7 @@
#include "BuilderSettingManager.h"
#include <QCoreApplication>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
@@ -17,8 +18,9 @@
#include <BuilderSettings/CubemapSettings.h>
#include <BuilderSettings/TextureSettings.h>
#include <Converters/Cubemap.h>
#include <Processing/PixelFormatInfo.h>
#include <Processing/ImageToProcess.h>
#include <Processing/PixelFormatInfo.h>
#include <Processing/Utils.h>
#include <ImageLoader/ImageLoaders.h>
#include <ImageProcessing_Traits_Platform.h>
@@ -41,13 +43,18 @@
namespace ImageProcessingAtom
{
const char* BuilderSettingManager::s_defaultConfigRelativeFolder = "Gems/Atom/Asset/ImageProcessingAtom/Config/";
const char* BuilderSettingManager::s_defaultConfigRelativeFolder = "Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/";
const char* BuilderSettingManager::s_projectConfigRelativeFolder = "Config/AtomImageBuilder/";
const char* BuilderSettingManager::s_builderSettingFileName = "ImageBuilder.settings";
const char* BuilderSettingManager::s_presetFileExtension = ".preset";
const char* BuilderSettingManager::s_presetFileExtension = "preset";
const char FileMaskDelimiter = '_';
namespace
{
static constexpr const char* const LogWindow = "Image Processing";
}
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3) \
namespace ImageProcess##PrivateName \
@@ -69,13 +76,15 @@ namespace ImageProcessingAtom
if (serialize)
{
serialize->Class<BuilderSettingManager>()
->Version(1)
->Field("AnalysisFingerprint", &BuilderSettingManager::m_analysisFingerprint)
->Version(2)
->Field("BuildSettings", &BuilderSettingManager::m_builderSettings)
->Field("DefaultPresetsByFileMask", &BuilderSettingManager::m_defaultPresetByFileMask)
->Field("PresetsByFileMask", &BuilderSettingManager::m_presetFilterMap)
->Field("DefaultPreset", &BuilderSettingManager::m_defaultPreset)
->Field("DefaultPresetAlpha", &BuilderSettingManager::m_defaultPresetAlpha)
->Field("DefaultPresetNonePOT", &BuilderSettingManager::m_defaultPresetNonePOT);
->Field("DefaultPresetNonePOT", &BuilderSettingManager::m_defaultPresetNonePOT)
// deprecated properties
->Field("DefaultPresetsByFileMask", &BuilderSettingManager::m_defaultPresetByFileMask)
->Field("AnalysisFingerprint", &BuilderSettingManager::m_analysisFingerprint);
}
}
@@ -122,7 +131,7 @@ namespace ImageProcessingAtom
s_globalInstance.Reset();
}
const PresetSettings* BuilderSettingManager::GetPreset(const PresetName& presetName, const PlatformName& platform, AZStd::string_view* settingsFilePathOut)
const PresetSettings* BuilderSettingManager::GetPreset(const PresetName& presetName, const PlatformName& platform, AZStd::string_view* settingsFilePathOut) const
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
auto itr = m_presets.find(presetName);
@@ -137,16 +146,17 @@ namespace ImageProcessingAtom
return nullptr;
}
const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform)
const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) const
{
if (m_builderSettings.find(platform) != m_builderSettings.end())
auto itr = m_builderSettings.find(platform);
if (itr != m_builderSettings.end())
{
return &m_builderSettings[platform];
return &itr->second;
}
return nullptr;
}
const PlatformNameList BuilderSettingManager::GetPlatformList()
const PlatformNameList BuilderSettingManager::GetPlatformList() const
{
PlatformNameList platforms;
@@ -161,7 +171,7 @@ namespace ImageProcessingAtom
return platforms;
}
const AZStd::map <FileMask, AZStd::unordered_set<PresetName>>& BuilderSettingManager::GetPresetFilterMap()
const AZStd::map <FileMask, AZStd::unordered_set<PresetName>>& BuilderSettingManager::GetPresetFilterMap() const
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
return m_presetFilterMap;
@@ -188,7 +198,6 @@ namespace ImageProcessingAtom
m_presetFilterMap.clear();
m_builderSettings.clear();
m_presets.clear();
m_defaultPresetByFileMask.clear();
}
StringOutcome BuilderSettingManager::LoadConfig()
@@ -198,44 +207,53 @@ namespace ImageProcessingAtom
auto fileIoBase = AZ::IO::FileIOBase::GetInstance();
if (fileIoBase == nullptr)
{
return AZ::Failure(AZStd::string("File IO instance needs to be initialized to resolve ImageProcessing builder file aliases"));
return AZ::Failure(
AZStd::string("File IO instance needs to be initialized to resolve ImageProcessing builder file aliases"));
}
// Construct the default setting path
AZ::IO::FixedMaxPath defaultConfigFolder;
if (auto engineRoot = fileIoBase->ResolvePath("@engroot@"); engineRoot.has_value())
{
defaultConfigFolder = *engineRoot;
defaultConfigFolder /= s_defaultConfigRelativeFolder;
m_defaultConfigFolder = *engineRoot;
m_defaultConfigFolder /= s_defaultConfigRelativeFolder;
}
AZ::IO::FixedMaxPath projectConfigFolder;
if (auto sourceGameRoot = fileIoBase->ResolvePath("@projectroot@"); sourceGameRoot.has_value())
{
projectConfigFolder = *sourceGameRoot;
projectConfigFolder /= s_projectConfigRelativeFolder;
m_projectConfigFolder = *sourceGameRoot;
m_projectConfigFolder /= s_projectConfigRelativeFolder;
}
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
ClearSettings();
outcome = LoadSettings((projectConfigFolder / s_builderSettingFileName).Native());
if (!outcome.IsSuccess())
{
outcome = LoadSettings((defaultConfigFolder / s_builderSettingFileName).Native());
}
outcome = LoadSettings();
if (outcome.IsSuccess())
{
// Load presets in default folder first, then load from project folder.
// The same presets which loaded last will overwrite previous loaded one.
LoadPresets(defaultConfigFolder.Native());
LoadPresets(projectConfigFolder.Native());
LoadPresets(m_defaultConfigFolder.Native());
LoadPresets(m_projectConfigFolder.Native());
}
// Regenerate file mask mapping after all presets loaded
RegenerateMappings();
// Collect extra file masks from preset files
CollectFileMasksFromPresets();
if (QCoreApplication::instance())
{
m_fileWatcher.reset(new QFileSystemWatcher);
// track preset files
// Note, the QT signal would only works for AP but not AssetBuilder
// We use file time stamp to track preset file change in builder's CreateJob
for (auto& preset : m_presets)
{
m_fileWatcher.data()->addPath(QString(preset.second.m_presetFilePath.c_str()));
}
m_fileWatcher.data()->addPath(QString(m_defaultConfigFolder.c_str()));
m_fileWatcher.data()->addPath(QString(m_projectConfigFolder.c_str()));
QObject::connect(m_fileWatcher.data(), &QFileSystemWatcher::fileChanged, this, &BuilderSettingManager::OnFileChanged);
QObject::connect(m_fileWatcher.data(), &QFileSystemWatcher::directoryChanged, this, &BuilderSettingManager::OnFolderChanged);
}
return outcome;
@@ -243,36 +261,84 @@ namespace ImageProcessingAtom
void BuilderSettingManager::LoadPresets(AZStd::string_view presetFolder)
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
QDirIterator it(presetFolder.data(), QStringList() << "*.preset", QDir::Files, QDirIterator::NoIteratorFlags);
while (it.hasNext())
{
QString filePath = it.next();
QFileInfo fileInfo = it.fileInfo();
LoadPreset(filePath.toUtf8().data());
}
}
MultiplatformPresetSettings preset;
auto result = AZ::JsonSerializationUtils::LoadObjectFromFile(preset, filePath.toUtf8().data());
if (!result.IsSuccess())
bool BuilderSettingManager::LoadPreset(const AZStd::string& filePath)
{
QFileInfo fileInfo (filePath.c_str());
if (!fileInfo.exists())
{
return false;
}
MultiplatformPresetSettings preset;
auto result = AZ::JsonSerializationUtils::LoadObjectFromFile(preset, filePath);
if (!result.IsSuccess())
{
AZ_Warning(LogWindow, false, "Failed to load preset file %s. Error: %s",
filePath.c_str(), result.GetError().c_str());
return false;
}
PresetName presetName(fileInfo.baseName().toUtf8().data());
AZ_Warning(LogWindow, presetName == preset.GetPresetName(), "Preset file name '%s' is not"
" same as preset name '%s'. Using preset file name as preset name",
filePath.c_str(), preset.GetPresetName().GetCStr());
preset.SetPresetName(presetName);
m_presets[presetName] = PresetEntry{preset, filePath.c_str(), fileInfo.lastModified()};
return true;
}
void BuilderSettingManager::ReloadPreset(const PresetName& presetName)
{
// Find the preset file from project or default config folder
AZStd::string presetFileName = AZStd::string::format("%s.%s", presetName.GetCStr(), s_presetFileExtension);
AZ::IO::FixedMaxPath filePath = m_projectConfigFolder/presetFileName;
QFileInfo fileInfo (filePath.c_str());
if (!fileInfo.exists())
{
filePath = (m_defaultConfigFolder/presetFileName).c_str();
fileInfo = QFileInfo(filePath.c_str());
}
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
//Skip the loading if the file wasn't chagned
if (fileInfo.exists())
{
if (m_presets.find(presetName) != m_presets.end())
{
AZ_Warning("Image Processing", false, "Failed to load preset file %s. Error: %s",
filePath.toUtf8().data(), result.GetError().c_str());
if (m_presets[presetName].m_lastModifiedTime == fileInfo.lastModified()
&& m_presets[presetName].m_presetFilePath == filePath.c_str())
{
return;
}
}
}
PresetName presetName(fileInfo.baseName().toUtf8().data());
// remove preset
m_presets.erase(presetName);
AZ_Warning("Image Processing", presetName == preset.GetPresetName(), "Preset file name '%s' is not"
" same as preset name '%s'. Using preset file name as preset name",
filePath.toUtf8().data(), preset.GetPresetName().GetCStr());
preset.SetPresetName(presetName);
m_presets[presetName] = PresetEntry{preset, filePath.toUtf8().data()};
if (fileInfo.exists())
{
LoadPreset(filePath.c_str());
}
}
StringOutcome BuilderSettingManager::LoadConfigFromFolder(AZStd::string_view configFolder)
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
// Load builder settings
AZStd::string settingFilePath = AZStd::string::format("%.*s%s", aznumeric_cast<int>(configFolder.size()),
configFolder.data(), s_builderSettingFileName);
@@ -282,12 +348,108 @@ namespace ImageProcessingAtom
if (result.IsSuccess())
{
LoadPresets(configFolder);
RegenerateMappings();
}
return result;
}
void BuilderSettingManager::ReportDeprecatedSettings()
{
// reported deprecated attributes in image builder settings
if (!m_analysisFingerprint.empty())
{
AZ_Warning(LogWindow, false, "'AnalysisFingerprint' is deprecated and it should be removed from file [%s]", s_builderSettingFileName);
}
if (!m_defaultPresetByFileMask.empty())
{
AZ_Warning(LogWindow, false, "'DefaultPresetsByFileMask' is deprecated and it should be removed from file [%s]. Use PresetsByFileMask instead", s_builderSettingFileName);
}
}
StringOutcome BuilderSettingManager::LoadSettings()
{
// If the project image build setting file exist, it will merge image builder settings from project folder to the settings from default config folder.
bool needMerge = false;
AZStd::string projectSettingFile{ (m_projectConfigFolder / s_builderSettingFileName).Native() };
if (AZ::IO::SystemFile::Exists(projectSettingFile.c_str()))
{
needMerge = true;
}
AZ::Outcome<void, AZStd::string> outcome;
AZStd::string defaultSettingFile{ (m_defaultConfigFolder / s_builderSettingFileName).Native() };
if (needMerge)
{
auto outcome1 = AZ::JsonSerializationUtils::ReadJsonFile(defaultSettingFile);
auto outcome2 = AZ::JsonSerializationUtils::ReadJsonFile(projectSettingFile);
// return error if it failed to load default settings
if (!outcome1.IsSuccess())
{
return STRING_OUTCOME_ERROR(outcome1.GetError());
}
// if project config was loaded successfully, apply merge patch
rapidjson::Document& originDoc = outcome1.GetValue();
if (outcome2.IsSuccess())
{
const rapidjson::Document& patchDoc = outcome2.GetValue();
AZ::JsonSerializationResult::ResultCode result =
AZ::JsonSerialization::ApplyPatch(originDoc, originDoc.GetAllocator(), patchDoc, AZ::JsonMergeApproach::JsonMergePatch);
if (result.GetProcessing() == AZ::JsonSerializationResult::Processing::Completed)
{
AZStd::vector<char> outBuffer;
AZ::IO::ByteContainerStream<AZStd::vector<char>> outStream{ &outBuffer };
AZ::JsonSerializationUtils::WriteJsonStream(originDoc, outStream);
outStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
outcome = AZ::JsonSerializationUtils::LoadObjectFromStream(*this, outStream);
if (!outcome.IsSuccess())
{
return STRING_OUTCOME_ERROR(outcome.GetError());
}
ReportDeprecatedSettings();
// Generate config file fingerprint
outStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
AZ::u64 hash = AssetBuilderSDK::GetHashFromIOStream(outStream);
m_analysisFingerprint = AZStd::string::format("%llX", hash);
}
else
{
needMerge = false;
AZ_Warning(LogWindow, false, "Failed to fully merge data into image builder settings. Skipping project build setting file [%s]", projectSettingFile.c_str());
}
}
else
{
AZ_Warning(LogWindow, false, "Failed to load project setting file [%s]. Skipping", projectSettingFile.c_str());
}
}
if (!needMerge)
{
outcome = AZ::JsonSerializationUtils::LoadObjectFromFile(*this, defaultSettingFile);
if (!outcome.IsSuccess())
{
return STRING_OUTCOME_ERROR(outcome.GetError());
}
ReportDeprecatedSettings();
// Generate config file fingerprint
AZ::u64 hash = AssetBuilderSDK::GetFileHash(defaultSettingFile.c_str());
m_analysisFingerprint = AZStd::string::format("%llX", hash);
}
return STRING_OUTCOME_SUCCESS;
}
StringOutcome BuilderSettingManager::LoadSettings(AZStd::string_view filepath)
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
@@ -336,13 +498,13 @@ namespace ImageProcessingAtom
return m_analysisFingerprint;
}
void BuilderSettingManager::RegenerateMappings()
void BuilderSettingManager::CollectFileMasksFromPresets()
{
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
AZStd::string noFilter = AZStd::string();
m_presetFilterMap.clear();
AZStd::string extraString;
for (const auto& presetIter : m_presets)
{
@@ -357,22 +519,31 @@ namespace ImageProcessingAtom
{
if (filemask.empty() || filemask[0] != FileMaskDelimiter)
{
AZ_Warning("Image Processing", false, "File mask '%s' is invalid. It must start with '%c'.", filemask.c_str(), FileMaskDelimiter);
AZ_Warning(LogWindow, false, "File mask '%s' is invalid. It must start with '%c'.", filemask.c_str(), FileMaskDelimiter);
continue;
}
else if (filemask.size() < 2)
{
AZ_Warning("Image Processing", false, "File mask '%s' is invalid. The '%c' must be followed by at least one other character.", filemask.c_str());
AZ_Warning(LogWindow, false, "File mask '%s' is invalid. The '%c' must be followed by at least one other character.", filemask.c_str());
continue;
}
else if (filemask.find(FileMaskDelimiter, 1) != AZStd::string::npos)
{
AZ_Warning("Image Processing", false, "File mask '%s' is invalid. It must contain only a single '%c' character.", filemask.c_str(), FileMaskDelimiter);
AZ_Warning(LogWindow, false, "File mask '%s' is invalid. It must contain only a single '%c' character.", filemask.c_str(), FileMaskDelimiter);
continue;
}
extraString += (filemask + preset.m_name.GetCStr());
m_presetFilterMap[filemask].insert(preset.m_name);
}
}
if (!extraString.empty())
{
AZ::u64 hash = AZStd::hash<AZStd::string>{}(extraString);
m_analysisFingerprint += AZStd::string::format("%llX", hash);
}
}
void BuilderSettingManager::MetafilePathFromImagePath(AZStd::string_view imagePath, AZStd::string& metafilePath)
@@ -419,38 +590,15 @@ namespace ImageProcessingAtom
return m_presets.find(presetName) != m_presets.end();
}
PresetName BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr imageFromFile)
PresetName BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath) const
{
PresetName emptyPreset;
//load the image to get its size for later use
IImageObjectPtr image = imageFromFile;
//if the input image is empty we will try to load it from the path
if (imageFromFile == nullptr)
{
image = IImageObjectPtr(LoadImageFromFile(imageFilePath));
}
if (image == nullptr)
{
return emptyPreset;
}
//get file mask of this image file
AZStd::string fileMask = GetFileMask(imageFilePath);
PresetName outPreset = emptyPreset;
//check default presets for some file masks
if (m_defaultPresetByFileMask.find(fileMask) != m_defaultPresetByFileMask.end())
{
outPreset = m_defaultPresetByFileMask[fileMask];
if (!IsValidPreset(outPreset))
{
outPreset = emptyPreset;
}
}
//use the preset filter map to find
if (outPreset.IsEmpty() && !fileMask.empty())
{
@@ -461,54 +609,21 @@ namespace ImageProcessingAtom
}
}
const PresetSettings* presetInfo = nullptr;
if (!outPreset.IsEmpty())
{
presetInfo = GetPreset(outPreset);
//special case for cubemap
if (presetInfo && presetInfo->m_cubemapSetting)
{
// If it's not a latitude-longitude map or it doesn't match any cubemap layouts then reset its preset
if (!IsValidLatLongMap(image) && CubemapLayout::GetCubemapLayoutInfo(image) == nullptr)
{
outPreset = emptyPreset;
}
}
}
if (outPreset == emptyPreset)
{
if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent)
{
outPreset = m_defaultPreset;
}
else
{
outPreset = m_defaultPresetAlpha;
}
outPreset = m_defaultPreset;
}
//get the pixel format for selected preset
presetInfo = GetPreset(outPreset);
return outPreset;
}
if (presetInfo)
{
//valid whether image size work with pixel format
if (CPixelFormats::GetInstance().IsImageSizeValid(presetInfo->m_pixelFormat,
image->GetWidth(0), image->GetHeight(0), false))
{
return outPreset;
}
else
{
AZ_Warning("Image Processing", false, "Image dimensions are not compatible with preset '%s'. The default preset will be used.", presetInfo->m_name.GetCStr());
}
}
//uncompressed one which could be used for almost everything
return m_defaultPresetNonePOT;
AZStd::vector<AZStd::string> BuilderSettingManager::GetPossiblePresetPaths(const PresetName& presetName) const
{
AZStd::vector<AZStd::string> paths;
AZStd::string presetFile = AZStd::string::format("%s.preset", presetName.GetCStr());
paths.push_back((m_defaultConfigFolder / presetFile).c_str());
paths.push_back((m_projectConfigFolder / presetFile).c_str());
return paths;
}
bool BuilderSettingManager::DoesSupportPlatform(AZStd::string_view platformId)
@@ -526,18 +641,50 @@ namespace ImageProcessingAtom
AZStd::string filePath;
if (!AzFramework::StringFunc::Path::Join(outputFolder.data(), fileName.c_str(), filePath))
{
AZ_Warning("Image Processing", false, "Failed to construct path with folder '%.*s' and file: '%s' to save preset",
AZ_Warning(LogWindow, false, "Failed to construct path with folder '%.*s' and file: '%s' to save preset",
aznumeric_cast<int>(outputFolder.size()), outputFolder.data(), filePath.c_str());
continue;
}
auto result = AZ::JsonSerializationUtils::SaveObjectToFile(&presetEntry.m_multiPreset, filePath);
if (!result.IsSuccess())
{
AZ_Warning("Image Processing", false, "Failed to save preset '%s' to file '%s'. Error: %s",
AZ_Warning(LogWindow, false, "Failed to save preset '%s' to file '%s'. Error: %s",
presetEntry.m_multiPreset.GetDefaultPreset().m_name.GetCStr(), filePath.c_str(), result.GetError().c_str());
}
}
}
void BuilderSettingManager::OnFileChanged(const QString &path)
{
// handles preset file change
// Note: this signal only works with AP but not AssetBuilder
AZ_TracePrintf(LogWindow, "File changed %s\n", path.toUtf8().data());
QFileInfo info(path);
// skip if the file is not a preset file
// Note: for .settings file change it's handled when restart AP.
if (info.suffix() != s_presetFileExtension)
{
return;
}
ReloadPreset(PresetName(info.baseName().toUtf8().data()));
}
void BuilderSettingManager::OnFolderChanged([[maybe_unused]] const QString &path)
{
// handles new file added or removed
// Note: this signal only works with AP but not AssetBuilder
AZ_TracePrintf(LogWindow, "folder changed %s\n", path.toUtf8().data());
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_presetMapLock);
m_presets.clear();
LoadPresets(m_defaultConfigFolder.Native());
LoadPresets(m_projectConfigFolder.Native());
for (auto& preset : m_presets)
{
m_fileWatcher.data()->addPath(QString(preset.second.m_presetFilePath.c_str()));
}
}
} // namespace ImageProcessingAtom
@@ -10,10 +10,15 @@
#include <BuilderSettings/ImageProcessingDefines.h>
#include <BuilderSettings/BuilderSettings.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/base.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/containers/set.h>
#include <Atom/ImageProcessing/ImageObject.h>
#include <QDateTime>
#include <QFileSystemWatcher>
#include <QScopedPointer>
class QSettings;
class QString;
@@ -36,6 +41,7 @@ namespace ImageProcessingAtom
* Each preset setting may have different values on different platform, but they are using same uuid.
*/
class BuilderSettingManager
: public QObject // required for using QFileSystemWatcher
{
friend class ImageProcessingTest;
@@ -49,17 +55,17 @@ namespace ImageProcessingAtom
static void DestroyInstance();
static void Reflect(AZ::ReflectContext* context);
const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr);
const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr) const;
const BuilderSettings* GetBuilderSetting(const PlatformName& platform);
const BuilderSettings* GetBuilderSetting(const PlatformName& platform) const;
//! Return A list of platform supported
const PlatformNameList GetPlatformList();
const PlatformNameList GetPlatformList() const;
//! Return A map of preset settings based on their filemasks.
//! @key filemask string, empty string means no filemask
//! @value set of preset setting names supporting the specified filemask
const AZStd::map<FileMask, AZStd::unordered_set<PresetName>>& GetPresetFilterMap();
const AZStd::map<FileMask, AZStd::unordered_set<PresetName>>& GetPresetFilterMap() const;
//! Find preset name based on the preset id.
const PresetName GetPresetNameFromId(const AZ::Uuid& presetId);
@@ -68,7 +74,11 @@ namespace ImageProcessingAtom
StringOutcome LoadConfig();
//! Load configurations files from a folder which includes builder settings and presets
StringOutcome LoadConfigFromFolder(AZStd::string_view configFolder);
//! Note: this is only used for unit test. Use LoadConfig() for editor or game launcher
StringOutcome LoadConfigFromFolder(AZStd::string_view configFolder);
//! Reload preset from config folders
void ReloadPreset(const PresetName& presetName);
const AZStd::string& GetAnalysisFingerprint() const;
@@ -81,7 +91,12 @@ namespace ImageProcessingAtom
//! @param imageFilePath: Filepath string of the image file. The function may load the image from the path for better detection
//! @param image: an optional image object which can be used for preset selection if there is no match based file mask.
//! @return suggested preset name.
PresetName GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr image = nullptr);
PresetName GetSuggestedPreset(AZStd::string_view imageFilePath) const;
//! Get the possible preset config's full file paths
//! This function is only used for setting up image's source dependency if a preset file is missing
//! Otherwise, the preset's file path can be retrieved in GetPreset() function
AZStd::vector<AZStd::string> GetPossiblePresetPaths(const PresetName& presetName) const;
bool IsValidPreset(PresetName presetName) const;
@@ -105,25 +120,41 @@ namespace ImageProcessingAtom
private: // functions
AZ_DISABLE_COPY_MOVE(BuilderSettingManager);
// Write image builder setting to the file specified by filepath
StringOutcome WriteSettings(AZStd::string_view filepath);
// Load image builder settings from the file specified by filepath
StringOutcome LoadSettings(AZStd::string_view filepath);
// Load merge image builder settings (project and default)
StringOutcome LoadSettings();
// report warnings for the deprecated properties in image builder setting data
void ReportDeprecatedSettings();
// Clear Builder Settings and any cached maps/lists
void ClearSettings();
// Regenerate Builder Settings and any cached maps/lists
void RegenerateMappings();
// collect file masks
void CollectFileMasksFromPresets();
// Functions to save/load preset from a folder
void SavePresets(AZStd::string_view outputFolder);
void LoadPresets(AZStd::string_view presetFolder);
// Load a preset to m_presets and return true if success
bool LoadPreset(const AZStd::string& filePath);
// handle preset files changes
void OnFileChanged(const QString &path);
void OnFolderChanged(const QString &path);
private: // variables
struct PresetEntry
{
MultiplatformPresetSettings m_multiPreset;
AZStd::string m_presetFilePath; // Can be used for debug output
QDateTime m_lastModifiedTime;
};
// Builder settings for each platform
@@ -131,13 +162,13 @@ namespace ImageProcessingAtom
AZStd::unordered_map<PresetName, PresetEntry> m_presets;
// Cached list of presets mapped by their file masks.
// a list of presets mapped by their file masks.
// @Key file mask, use empty string to indicate all presets without filtering
// @Value set of preset names that matches the file mask
AZStd::map <FileMask, AZStd::unordered_set<PresetName>> m_presetFilterMap;
// A mutex to protect when modifying any map in this manager
AZStd::recursive_mutex m_presetMapLock;
// A mutex to protect when modifying any map in this manager
mutable AZStd::recursive_mutex m_presetMapLock;
// Default presets for certain file masks
AZStd::map <FileMask, PresetName > m_defaultPresetByFileMask;
@@ -153,5 +184,14 @@ namespace ImageProcessingAtom
// Image builder's version
AZStd::string m_analysisFingerprint;
// default config folder
AZ::IO::FixedMaxPath m_defaultConfigFolder;
// project config folder
AZ::IO::FixedMaxPath m_projectConfigFolder;
// File system watcher to detect preset file changes
QScopedPointer<QFileSystemWatcher> m_fileWatcher;
};
} // namespace ImageProcessingAtom
@@ -171,7 +171,7 @@ namespace ImageProcessingAtomEditor
if (!preset)
{
AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetName.GetCStr());
presetName = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img);
presetName = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath);
for (auto& settingIter : m_settingsMap)
{
@@ -221,6 +221,58 @@ namespace ImageProcessingAtom
m_isShuttingDown = true;
}
PresetName GetImagePreset(const AZStd::string& filepath)
{
// first let preset from asset info
TextureSettings textureSettings;
StringOutcome output = TextureSettings::LoadTextureSetting(filepath, textureSettings);
if (!textureSettings.m_preset.IsEmpty())
{
return textureSettings.m_preset;
}
return BuilderSettingManager::Instance()->GetSuggestedPreset(filepath);
}
void HandlePresetDependency(PresetName presetName, AZStd::vector<AssetBuilderSDK::SourceFileDependency>& sourceDependencyList)
{
// Reload preset if it was changed
ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetName);
AZStd::string_view filePath;
auto presetSettings = BuilderSettingManager::Instance()->GetPreset(presetName, /*default platform*/"", &filePath);
AssetBuilderSDK::SourceFileDependency sourceFileDependency;
sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute;
// Need to watch any possibe preset paths
AZStd::vector<AZStd::string> possiblePresetPaths = BuilderSettingManager::Instance()->GetPossiblePresetPaths(presetName);
for (const auto& path:possiblePresetPaths)
{
sourceFileDependency.m_sourceFileDependencyPath = path;
sourceDependencyList.push_back(sourceFileDependency);
}
if (presetSettings)
{
// handle special case here
// Cubemap setting may reference some other presets
if (presetSettings->m_cubemapSetting)
{
if (presetSettings->m_cubemapSetting->m_generateIBLDiffuse && !presetSettings->m_cubemapSetting->m_iblDiffusePreset.IsEmpty())
{
HandlePresetDependency(presetSettings->m_cubemapSetting->m_iblDiffusePreset, sourceDependencyList);
}
if (presetSettings->m_cubemapSetting->m_generateIBLSpecular && !presetSettings->m_cubemapSetting->m_iblSpecularPreset.IsEmpty())
{
HandlePresetDependency(presetSettings->m_cubemapSetting->m_iblSpecularPreset, sourceDependencyList);
}
}
}
}
// this happens early on in the file scanning pass
// this function should consistently always create the same jobs, and should do no checking whether the job is up to date or not - just be consistent.
void ImageBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
@@ -242,13 +294,26 @@ namespace ImageProcessingAtom
if (ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformInfo.m_identifier))
{
AssetBuilderSDK::JobDescriptor descriptor;
descriptor.m_jobKey = ext + " Atom Compile";
descriptor.m_jobKey = "Image Compile: " + ext;
descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
descriptor.m_critical = false;
descriptor.m_additionalFingerprintInfo = "";
response.m_createJobOutputs.push_back(descriptor);
}
}
// add source dependency for .assetinfo file
AssetBuilderSDK::SourceFileDependency sourceFileDependency;
sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute;
sourceFileDependency.m_sourceFileDependencyPath = request.m_sourceFile;
AZ::StringFunc::Path::ReplaceExtension(sourceFileDependency.m_sourceFileDependencyPath, TextureSettings::ExtensionName);
response.m_sourceFileDependencyList.push_back(sourceFileDependency);
// add source dependencies for .preset files
// Get the preset for this file
auto presetName = GetImagePreset(request.m_sourceFile);
HandlePresetDependency(presetName, response.m_sourceFileDependencyList);
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
return;
}
@@ -11,6 +11,7 @@
#include <Processing/ImageConvert.h>
#include <Processing/ImageAssetProducer.h>
#include <Processing/ImageFlags.h>
#include <Processing/Utils.h>
#include <Converters/FIR-Weights.h>
#include <Converters/Cubemap.h>
#include <Converters/PixelOperation.h>
@@ -229,12 +230,24 @@ namespace ImageProcessingAtom
AZStd::unique_ptr<CubemapSettings>& cubemapSettings = m_input->m_presetSetting.m_cubemapSetting;
if (cubemapSettings->m_generateIBLSpecular && !cubemapSettings->m_iblSpecularPreset.IsEmpty())
{
CreateIBLCubemap(cubemapSettings->m_iblSpecularPreset, SpecularCubemapSuffix, m_iblSpecularCubemapImage);
bool success = CreateIBLCubemap(cubemapSettings->m_iblSpecularPreset, SpecularCubemapSuffix, m_iblSpecularCubemapImage);
if (!success)
{
m_isSucceed = false;
m_isFinished = true;
break;
}
}
if (cubemapSettings->m_generateIBLDiffuse && !cubemapSettings->m_iblDiffusePreset.IsEmpty())
{
CreateIBLCubemap(cubemapSettings->m_iblDiffusePreset, DiffuseCubemapSuffix, m_iblDiffuseCubemapImage);
bool success = CreateIBLCubemap(cubemapSettings->m_iblDiffusePreset, DiffuseCubemapSuffix, m_iblDiffuseCubemapImage);
if (!success)
{
m_isSucceed = false;
m_isFinished = true;
break;
}
}
}
@@ -251,7 +264,12 @@ namespace ImageProcessingAtom
{
if (m_input->m_presetSetting.m_cubemapSetting->m_requiresConvolve)
{
FillCubemapMipmaps();
bool success = FillCubemapMipmaps();
if (!success)
{
m_isSucceed = false;
m_isFinished = true;
}
}
}
else
@@ -268,9 +286,7 @@ namespace ImageProcessingAtom
// get gloss from normal for all mipmaps and save to alpha channel
if (m_input->m_presetSetting.m_glossFromNormals)
{
bool hasAlpha = (m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlack
|| m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite
|| m_alphaContent == EAlphaContent::eAlphaContent_Greyscale);
bool hasAlpha = Utils::NeedAlphaChannel(m_alphaContent);
m_image->Get()->GlossFromNormals(hasAlpha);
// set alpha content so it won't be ignored later.
@@ -347,7 +363,11 @@ namespace ImageProcessingAtom
}
else
{
AZ_TracePrintf("Image Processing", "Image converted with preset [%s] [%s] and saved to [%s] (%d bytes) taking %f seconds\n",
[[maybe_unused]] const PixelFormatInfo* formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->Get()->GetPixelFormat());
AZ_TracePrintf("Image Processing", "Image [%dx%d] [%s] converted with preset [%s] [%s] and saved to [%s] (%d bytes) taking %f seconds\n",
m_image->Get()->GetWidth(0), m_image->Get()->GetHeight(0),
formatInfo->szName,
m_input->m_presetSetting.m_name.GetCStr(),
m_input->m_filePath.c_str(),
m_input->m_outputFolder.c_str(), sizeTotal, m_processTime);
@@ -421,6 +441,17 @@ namespace ImageProcessingAtom
outHeight >>= 1;
outReduce++;
}
// resize to min texture size if it's smaller
if (outWidth < presetSettings->m_minTextureSize)
{
outWidth = presetSettings->m_minTextureSize;
}
if (outHeight < presetSettings->m_minTextureSize)
{
outHeight = presetSettings->m_minTextureSize;
}
}
bool ImageConvertProcess::ConvertToLinear()
@@ -647,7 +678,7 @@ namespace ImageProcessingAtom
}
else if (!CPixelFormats::GetInstance().IsImageSizeValid(dstFmt, dwWidth, dwHeight, false))
{
AZ_Warning("Image Processing", false, "Image size will be scaled for pixel format %s", CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName);
AZ_TracePrintf("Image processing", "Image size will be scaled for pixel format %s\n", CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName);
}
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
@@ -758,7 +789,7 @@ namespace ImageProcessingAtom
// in very rare user case, an old texture setting file may not have a preset. We fix it over here too.
if (textureSettings.m_preset.IsEmpty())
{
textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath, srcImage);
textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath);
}
// Get preset
@@ -795,7 +826,7 @@ namespace ImageProcessingAtom
return process;
}
void ImageConvertProcess::CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage)
bool ImageConvertProcess::CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage)
{
const AZStd::string& platformId = m_input->m_platform;
AZStd::string_view filePath;
@@ -803,7 +834,7 @@ namespace ImageProcessingAtom
if (presetSettings == nullptr)
{
AZ_Error("Image Processing", false, "Couldn't find preset for IBL cubemap generation");
return;
return false;
}
// generate export file name
@@ -838,14 +869,14 @@ namespace ImageProcessingAtom
if (!imageConvertProcess)
{
AZ_Error("Image Processing", false, "Failed to create image convert process for the IBL cubemap");
return;
return false;
}
imageConvertProcess->ProcessAll();
if (!imageConvertProcess->IsSucceed())
{
AZ_Error("Image Processing", false, "Image convert process for the IBL cubemap failed");
return;
return false;
}
// append the output products to the job's product list
@@ -853,6 +884,7 @@ namespace ImageProcessingAtom
// store the output cubemap so it can be accessed by unit tests
cubemapImage = imageConvertProcess->m_image->Get();
return true;
}
bool ConvertImageFile(const AZStd::string& imageFilePath, const AZStd::string& exportDir,
@@ -160,7 +160,7 @@ namespace ImageProcessingAtom
bool FillCubemapMipmaps();
//IBL cubemap generation, this creates a separate ImageConvertProcess
void CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage);
bool CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage);
//convert color space to linear with pixel format rgba32f
bool ConvertToLinear();
@@ -183,10 +183,9 @@ namespace ImageProcessingAtom
return EAlphaContent::eAlphaContent_Absent;
}
//if it's compressed format, return indeterminate. if user really want to know the content, they may convert the format to ARGB8 first
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat))
{
AZ_Assert(false, "the function only works right with uncompressed formats. convert to uncompressed format if you get accurate result");
AZ_TracePrintf("Image processing", "GetAlphaContent() was called for compressed format\n");
return EAlphaContent::eAlphaContent_Indeterminate;
}
@@ -385,6 +385,13 @@ namespace ImageProcessingAtom
}
return true;
}
bool NeedAlphaChannel(EAlphaContent alphaContent)
{
return (alphaContent == EAlphaContent::eAlphaContent_OnlyBlack
|| alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite
|| alphaContent == EAlphaContent::eAlphaContent_Greyscale);
}
}
} // namespace ImageProcessingAtom
@@ -26,5 +26,7 @@ namespace ImageProcessingAtom
IImageObjectPtr LoadImageFromImageAsset(const AZ::Data::Asset<AZ::RPI::StreamingImageAsset>& asset);
bool SaveImageToDdsFile(IImageObjectPtr image, AZStd::string_view filePath);
bool NeedAlphaChannel(EAlphaContent alphaContent);
}
}
@@ -203,7 +203,7 @@ namespace UnitTest
m_gemFolder = AZ::Test::GetEngineRootPath() + "/Gems/Atom/Asset/ImageProcessingAtom/";
m_outputFolder = m_gemFolder + AZStd::string("Code/Tests/TestAssets/temp/");
m_defaultSettingFolder = m_gemFolder + AZStd::string("Config/");
m_defaultSettingFolder = m_gemFolder + AZStd::string("Assets/Config/");
m_testFileFolder = m_gemFolder + AZStd::string("Code/Tests/TestAssets/");
InitialImageFilenames();
@@ -1,67 +0,0 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "BuilderSettingManager",
"ClassData": {
"AnalysisFingerprint": "2",
"BuildSettings": {
"android": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"ios": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"mac": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"pc": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"linux": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": true
},
"provo": {
"GlossScale": 16.0,
"GlossBias": 0.0,
"Streaming": false,
"Enable": false
}
},
"DefaultPresetsByFileMask": {
"_basecolor": "Albedo",
"_diff": "Albedo",
"_diffuse": "Albedo",
"_ddn": "Normals",
"_normal": "Normals",
"_ddna": "NormalsWithSmoothness",
"_glossness": "Reflectance",
"_spec": "Reflectance",
"_specular": "Reflectance",
"_metallic": "Reflectance",
"_refl": "Reflectance",
"_roughness": "Reflectance",
"_ibldiffusecm": "IBLDiffuse",
"_iblskyboxcm": "IBLSkybox",
"_iblspecularcm": "IBLSpecular",
"_skyboxcm": "Skybox"
},
"DefaultPreset": "Albedo",
"DefaultPresetAlpha": "AlbedoWithGenericAlpha",
"DefaultPresetNonePOT": "ReferenceImage"
}
}
@@ -1,157 +0,0 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_spec",
"_refl",
"_ref",
"_rf",
"_gloss",
"_g",
"_f0",
"_specf0",
"_specular",
"_metal",
"_mtl",
"_m",
"_mt",
"_metalness",
"_metallic",
"_roughness",
"_rough"
],
"PixelFormat": "BC1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_spec",
"_refl",
"_ref",
"_rf",
"_gloss",
"_g",
"_f0",
"_specf0",
"_metal",
"_mtl",
"_m",
"_mt",
"_metalness",
"_metallic",
"_roughness",
"_rough"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_spec",
"_refl",
"_ref",
"_rf",
"_gloss",
"_g",
"_f0",
"_specf0",
"_metal",
"_mtl",
"_m",
"_mt",
"_metalness",
"_metallic",
"_roughness",
"_rough"
],
"PixelFormat": "ASTC_6x6",
"MaxTextureSize": 2048,
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_spec",
"_refl",
"_ref",
"_rf",
"_gloss",
"_g",
"_f0",
"_specf0",
"_metal",
"_mtl",
"_m",
"_mt",
"_metalness",
"_metallic",
"_roughness",
"_rough"
],
"PixelFormat": "BC1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}",
"Name": "Reflectance",
"SourceColor": "Linear",
"DestColor": "Linear",
"FileMasks": [
"_spec",
"_refl",
"_ref",
"_rf",
"_gloss",
"_g",
"_f0",
"_specf0",
"_metal",
"_mtl",
"_m",
"_mt",
"_metalness",
"_metallic",
"_roughness",
"_rough"
],
"PixelFormat": "BC1",
"IsPowerOf2": true,
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -14,6 +14,7 @@
#include <Atom/RPI/Math.azsli>
#include "BicubicPcfFilters.azsli"
#include "Shadow.azsli"
#include "NormalOffsetShadows.azsli"
// ProjectedShadow calculates shadowed area projected from a light.
class ProjectedShadow
@@ -123,6 +124,7 @@ float ProjectedShadow::GetThickness(uint shadowIndex, float3 worldPosition)
ProjectedShadow shadow;
shadow.m_worldPosition = worldPosition;
shadow.m_normalVector = 0; // The normal vector is used to reduce acne, this is not an issue when using the shadowmap to determine thickness.
shadow.m_shadowIndex = shadowIndex;
shadow.SetShadowPosition();
return shadow.GetThickness();
@@ -317,8 +319,13 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition)
void ProjectedShadow::SetShadowPosition()
{
const float normalBias = ViewSrg::m_projectedShadows[m_shadowIndex].m_normalShadowBias;
const float shadowmapSize = ViewSrg::m_projectedFilterParams[m_shadowIndex].m_shadowmapSize;
const float3 shadowOffset = ComputeNormalShadowOffset(normalBias, m_normalVector, shadowmapSize);
const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix;
float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition, 1));
float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition + shadowOffset, 1));
m_shadowPosition = shadowPositionHomogeneous.xyz / shadowPositionHomogeneous.w;
m_bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias / shadowPositionHomogeneous.w;
@@ -86,6 +86,8 @@ namespace AZ
virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0;
//! Sets the shadow bias
virtual void SetShadowBias(LightHandle handle, float bias) = 0;
//! Sets the normal shadow bias
virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0;
//! Sets the shadowmap size (width and height) of the light.
virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0;
//! Specifies filter method of shadows.
@@ -74,6 +74,8 @@ namespace AZ
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow.
virtual void SetEsmExponent(LightHandle handle, float exponent) = 0;
//! Sets the normal shadow bias. Reduces acne by biasing the shadowmap lookup along the geometric normal.
virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0;
//! Sets all of the the point data for the provided LightHandle.
virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0;
};
@@ -343,7 +343,6 @@ namespace AZ
m_shadowBufferNeedsUpdate = true;
m_shadowProperties.GetData(index).m_cameraConfigurations[nullptr] = {};
m_shadowProperties.GetData(index).m_cameraTransforms[nullptr] = Transform::CreateIdentity();
const LightHandle handle(index);
m_shadowingLightHandle = handle; // only the recent light has shadows.
@@ -495,20 +494,10 @@ namespace AZ
void DirectionalLightFeatureProcessor::SetCameraTransform(
LightHandle handle,
const Transform& cameraTransform,
const RPI::RenderPipelineId& renderPipelineId)
const Transform&,
const RPI::RenderPipelineId&)
{
ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex());
if (RPI::RenderPipeline* renderPipeline = GetParentScene()->GetRenderPipeline(renderPipelineId).get())
{
const RPI::View* cameraView = renderPipeline->GetDefaultView().get();
property.m_cameraTransforms[cameraView] = cameraTransform;
}
else
{
property.m_cameraTransforms[nullptr] = cameraTransform;
}
property.m_shadowmapViewNeedsUpdate = true;
}
@@ -934,17 +923,6 @@ namespace AZ
return property.m_cameraConfigurations.at(nullptr);
}
const Transform& DirectionalLightFeatureProcessor::GetCameraTransform(LightHandle handle, const RPI::View* cameraView) const
{
const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex());
const auto findIt = property.m_cameraTransforms.find(cameraView);
if (findIt != property.m_cameraTransforms.end())
{
return findIt->second;
}
return property.m_cameraTransforms.at(nullptr);
}
void DirectionalLightFeatureProcessor::UpdateFrustums(
LightHandle handle)
{
@@ -1365,10 +1343,11 @@ namespace AZ
// If we used an AABB whose Y-direction range is from a segment,
// the depth value on the shadowmap saturated to 0 or 1,
// and we could not draw shadow correctly.
const Transform cameraTransform = cameraView->GetCameraTransform();
const Vector3 entireFrustumCenterLight =
lightTransform.GetInverseFast() * (GetCameraTransform(handle, cameraView).TransformPoint(property.m_entireFrustumCenterLocal));
lightTransform.GetInverseFast() * (cameraTransform.TransformPoint(property.m_entireFrustumCenterLocal));
const float entireCenterY = entireFrustumCenterLight.GetElement(1);
const Vector3 cameraLocationWorld = GetCameraTransform(handle, cameraView).GetTranslation();
const Vector3 cameraLocationWorld = cameraTransform.GetTranslation();
const Vector3 cameraLocationLight = lightTransformInverse * cameraLocationWorld;
// Extend light view frustum by camera depth far in order to avoid shadow lacking behind camera.
const float cameraBehindMinY = cameraLocationLight.GetElement(1) - GetCameraConfiguration(handle, cameraView).GetDepthFar();
@@ -1428,8 +1407,8 @@ namespace AZ
GetCameraConfiguration(handle, cameraView).GetDepthCenter(depthNear, depthFar),
depthFar);
const Vector3 localCenter{ 0.f, depthCenter, 0.f };
return GetCameraTransform(handle, cameraView).TransformPoint(localCenter);
const Vector3 localCenter{ 0.f, depthCenter, 0.f };
return cameraView->GetCameraTransform().TransformPoint(localCenter);
}
float DirectionalLightFeatureProcessor::GetRadius(
@@ -1483,7 +1462,7 @@ namespace AZ
const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex());
const Vector3& boundaryCenter = GetWorldCenterPosition(handle, cameraView, depthNear, depthFar);
const CascadeShadowCameraConfiguration& cameraConfiguration = GetCameraConfiguration(handle, cameraView);
const Transform& cameraTransform = GetCameraTransform(handle, cameraView);
const Transform cameraTransform = cameraView->GetCameraTransform();
const Vector3& cameraFwd = cameraTransform.GetBasis(1);
const Vector3& cameraUp = cameraTransform.GetBasis(2);
const Vector3 cameraToBoundaryCenter = boundaryCenter - cameraTransform.GetTranslation();
@@ -134,9 +134,6 @@ namespace AZ
// Default far depth of each cascade.
AZStd::array<float, Shadow::MaxNumberOfCascades> m_defaultFarDepths;
// Transforms of camera who offers view frustum for each camera view.
AZStd::unordered_map<const RPI::View*, Transform> m_cameraTransforms;
// Configuration offers shape of the camera view frustum for each camera view.
AZStd::unordered_map<const RPI::View*, CascadeShadowCameraConfiguration> m_cameraConfigurations;
@@ -259,11 +256,6 @@ namespace AZ
//! it returns one of the fallback render pipeline ID.
const CascadeShadowCameraConfiguration& GetCameraConfiguration(LightHandle handle, const RPI::View* cameraView) const;
//! This returns the camera transform.
//! If it has not been registered for the given camera view.
//! it returns one of the fallback render pipeline ID.
const Transform& GetCameraTransform(LightHandle handle, const RPI::View* cameraView) const;
//! This update view frustum of camera.
void UpdateFrustums(LightHandle handle);
@@ -313,6 +313,11 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias);
}
void DiskLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias);
}
void DiskLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize);
@@ -51,6 +51,7 @@ namespace AZ
void SetConeAngles(LightHandle handle, float innerDegrees, float outerDegrees) override;
void SetShadowsEnabled(LightHandle handle, bool enabled) override;
void SetShadowBias(LightHandle handle, float bias) override;
void SetNormalShadowBias(LightHandle handle, float bias) override;
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
@@ -302,5 +302,10 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent);
}
void PointLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias);
}
} // namespace Render
} // namespace AZ
@@ -52,6 +52,7 @@ namespace AZ
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetEsmExponent(LightHandle handle, float esmExponent) override;
void SetNormalShadowBias(LightHandle handle, float bias) override;
void SetPointData(LightHandle handle, const PointLightData& data) override;
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
@@ -155,8 +155,9 @@ namespace AZ::Render
{
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias().");
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id);
shadowProperty.m_normalShadowBias = normalShadowBias;
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
shadowData.m_normalShadowBias = normalShadowBias;
m_deviceBufferNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size)
@@ -68,7 +68,7 @@ namespace AZ::Render
uint32_t m_filteringSampleCount = 0;
AZStd::array<float, 2> m_unprojectConstants = { {0, 0} };
float m_bias;
float m_normalShadowBias;
float m_normalShadowBias = 0;
float m_esmExponent = 87.0f;
float m_padding[3];
};
@@ -79,7 +79,6 @@ namespace AZ::Render
ProjectedShadowDescriptor m_desc;
RPI::ViewPtr m_shadowmapView;
float m_bias = 0.1f;
float m_normalShadowBias = 0.0f;
ShadowId m_shadowId;
};
@@ -163,6 +163,7 @@ _LOGGER.debug('Invoking __init__.py for {0}.'.format({_PACKAGENAME}))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def get_datadir() -> pathlib.Path:
"""
persistent application data.
@@ -10,9 +10,7 @@
"""Frame capture of the Displaymapper Passthrough (outputs .dds image)"""
# ------------------------------------------------------------------------
import logging as _logging
from env_bool import env_bool
# ------------------------------------------------------------------------
_MODULENAME = 'ColorGrading.capture_displaymapperpassthrough'
import ColorGrading.initialize
@@ -27,25 +25,35 @@ _LOGGER.debug('Initializing: {0}.'.format({_MODULENAME}))
import azlmbr.bus
import azlmbr.atom
default_passtree = ["Root",
# This requires the level to have the DisplayMapper component added
# and configured to 'Passthrough'
# but now we can capture the parent input
# so this is here for reference for how it previously worked
passtree_displaymapperpassthrough = ["Root",
"MainPipeline_0",
"MainPipeline",
"PostProcessPass",
"LightAdaptation",
"DisplayMapperPass",
"DisplayMapperPassthrough"]
# we can grad the parent pass input to the displaymapper directly
passtree_default = ["Root",
"MainPipeline_0",
"MainPipeline",
"PostProcessPass",
"LightAdaptation",
"DisplayMapperPass",
"DisplayMapperPassthrough"]
"DisplayMapperPass"]
default_path = "FrameCapture\DisplayMapperPassthrough.dds"
# To Do: we should try to set display mapper to passthrough,
# then back after capture?
default_path = "FrameCapture\DisplayMappeInput.dds"
# To Do: we can wrap this, to call from a PySide2 GUI
def capture(command="CapturePassAttachment",
passtree=default_passtree,
pass_type="Output",
passtree=passtree_default,
pass_type="Input",
output_path=default_path):
"""Writes frame capture into project cache"""
azlmbr.atom.FrameCaptureRequestBus(azlmbr.bus.Broadcast,
command,
passtree,
@@ -32,10 +32,7 @@ if DCCSI_GDEBUG:
DCCSI_LOGLEVEL = int(10)
# set up logger with both console and file _logging
if DCCSI_GDEBUG:
_LOGGER = initialize_logger(_PACKAGENAME, log_to_file=True, default_log_level=DCCSI_LOGLEVEL)
else:
_LOGGER = initialize_logger(_PACKAGENAME, log_to_file=False, default_log_level=DCCSI_LOGLEVEL)
_LOGGER = initialize_logger(_PACKAGENAME, log_to_file=DCCSI_GDEBUG, default_log_level=DCCSI_LOGLEVEL)
_LOGGER.debug('Initializing: {0}.'.format({_MODULENAME}))
@@ -46,7 +43,7 @@ if DCCSI_DEV_MODE:
APPDATA = get_datadir() # os APPDATA
APPDATA_WING = Path(APPDATA, f"Wing Pro {DCCSI_WING_VERSION_MAJOR}").resolve()
if APPDATA_WING.exists():
site.addsitedir(pathlib.PureWindowsPath(APPDATA_WING).as_posix())
site.addsitedir(APPDATA_WING.resolve())
import wingdbstub as debugger
try:
debugger.Ensure()
@@ -75,8 +72,7 @@ def start():
try:
_O3DE_DEV = Path(os.getenv('O3DE_DEV'))
_O3DE_DEV = _O3DE_DEV.resolve()
os.environ['O3DE_DEV'] = pathlib.PureWindowsPath(_O3DE_DEV).as_posix()
os.environ['O3DE_DEV'] = _O3DE_DEV.as_posix()
_LOGGER.debug(f'O3DE_DEV is: {_O3DE_DEV}')
except EnvironmentError as e:
_LOGGER.error('O3DE engineroot not set or found')
@@ -86,23 +82,22 @@ def start():
_TAG_LY_BUILD_PATH = os.getenv('TAG_LY_BUILD_PATH', 'build')
_DEFAULT_BIN_PATH = Path(str(_O3DE_DEV), _TAG_LY_BUILD_PATH, 'bin', 'profile')
_O3DE_BIN_PATH = Path(os.getenv('O3DE_BIN_PATH', _DEFAULT_BIN_PATH))
_O3DE_BIN_PATH = _O3DE_BIN_PATH.resolve()
os.environ['O3DE_BIN_PATH'] = pathlib.PureWindowsPath(_O3DE_BIN_PATH).as_posix()
os.environ['O3DE_BIN_PATH'] = _O3DE_BIN_PATH.as_posix()
_LOGGER.debug(f'O3DE_BIN_PATH is: {_O3DE_BIN_PATH}')
site.addsitedir(pathlib.PureWindowsPath(_O3DE_BIN_PATH).as_posix())
site.addsitedir(_O3DE_BIN_PATH.resolve())
except EnvironmentError as e:
_LOGGER.error('O3DE bin folder not set or found')
raise e
if running_editor:
_O3DE_DEV = Path(os.getenv('O3DE_DEV', Path(azlmbr.paths.engroot)))
os.environ['O3DE_DEV'] = pathlib.PureWindowsPath(_O3DE_DEV).as_posix()
os.environ['O3DE_DEV'] = _O3DE_DEV.as_posix()
_LOGGER.debug(_O3DE_DEV)
_O3DE_BIN_PATH = Path(str(_O3DE_DEV),Path(azlmbr.paths.executableFolder))
_O3DE_BIN = Path(os.getenv('O3DE_BIN', _O3DE_BIN_PATH.resolve()))
os.environ['O3DE_BIN'] = pathlib.PureWindowsPath(_O3DE_BIN).as_posix()
os.environ['O3DE_BIN'] = _O3DE_BIN_PATH.as_posix()
_LOGGER.debug(_O3DE_BIN)
@@ -34,15 +34,15 @@ SETLOCAL ENABLEDELAYEDEXPANSION
IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat
:: Initialize env
echo
echo.
echo ... calling Env_Core.bat
CALL %~dp0\Env_Core.bat
echo
echo.
echo ... calling Env_Python.bat
CALL %~dp0\Env_Python.bat
echo
echo.
echo ... calling Env_Tools.bat
CALL %~dp0\Env_Tools.bat
@@ -27,37 +27,19 @@ echo ~ O3DE Color Grading Python Env ...
echo _____________________________________________________________________
echo.
:: Python Version
:: Ideally these are set to match the O3DE python distribution
:: <O3DE>\python\runtime
IF "%DCCSI_PY_VERSION_MAJOR%"=="" (set DCCSI_PY_VERSION_MAJOR=3)
echo DCCSI_PY_VERSION_MAJOR = %DCCSI_PY_VERSION_MAJOR%
:: PY version Major
IF "%DCCSI_PY_VERSION_MINOR%"=="" (set DCCSI_PY_VERSION_MINOR=7)
echo DCCSI_PY_VERSION_MINOR = %DCCSI_PY_VERSION_MINOR%
IF "%DCCSI_PY_VERSION_RELEASE%"=="" (set DCCSI_PY_VERSION_RELEASE=10)
echo DCCSI_PY_VERSION_RELEASE = %DCCSI_PY_VERSION_RELEASE%
:: shared location for 64bit python 3.7 DEV location
:: this defines a DCCsi sandbox for lib site-packages by version
:: <O3DE>\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python\Lib
set DCCSI_PYTHON_PATH=%DCCSIG_PATH%\3rdParty\Python
echo DCCSI_PYTHON_PATH = %DCCSI_PYTHON_PATH%
:: add access to a Lib location that matches the py version (example: 3.7.x)
:: switch this for other python versions like maya (2.7.x)
IF "%DCCSI_PYTHON_LIB_PATH%"=="" (set DCCSI_PYTHON_LIB_PATH=%DCCSI_PYTHON_PATH%\Lib\%DCCSI_PY_VERSION_MAJOR%.x\%DCCSI_PY_VERSION_MAJOR%.%DCCSI_PY_VERSION_MINOR%.x\site-packages)
echo DCCSI_PYTHON_LIB_PATH = %DCCSI_PYTHON_LIB_PATH%
:: add to the PATH
SET PATH=%DCCSI_PYTHON_LIB_PATH%;%PATH%
:: shared location for default O3DE python location
set DCCSI_PYTHON_INSTALL=%O3DE_DEV%\Python
echo DCCSI_PYTHON_INSTALL = %DCCSI_PYTHON_INSTALL%
:: Warning, many DCC tools (like Maya) include thier own versioned python interpretter.
:: Some apps may not operate correctly if PYTHONHOME is set/propogated.
:: This is definitely the case with Maya, doing so causes Maya to not boot.
FOR /F "tokens=* USEBACKQ" %%F IN (`%DCCSI_PYTHON_INSTALL%\python.cmd %DCCSI_PYTHON_INSTALL%\get_python_path.py`) DO (SET PYTHONHOME=%%F)
echo PYTHONHOME - is now the folder containing O3DE python executable
echo PYTHONHOME = %PYTHONHOME%
SET PYTHON=%PYTHONHOME%\python.exe
:: location for O3DE python 3.7 location
set DCCSI_PY_BASE=%DCCSI_PYTHON_INSTALL%\python.cmd
echo DCCSI_PY_BASE = %DCCSI_PY_BASE%
@@ -65,10 +47,7 @@ echo DCCSI_PY_BASE = %DCCSI_PY_BASE%
:: ide and debugger plug
set DCCSI_PY_DEFAULT=%DCCSI_PY_BASE%
IF "%DCCSI_PY_REV%"=="" (set DCCSI_PY_REV=rev2)
IF "%DCCSI_PY_PLATFORM%"=="" (set DCCSI_PY_PLATFORM=windows)
set DCCSI_PY_IDE=%DCCSI_PYTHON_INSTALL%\runtime\python-%DCCSI_PY_VERSION_MAJOR%.%DCCSI_PY_VERSION_MINOR%.%DCCSI_PY_VERSION_RELEASE%-%DCCSI_PY_REV%-%DCCSI_PY_PLATFORM%\python
set DCCSI_PY_IDE=%PYTHONHOME%
echo DCCSI_PY_IDE = %DCCSI_PY_IDE%
:: Wing and other IDEs probably prefer access directly to the python.exe
@@ -91,11 +70,6 @@ SET PATH=%DCCSI_PYTHON_INSTALL%;%DCCSI_PY_IDE%;%DCCSI_PY_IDE_PACKAGES%;%DCCSI_PY
set PYTHONPATH=%DCCSIG_PATH%;%DCCSI_PYTHON_LIB_PATH%;%O3DE_BIN_PATH%;%DCCSI_COLORGRADING_SCRIPTS%;%DCCSI_FEATURECOMMON_SCRIPTS%;%PYTHONPATH%
echo PYTHONPATH = %PYTHONPATH%
:: used for debugging in WingIDE (but needs to be here)
IF "%TAG_USERNAME%"=="" (set TAG_USERNAME=NOT_SET)
echo TAG_USERNAME = %TAG_USERNAME%
IF "%TAG_USERNAME%"=="NOT_SET" (echo Add TAG_USERNAME to User_Env.bat)
:: Set flag so we don't initialize dccsi environment twice
SET O3DE_ENV_PY_INIT=1
GOTO END_OF_FILE
@@ -25,11 +25,6 @@ SET TAG_LY_BUILD_PATH=build
SET DCCSI_GDEBUG=True
SET DCCSI_DEV_MODE=True
:: set the your user name here for windows path
SET TAG_USERNAME=NOT_SET
SET DCCSI_PY_REV=rev1
SET DCCSI_PY_PLATFORM=windows
:: Set flag so we don't initialize dccsi environment twice
SET O3DE_USER_ENV_INIT=1
GOTO END_OF_FILE
@@ -92,6 +92,8 @@ namespace AZ
const AZ::Matrix4x4& GetViewToWorldMatrix() const;
const AZ::Matrix4x4& GetViewToClipMatrix() const;
const AZ::Matrix4x4& GetWorldToClipMatrix() const;
const AZ::Matrix4x4& GetClipToWorldMatrix() const;
//! Get the camera's world transform, converted from the viewToWorld matrix's native y-up to z-up
AZ::Transform GetCameraTransform() const;
@@ -130,17 +132,22 @@ namespace AZ
//! Returns the masked occlusion culling interface
MaskedOcclusionCulling* GetMaskedOcclusionCulling();
//! This is called by RenderPipeline when this view is added to the pipeline.
void OnAddToRenderPipeline();
private:
View() = delete;
View(const AZ::Name& name, UsageFlags usage);
//! Sorts the finalized draw lists in this view
void SortFinalizedDrawLists();
//! Sorts a drawList using the sort function from a pass with the corresponding drawListTag
void SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag);
//! Attempt to create a shader resource group.
void TryCreateShaderResourceGroup();
AZ::Name m_name;
UsageFlags m_usageFlags;
@@ -178,6 +178,10 @@ namespace AZ
pipelineViews.m_views.resize(1);
}
ViewPtr previousView = pipelineViews.m_views[0];
if (view)
{
view->OnAddToRenderPipeline();
}
pipelineViews.m_views[0] = view;
if (previousView)
@@ -238,6 +242,7 @@ namespace AZ
pipelineViews.m_type = PipelineViewType::Transient;
}
view->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
view->OnAddToRenderPipeline();
pipelineViews.m_views.push_back(view);
}
}
+64 -26
View File
@@ -47,18 +47,14 @@ namespace AZ
{
AZ_Assert(!name.IsEmpty(), "invalid name");
// Set default matrixes.
// Set default matrices
SetWorldToViewMatrix(AZ::Matrix4x4::CreateIdentity());
AZ::Matrix4x4 viewToClipMatrix;
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1, 0.1f, 1000.f, true);
SetViewToClipMatrix(viewToClipMatrix);
Data::Asset<ShaderAsset> viewSrgShaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
TryCreateShaderResourceGroup();
if (viewSrgShaderAsset.IsReady())
{
m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgShaderAsset, RPISystemInterface::Get()->GetViewSrgLayout()->GetName());
}
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
m_maskedOcclusionCulling = MaskedOcclusionCulling::Create();
m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight);
@@ -125,6 +121,7 @@ namespace AZ
m_worldToViewMatrix = worldToView;
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
@@ -162,6 +159,7 @@ namespace AZ
m_worldToViewMatrix = m_viewToWorldMatrix.GetInverseFast();
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
// Only signal an update when there is a change, otherwise this might block
// user input from changing the value.
@@ -177,6 +175,7 @@ namespace AZ
m_viewToClipMatrix = viewToClip;
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
// Update z depth constant simultaneously
// zNear -> n, zFar -> f
@@ -227,6 +226,11 @@ namespace AZ
return m_worldToClipMatrix;
}
const AZ::Matrix4x4& View::GetClipToWorldMatrix() const
{
return m_clipToWorldMatrix;
}
bool View::HasDrawListTag(RHI::DrawListTag drawListTag)
{
return drawListTag.IsValid() && m_drawListMask[drawListTag.GetIndex()];
@@ -361,16 +365,19 @@ namespace AZ
{
if (m_clipSpaceOffset.IsZero())
{
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
if (m_shaderResourceGroup)
{
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
}
}
else
{
// Offset the current and previous frame clip matricies
// Offset the current and previous frame clip matrices
Matrix4x4 offsetViewToClipMatrix = m_viewToClipMatrix;
offsetViewToClipMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
offsetViewToClipMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
@@ -379,27 +386,33 @@ namespace AZ
offsetViewToClipPrevMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
offsetViewToClipPrevMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
// Build other matricies dependent on the view to clip matricies
// Build other matrices dependent on the view to clip matrices
Matrix4x4 offsetWorldToClipMatrix = offsetViewToClipMatrix * m_worldToViewMatrix;
Matrix4x4 offsetWorldToClipPrevMatrix = offsetViewToClipPrevMatrix * m_worldToViewPrevMatrix;
Matrix4x4 offsetClipToViewMatrix = offsetViewToClipMatrix.GetInverseFull();
Matrix4x4 offsetClipToWorldMatrix = m_viewToWorldMatrix * offsetClipToViewMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
if (m_shaderResourceGroup)
{
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
}
}
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
if (m_shaderResourceGroup)
{
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
m_shaderResourceGroup->Compile();
m_shaderResourceGroup->Compile();
}
m_viewToClipPrevMatrix = m_viewToClipMatrix;
m_worldToViewPrevMatrix = m_worldToViewMatrix;
@@ -418,5 +431,30 @@ namespace AZ
{
return m_maskedOcclusionCulling;
}
void View::TryCreateShaderResourceGroup()
{
if (!m_shaderResourceGroup)
{
if (auto rpiSystemInterface = RPISystemInterface::Get())
{
if (Data::Asset<ShaderAsset> viewSrgShaderAsset = rpiSystemInterface->GetCommonShaderAssetForSrgs();
viewSrgShaderAsset.IsReady())
{
m_shaderResourceGroup =
ShaderResourceGroup::Create(viewSrgShaderAsset, rpiSystemInterface->GetViewSrgLayout()->GetName());
}
}
}
}
void View::OnAddToRenderPipeline()
{
TryCreateShaderResourceGroup();
if (!m_shaderResourceGroup)
{
AZ_Warning("RPI::View", false, "Shader Resource Group failed to initialize");
}
}
} // namespace RPI
} // namespace AZ
@@ -69,6 +69,19 @@ namespace UnitTest
assetPath /= "Cache";
AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetPath.c_str());
// Remark, AZ::Utils::GetProjectPath() is not used when defining "user" folder,
// instead We use AZ::Test::GetEngineRootPath();.
// Reason:
// When running unit tests, using AZ::Utils::GetProjectPath() will resolve to something like:
// "/data/workspace/o3de/build/linux/External/Atom-9a4d112b/RPI/Code/Cache"
// The ShaderMetricSystem.cpp writes to the @user@ folder and the following runtime error occurs:
// "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead."
// "Attempted write location: /data/workspace/o3de/build/linux/External/Atom-9a4d112b/RPI/Code/Cache/user/shadermetrics.json"
// To avoid the error We use AZ::Test::GetEngineRootPath();
AZ::IO::Path userPath = AZ::Test::GetEngineRootPath();
userPath /= "user";
AZ::IO::FileIOBase::GetInstance()->SetAlias("@user@", userPath.c_str());
m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
m_jsonSystemComponent = AZStd::make_unique<AZ::JsonSystemComponent>();
m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get());
@@ -80,6 +80,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PRIVATE
AZ::AzTest
AZ::AzTestShared
AZ::AzFrameworkTestShared
Gem::AtomToolsFramework.Static
Gem::Atom_Utils.TestUtils.Static
)
@@ -112,15 +112,16 @@ namespace AtomToolsFramework
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
// ModularViewportCameraControllerRequestBus overrides ...
void InterpolateToTransform(const AZ::Transform& worldFromLocal) override;
AZ::Transform GetReferenceFrame() const override;
void SetReferenceFrame(const AZ::Transform& worldFromLocal) override;
void ClearReferenceFrame() override;
bool InterpolateToTransform(const AZ::Transform& worldFromLocal) override;
bool IsInterpolating() const override;
void StartTrackingTransform(const AZ::Transform& worldFromLocal) override;
void StopTrackingTransform() override;
bool IsTrackingTransform() const override;
private:
//! Update the reference frame after a change has been made to the camera
//! view without updating the internal camera via user input.
void RefreshReferenceFrame();
//! Combine the current camera transform with any potential roll from the tracked
//! transform (this is usually zero).
AZ::Transform CombinedCameraTransform() const;
//! The current mode the camera controller is in.
enum class CameraMode
@@ -141,21 +142,21 @@ namespace AtomToolsFramework
AzFramework::Camera m_camera; //!< The current camera state (pitch/yaw/position/look-distance).
AzFramework::Camera m_targetCamera; //!< The target (next) camera state that m_camera is catching up to.
AzFramework::Camera m_previousCamera; //!< The state of the camera from the previous frame.
AZStd::optional<AzFramework::Camera> m_storedCamera; //!< A potentially stored camera for when a custom reference frame is set.
AZStd::optional<AzFramework::Camera> m_storedCamera; //!< A potentially stored camera for when a transform is being tracked.
AzFramework::CameraSystem m_cameraSystem; //!< The camera system responsible for managing all CameraInputs.
AzFramework::CameraProps m_cameraProps; //!< Camera properties to control rotate and translate smoothness.
CameraControllerPriorityFn m_priorityFn; //!< Controls at what priority the camera controller should respond to events.
CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation).
CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in.
//! An additional reference frame the camera can operate in (identity has no effect).
AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity();
//! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally).
bool m_updatingTransformInternally = false;
float m_roll = 0.0f; //!< The current amount of roll to be applied to the camera.
float m_targetRoll = 0.0f; //!< The target amount of roll to be applied to the camera (current will move towards this).
//! Listen for camera view changes outside of the camera controller.
AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler;
//! The current instance of the modular camera viewport context.
AZStd::unique_ptr<ModularCameraViewportContext> m_modularCameraViewportContext;
//! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally).
bool m_updatingTransformInternally = false;
};
//! Placeholder implementation for ModularCameraViewportContext (useful for verifying the interface).
@@ -23,23 +23,31 @@ namespace AtomToolsFramework
class ModularViewportCameraControllerRequests : public AZ::EBusTraits
{
public:
static inline constexpr float InterpolateToTransformDuration = 1.0f;
using BusIdType = AzFramework::ViewportId;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
//! Begin a smooth transition of the camera to the requested transform.
//! @param worldFromLocal The transform of where the camera should end up.
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0;
//! @return Returns true if the call began an interpolation and false otherwise. Calls to InterpolateToTransform
//! will have no effect if an interpolation is currently in progress.
virtual bool InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0;
//! Return the current reference frame.
//! @note If a reference frame has not been set or a frame has been cleared, this is just the identity.
virtual AZ::Transform GetReferenceFrame() const = 0;
//! Returns if the camera is currently interpolating to a new transform.
virtual bool IsInterpolating() const = 0;
//! Set a new reference frame other than the identity for the camera controller.
virtual void SetReferenceFrame(const AZ::Transform& worldFromLocal) = 0;
//! Start tracking a transform.
//! Store the current camera transform and move to the next camera transform.
virtual void StartTrackingTransform(const AZ::Transform& worldFromLocal) = 0;
//! Clear the current reference frame to restore the identity.
virtual void ClearReferenceFrame() = 0;
//! Stop tracking the set transform.
//! The previously stored camera transform is restored.
virtual void StopTrackingTransform() = 0;
//! Return if the tracking transform is set.
virtual bool IsTrackingTransform() const = 0;
protected:
~ModularViewportCameraControllerRequests() = default;
@@ -21,6 +21,7 @@
#include <AzFramework/Windowing/WindowBus.h>
#include <AzCore/Component/TickBus.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <AtomToolsFramework/Viewport/ViewportInteractionImpl.h>
namespace AtomToolsFramework
{
@@ -30,8 +31,8 @@ namespace AtomToolsFramework
//! @see AZ::RPI::ViewportContext for Atom's API for setting up
class RenderViewportWidget
: public QWidget
, public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
, public AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler
, public AzToolsFramework::ViewportInteraction::ViewportInteractionRequests
, public AzFramework::WindowRequestBus::Handler
, protected AzFramework::InputChannelEventListener
, protected AZ::TickBus::Handler
@@ -90,11 +91,11 @@ namespace AtomToolsFramework
//! Input processing is enabled by default.
void SetInputProcessingEnabled(bool enabled);
// AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler overrides ...
// ViewportInteractionRequests overrides ...
AzFramework::CameraState GetCameraState() override;
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override;
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) override;
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition) override;
float DeviceScalingFactor() override;
@@ -149,5 +150,7 @@ namespace AtomToolsFramework
AZ::ScriptTimePoint m_time;
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
// Implementation of ViewportInteractionRequests (handles viewport picking operations).
AZStd::unique_ptr<ViewportInteractionImpl> m_viewportInteractionImpl;
};
} //namespace AtomToolsFramework
@@ -0,0 +1,42 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/View.h>
#include <AzFramework/Viewport/CameraState.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AtomToolsFramework
{
//! A concrete implementation of the ViewportInteractionRequestBus.
//! Primarily concerned with picking (screen to world and world to screen transformations).
class ViewportInteractionImpl : public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler
{
public:
explicit ViewportInteractionImpl(AZ::RPI::ViewPtr viewPtr);
void Connect(AzFramework::ViewportId viewportId);
void Disconnect();
// ViewportInteractionRequestBus overrides ...
AzFramework::CameraState GetCameraState() override;
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override;
AZ::Vector3 ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition) override;
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition) override;
float DeviceScalingFactor() override;
AZStd::function<AzFramework::ScreenSize()> m_screenSizeFn; //! Callback to determine the screen size.
AZStd::function<float()> m_deviceScalingFactorFn; //! Callback to determine the device scaling factor.
private:
AZ::RPI::ViewPtr m_viewPtr;
};
} // namespace AtomToolsFramework
@@ -79,12 +79,18 @@ namespace AtomToolsFramework
m_styleManager.reset(new AzQtComponents::StyleManager(this));
m_styleManager->initialize(this, engineRootPath);
connect(&m_timer, &QTimer::timeout, this, [&]()
m_timer.setInterval(1);
connect(&m_timer, &QTimer::timeout, this, [this]()
{
this->PumpSystemEventLoopUntilEmpty();
this->Tick();
});
connect(this, &QGuiApplication::applicationStateChanged, this, [this]()
{
// Limit the update interval when not in focus to reduce power consumption and interference with other applications
this->m_timer.setInterval((applicationState() & Qt::ApplicationActive) ? 1 : 32);
});
}
AtomToolsApplication ::~AtomToolsApplication()
@@ -9,11 +9,13 @@
#pragma once
#include <AzCore/Module/Module.h>
#include <AzToolsFramework/API/PythonLoader.h>
namespace AtomToolsFramework
{
class AtomToolsFrameworkModule
: public AZ::Module
, public AzToolsFramework::EmbeddedPython::PythonLoader
{
public:
AZ_RTTI(AtomToolsFrameworkModule, "{B58B7CA8-98C9-4DC8-8607-E094989BBBE2}", AZ::Module);
@@ -12,6 +12,7 @@
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/Color.h>
#include <AzCore/std/math.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
@@ -175,16 +176,12 @@ namespace AtomToolsFramework
// ignore these updates if the camera is being updated internally
if (!m_updatingTransformInternally)
{
if (m_storedCamera.has_value())
{
// if an external change occurs ensure we update the stored reference frame if one is set
RefreshReferenceFrame();
return;
}
m_previousCamera = m_targetCamera;
UpdateCameraFromTransform(m_targetCamera, m_modularCameraViewportContext->GetCameraTransform());
m_camera = m_targetCamera;
const AZ::Transform transform = m_modularCameraViewportContext->GetCameraTransform();
const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform));
UpdateCameraFromTranslationAndRotation(m_targetCamera, transform.GetTranslation(), eulerAngles);
m_targetRoll = eulerAngles.GetY();
}
};
@@ -227,7 +224,9 @@ namespace AtomToolsFramework
{
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count());
m_modularCameraViewportContext->SetCameraTransform(m_referenceFrameOverride * m_camera.Transform());
m_roll = AzFramework::SmoothValue(m_targetRoll, m_roll, m_cameraProps.m_rotateSmoothnessFn(), event.m_deltaTime.count());
m_modularCameraViewportContext->SetCameraTransform(CombinedCameraTransform());
}
else if (m_cameraMode == CameraMode::Animation)
{
@@ -236,7 +235,10 @@ namespace AtomToolsFramework
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
};
m_cameraAnimation.m_time = AZ::GetClamp(m_cameraAnimation.m_time + event.m_deltaTime.count(), 0.0f, 1.0f);
m_cameraAnimation.m_time = AZ::GetClamp(
m_cameraAnimation.m_time +
(event.m_deltaTime.count() / ModularViewportCameraControllerRequests::InterpolateToTransformDuration),
0.0f, 1.0f);
const auto& [transformStart, transformEnd, animationTime] = m_cameraAnimation;
@@ -250,6 +252,7 @@ namespace AtomToolsFramework
m_camera.m_yaw = eulerAngles.GetZ();
m_camera.m_pivot = current.GetTranslation();
m_camera.m_offset = AZ::Vector3::CreateZero();
m_targetRoll = eulerAngles.GetY();
m_targetCamera = m_camera;
m_modularCameraViewportContext->SetCameraTransform(current);
@@ -257,55 +260,59 @@ namespace AtomToolsFramework
if (animationTime >= 1.0f)
{
m_cameraMode = CameraMode::Control;
RefreshReferenceFrame();
}
}
m_updatingTransformInternally = false;
}
void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal)
bool ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal)
{
m_cameraMode = CameraMode::Animation;
m_cameraAnimation = CameraAnimation{ m_referenceFrameOverride * m_camera.Transform(), worldFromLocal, 0.0f };
if (!IsInterpolating())
{
m_cameraMode = CameraMode::Animation;
m_cameraAnimation = CameraAnimation{ CombinedCameraTransform(), worldFromLocal, 0.0f };
return true;
}
return false;
}
AZ::Transform ModularViewportCameraControllerInstance::GetReferenceFrame() const
bool ModularViewportCameraControllerInstance::IsInterpolating() const
{
return m_referenceFrameOverride;
return m_cameraMode == CameraMode::Animation;
}
void ModularViewportCameraControllerInstance::SetReferenceFrame(const AZ::Transform& worldFromLocal)
void ModularViewportCameraControllerInstance::StartTrackingTransform(const AZ::Transform& worldFromLocal)
{
if (!m_storedCamera.has_value())
{
m_storedCamera = m_previousCamera;
}
m_referenceFrameOverride = worldFromLocal;
m_targetCamera.m_pitch = 0.0f;
m_targetCamera.m_yaw = 0.0f;
const auto angles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromQuaternion(worldFromLocal.GetRotation()));
m_targetCamera.m_pitch = angles.GetX();
m_targetCamera.m_yaw = angles.GetZ();
m_targetCamera.m_offset = AZ::Vector3::CreateZero();
m_targetCamera.m_pivot = AZ::Vector3::CreateZero();
m_camera = m_targetCamera;
m_targetCamera.m_pivot = worldFromLocal.GetTranslation();
m_targetRoll = angles.GetY();
}
void ModularViewportCameraControllerInstance::ClearReferenceFrame()
void ModularViewportCameraControllerInstance::StopTrackingTransform()
{
m_referenceFrameOverride = AZ::Transform::CreateIdentity();
if (m_storedCamera.has_value())
{
m_targetCamera = m_storedCamera.value();
m_camera = m_targetCamera;
m_targetRoll = 0.0f;
}
m_storedCamera.reset();
}
void ModularViewportCameraControllerInstance::RefreshReferenceFrame()
bool ModularViewportCameraControllerInstance::IsTrackingTransform() const
{
m_referenceFrameOverride = m_modularCameraViewportContext->GetCameraTransform() * m_camera.Transform().GetInverse();
return m_storedCamera.has_value();
}
AZ::Transform PlaceholderModularCameraViewportContextImpl::GetCameraTransform() const
@@ -324,4 +331,9 @@ namespace AtomToolsFramework
{
handler.Connect(m_viewMatrixChangedEvent);
}
AZ::Transform ModularViewportCameraControllerInstance::CombinedCameraTransform() const
{
return m_camera.Transform() * AZ::Transform::CreateFromMatrix3x3(AZ::Matrix3x3::CreateRotationY(m_targetRoll));
}
} // namespace AtomToolsFramework
@@ -75,7 +75,11 @@ namespace AtomToolsFramework
m_defaultCamera = AZ::RPI::View::CreateView(cameraName, AZ::RPI::View::UsageFlags::UsageCamera);
AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()->PushView(m_viewportContext->GetName(), m_defaultCamera);
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(GetId());
m_viewportInteractionImpl = AZStd::make_unique<ViewportInteractionImpl>(m_defaultCamera);
m_viewportInteractionImpl->m_deviceScalingFactorFn = [this] { return aznumeric_cast<float>(devicePixelRatioF()); };
m_viewportInteractionImpl->m_screenSizeFn = [this] { return AzFramework::ScreenSize(width(), height()); };
m_viewportInteractionImpl->Connect(id);
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(GetId());
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
@@ -107,7 +111,7 @@ namespace AtomToolsFramework
AZ::TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
m_viewportInteractionImpl->Disconnect();
}
void RenderViewportWidget::LockRenderTargetSize(uint32_t width, uint32_t height)
@@ -278,77 +282,23 @@ namespace AtomToolsFramework
AzFramework::CameraState RenderViewportWidget::GetCameraState()
{
AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
if (currentView == nullptr)
{
return {};
}
// Build camera state from Atom camera transforms
AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(
currentView->GetViewToWorldMatrix(),
AZ::Vector2{aznumeric_cast<float>(width()), aznumeric_cast<float>(height())}
);
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
// Convert from Z-up
AZStd::swap(cameraState.m_forward, cameraState.m_up);
cameraState.m_forward = -cameraState.m_forward;
return cameraState;
return m_viewportInteractionImpl->GetCameraState();
}
AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
currentView == nullptr)
{
return AzFramework::ScreenPoint(0, 0);
}
return AzFramework::WorldToScreen(worldPosition, GetCameraState());
return m_viewportInteractionImpl->ViewportWorldToScreen(worldPosition);
}
AZStd::optional<AZ::Vector3> RenderViewportWidget::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth)
AZ::Vector3 RenderViewportWidget::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition)
{
const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix();
const auto& cameraView = m_viewportContext->GetCameraViewMatrix();
const AZ::Vector4 normalizedScreenPosition {
screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f
};
AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView;
worldFromScreen.InvertFull();
const AZ::Vector4 projectedPosition = worldFromScreen * normalizedScreenPosition;
if (projectedPosition.GetW() == 0.0f)
{
return {};
}
return projectedPosition.GetAsVector3() / projectedPosition.GetW();
return m_viewportInteractionImpl->ViewportScreenToWorld(screenPosition);
}
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> RenderViewportWidget::ViewportScreenToWorldRay(
AzToolsFramework::ViewportInteraction::ProjectedViewportRay RenderViewportWidget::ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition)
{
auto pos0 = ViewportScreenToWorld(screenPosition, 0.f);
auto pos1 = ViewportScreenToWorld(screenPosition, 1.f);
if (!pos0.has_value() || !pos1.has_value())
{
return {};
}
pos0 = m_viewportContext->GetDefaultView()->GetViewToWorldMatrix().GetTranslation();
AZ::Vector3 rayOrigin = pos0.value();
AZ::Vector3 rayDirection = pos1.value() - pos0.value();
rayDirection.Normalize();
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
return m_viewportInteractionImpl->ViewportScreenToWorldRay(screenPosition);
}
float RenderViewportWidget::DeviceScalingFactor()
@@ -0,0 +1,61 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AtomToolsFramework/Viewport/ViewportInteractionImpl.h>
#include <AzFramework/Viewport/ViewportScreen.h>
namespace AtomToolsFramework
{
ViewportInteractionImpl::ViewportInteractionImpl(AZ::RPI::ViewPtr viewPtr)
: m_viewPtr(AZStd::move(viewPtr))
{
}
void ViewportInteractionImpl::Connect(const AzFramework::ViewportId viewportId)
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(viewportId);
}
void ViewportInteractionImpl::Disconnect()
{
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
}
AzFramework::CameraState ViewportInteractionImpl::GetCameraState()
{
// build camera state from atom camera transforms
AzFramework::CameraState cameraState =
AzFramework::CreateDefaultCamera(m_viewPtr->GetCameraTransform(), AzFramework::Vector2FromScreenSize(m_screenSizeFn()));
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, m_viewPtr->GetViewToClipMatrix());
return cameraState;
}
AzFramework::ScreenPoint ViewportInteractionImpl::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
return AzFramework::WorldToScreen(worldPosition, GetCameraState());
}
AZ::Vector3 ViewportInteractionImpl::ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition)
{
return AzFramework::ScreenToWorld(screenPosition, GetCameraState());
}
AzToolsFramework::ViewportInteraction::ProjectedViewportRay ViewportInteractionImpl::ViewportScreenToWorldRay(
const AzFramework::ScreenPoint& screenPosition)
{
const AzFramework::CameraState cameraState = GetCameraState();
const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPosition, cameraState);
const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized();
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
}
float ViewportInteractionImpl::DeviceScalingFactor()
{
return m_deviceScalingFactorFn();
}
} // namespace AtomToolsFramework
@@ -12,16 +12,25 @@
namespace UnitTest
{
class AtomToolsFrameworkTestEnvironment : public AZ::Test::ITestEnvironment
{
protected:
void SetupEnvironment() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
void TeardownEnvironment() override
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
};
class AtomToolsFrameworkTest : public ::testing::Test
{
protected:
void SetUp() override
{
if (!AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Create(AZ::SystemAllocator::Descriptor());
}
m_assetSystemStub.Activate();
RegisterSourceAsset("objects/upgrades/materials/supercondor.material");
@@ -38,11 +47,6 @@ namespace UnitTest
void TearDown() override
{
m_assetSystemStub.Deactivate();
if (AZ::AllocatorInstance<AZ::SystemAllocator>::IsReady())
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
}
}
void RegisterSourceAsset(const AZStd::string& path)
@@ -73,5 +77,5 @@ namespace UnitTest
ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material");
}
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
AZ_UNIT_TEST_HOOK(new AtomToolsFrameworkTestEnvironment);
} // namespace UnitTest
@@ -0,0 +1,172 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Public/View.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/Math/MatrixUtils.h>
#include <AzCore/Name/NameDictionary.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <Tests/Utils/Printers.h>
namespace UnitTest
{
class ViewportInteractionImplFixture : public ::testing::Test
{
public:
static inline constexpr AzFramework::ViewportId TestViewportId = 1234;
static inline constexpr AzFramework::ScreenSize ScreenDimensions = AzFramework::ScreenSize(1280, 720);
static AzFramework::ScreenPoint ScreenCenter()
{
const auto halfScreenDimensions = ScreenDimensions * 0.5f;
return AzFramework::ScreenPoint(halfScreenDimensions.m_width, halfScreenDimensions.m_height);
}
void SetUp() override
{
AZ::NameDictionary::Create();
m_view = AZ::RPI::View::CreateView(AZ::Name("TestView"), AZ::RPI::View::UsageCamera);
const auto aspectRatio = aznumeric_cast<float>(ScreenDimensions.m_width) / aznumeric_cast<float>(ScreenDimensions.m_height);
AZ::Matrix4x4 viewToClipMatrix;
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::DegToRad(60.0f), aspectRatio, 0.1f, 1000.f, true);
m_view->SetViewToClipMatrix(viewToClipMatrix);
m_viewportInteractionImpl = AZStd::make_unique<AtomToolsFramework::ViewportInteractionImpl>(m_view);
m_viewportInteractionImpl->m_deviceScalingFactorFn = []
{
return 1.0f;
};
m_viewportInteractionImpl->m_screenSizeFn = []
{
return ScreenDimensions;
};
m_viewportInteractionImpl->Connect(TestViewportId);
}
void TearDown() override
{
m_viewportInteractionImpl->Disconnect();
m_viewportInteractionImpl.reset();
m_view.reset();
AZ::NameDictionary::Destroy();
}
AZ::RPI::ViewPtr m_view;
AZStd::unique_ptr<AtomToolsFramework::ViewportInteractionImpl> m_viewportInteractionImpl;
};
// transform a point from screen space to world space, and then from world space back to screen space
AzFramework::ScreenPoint ScreenToWorldToScreen(
const AzFramework::ScreenPoint& screenPoint,
AzToolsFramework::ViewportInteraction::ViewportInteractionRequests& viewportInteractionRequests)
{
const auto worldResult = viewportInteractionRequests.ViewportScreenToWorld(screenPoint);
return viewportInteractionRequests.ViewportWorldToScreen(worldResult);
}
TEST_F(ViewportInteractionImplFixture, ViewportInteractionRequestsMapsFromScreenToWorldAndBack)
{
using AzFramework::ScreenPoint;
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(10.0f, 0.0f, 5.0f)));
{
const auto expectedScreenPoint = ScreenPoint{ 600, 450 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
auto expectedScreenPoint = ScreenCenter();
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
const auto expectedScreenPoint = ScreenPoint{ 0, 0 };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
{
const auto expectedScreenPoint = ScreenPoint{ ScreenDimensions.m_width, ScreenDimensions.m_height };
const auto resultScreenPoint = ScreenToWorldToScreen(expectedScreenPoint, *m_viewportInteractionImpl);
EXPECT_EQ(resultScreenPoint, expectedScreenPoint);
}
}
TEST_F(ViewportInteractionImplFixture, ScreenToWorldReturnsPositionOnNearClipPlaneInWorldSpace)
{
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(-90.0f)), AZ::Vector3(20.0f, 0.0f, 0.0f)));
const auto worldResult = m_viewportInteractionImpl->ViewportScreenToWorld(ScreenCenter());
EXPECT_THAT(worldResult, IsClose(AZ::Vector3(20.1f, 0.0f, 0.0f)));
}
// note: values produced by reproducing in the editor viewport
TEST_F(ViewportInteractionImplFixture, WorldToScreenGivesExpectedScreenCoordinates)
{
using AzFramework::ScreenPoint;
{
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(160.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-18.0f)),
AZ::Vector3(-21.0f, 2.5f, 6.0f)));
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-21.0f, -1.5f, 5.0f));
EXPECT_EQ(screenResult, ScreenPoint(420, 326));
}
{
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(175.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-90.0f)),
AZ::Vector3(-10.0f, -11.0f, 2.5f)));
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-10.0f, -10.5f, 0.5f));
EXPECT_EQ(screenResult, ScreenPoint(654, 515));
}
{
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(70.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(65.0f)),
AZ::Vector3(-22.5f, -10.0f, 1.5f)));
const auto screenResult = m_viewportInteractionImpl->ViewportWorldToScreen(AZ::Vector3(-23.0f, -9.5f, 3.0f));
EXPECT_EQ(screenResult, ScreenPoint(754, 340));
}
}
TEST_F(ViewportInteractionImplFixture, ScreenToWorldRayGivesGivesExpectedOriginAndDirection)
{
using AzFramework::ScreenPoint;
m_view->SetCameraTransform(AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(
AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(34.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-24.0f)),
AZ::Vector3(-9.3f, -9.8f, 4.0f)));
const auto ray = m_viewportInteractionImpl->ViewportScreenToWorldRay(ScreenPoint(832, 226));
float unused;
auto intersection = AZ::Intersect::IntersectRaySphere(ray.origin, ray.direction, AZ::Vector3(-14.0f, 5.7f, 0.75f), 0.5f, unused);
EXPECT_EQ(intersection, AZ::Intersect::SphereIsectTypes::ISECT_RAY_SPHERE_ISECT);
}
} // namespace UnitTest
@@ -28,6 +28,7 @@ set(FILES
Include/AtomToolsFramework/Util/MaterialPropertyUtil.h
Include/AtomToolsFramework/Util/Util.h
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
Include/AtomToolsFramework/Viewport/ViewportInteractionImpl.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h
@@ -55,6 +56,7 @@ set(FILES
Source/Util/Util.cpp
Source/Viewport/RenderViewportWidget.cpp
Source/Viewport/ModularViewportCameraController.cpp
Source/Viewport/ViewportInteractionImpl.cpp
Source/Window/AtomToolsMainWindow.cpp
Source/Window/AtomToolsMainWindowSystemComponent.cpp
Source/Window/AtomToolsMainWindowSystemComponent.h
@@ -8,4 +8,5 @@
set(FILES
Tests/AtomToolsFrameworkTest.cpp
Tests/ViewportInteractionImplTests.cpp
)
@@ -132,6 +132,13 @@ namespace AZ
//! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow.
virtual void SetEsmExponent(float exponent) = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @return Returns the amount of bias to apply.
virtual float GetNormalShadowBias() const = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
};
//! The EBus for requests to for setting and getting light component properties.
@@ -57,6 +57,7 @@ namespace AZ
// Shadows (only used for supported shapes)
bool m_enableShadow = false;
float m_bias = 0.1f;
float m_normalShadowBias = 0.0f;
ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
uint16_t m_filteringSampleCount = 12;
@@ -34,6 +34,7 @@ namespace AZ
// Shadows
->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow)
->Field("Shadow Bias", &AreaLightComponentConfig::m_bias)
->Field("Normal Shadow Bias", &AreaLightComponentConfig::m_normalShadowBias)
->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize)
->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod)
->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount)
@@ -70,6 +70,8 @@ namespace AZ::Render
->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow)
->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias)
->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias)
->Event("GetNormalShadowBias", &AreaLightRequestBus::Events::GetNormalShadowBias)
->Event("SetNormalShadowBias", &AreaLightRequestBus::Events::SetNormalShadowBias)
->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize)
->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize)
->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod)
@@ -91,6 +93,7 @@ namespace AZ::Render
->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow")
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias")
->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
@@ -302,6 +305,7 @@ namespace AZ::Render
if (m_configuration.m_enableShadow)
{
m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias);
m_lightShapeDelegate->SetNormalShadowBias(m_configuration.m_normalShadowBias);
m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize);
m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
@@ -474,6 +478,20 @@ namespace AZ::Render
}
}
void AreaLightComponentController::SetNormalShadowBias(float bias)
{
m_configuration.m_normalShadowBias = bias;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetNormalShadowBias(bias);
}
}
float AreaLightComponentController::GetNormalShadowBias() const
{
return m_configuration.m_normalShadowBias;
}
ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const
{
return m_configuration.m_shadowmapMaxSize;
@@ -86,6 +86,8 @@ namespace AZ
void SetFilteringSampleCount(uint32_t count) override;
float GetEsmExponent() const override;
void SetEsmExponent(float exponent) override;
float GetNormalShadowBias() const override;
void SetNormalShadowBias(float bias) override;
void HandleDisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,

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