Merge branch 'main' into ATOM/tonypeng/ATOM-14947

main
Peng 5 years ago
commit 76423a1cc8

@ -95,23 +95,22 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
endif()
## White Box ##
# DISABLED - See LYN-2663
#if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# ly_add_pytest(
# NAME AutomatedTesting::WhiteBoxTests
# TEST_SUITE main
# TEST_SERIAL
# PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
# TIMEOUT 3600
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# COMPONENT
# WhiteBox
# )
#endif()
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::WhiteBoxTests
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
WhiteBox
)
endif()
## NvCloth ##
# [TODO LYN-1928] Enable when AutomatedTesting runs with Atom

@ -22,10 +22,10 @@ class Tests():
# fmt:on
def run():
def C28798177_WhiteBox_AddComponentToEntity():
import os
import sys
import WhiteBoxInit as init
from Gems.WhiteBox.Editor.Scripts import WhiteBoxInit as init
import ImportPathHelper as imports
imports.init()
@ -58,4 +58,8 @@ def run():
if __name__ == "__main__":
run()
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
Report.start_test(C28798177_WhiteBox_AddComponentToEntity)

@ -22,13 +22,13 @@ class Tests():
# fmt:on
def run():
def C28798205_WhiteBox_SetInvisible():
# note: This automated test does not fully replicate the test case in Test Rail as it's
# not currently possible using the Hydra API to get an EntityComponentIdPair at runtime,
# in future game_mode will be activated and a runtime White Box Component queried
import os
import sys
import WhiteBoxInit as init
from Gems.WhiteBox.Editor.Scripts import WhiteBoxInit as init
import ImportPathHelper as imports
import editor_python_test_tools.hydra_editor_utils as hydra
imports.init()
@ -68,4 +68,8 @@ def run():
if __name__ == "__main__":
run()
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
Report.start_test(C28798205_WhiteBox_SetInvisible)

@ -26,10 +26,10 @@ class Tests():
critical_shape_check = ("Default shape has more than 0 sides", "default shape has 0 sides")
def run():
def C29279329_WhiteBox_SetDefaultShape():
import os
import sys
import WhiteBoxInit as init
from Gems.WhiteBox.Editor.Scripts import WhiteBoxInit as init
import ImportPathHelper as imports
imports.init()
@ -107,4 +107,8 @@ def run():
if __name__ == "__main__":
run()
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
Report.start_test(C29279329_WhiteBox_SetDefaultShape)

@ -41,7 +41,7 @@ class TestDynamicSliceInstanceSpawner(object):
return console
@pytest.mark.test_case_id("C28851763")
@pytest.mark.SUITE_main
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project,
launcher_platform):

@ -36,8 +36,13 @@ class TestEmptyInstanceSpawner(object):
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C28851762")
# Main suite needs at least one test
@pytest.mark.SUITE_main
def test_EmptyInstanceSpawner_Dummy(self, request, editor, level, workspace, project, launcher_platform):
pass
@pytest.mark.test_case_id("C28851762")
@pytest.mark.SUITE_sandbox
def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform):
cfg_args = [level]

@ -269,6 +269,8 @@ class TestAutomation(TestAutomationBase):
from . import C18977601_Material_FrictionCombinePriority as test_module
self._run_test(request, workspace, editor, test_module)
@pytest.mark.xfail(
reason="Something with the CryRenderer disabling is causing this test to fail now.")
@revert_physics_config
def test_C13895144_Ragdoll_ChangeLevel(self, request, workspace, editor, launcher_platform):
from . import C13895144_Ragdoll_ChangeLevel as test_module

@ -247,7 +247,7 @@ CUNIXConsole* pUnixConsole;
#define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml"
#define LOAD_LEGACY_RENDERER_FOR_EDITOR true // If you set this to false you must for now also set 'ed_useAtomNativeViewport' to true (see /Code/Sandbox/Editor/ViewManager.cpp)
#define LOAD_LEGACY_RENDERER_FOR_EDITOR false // If you set this to true you must also set 'ed_useAtomNativeViewport' to false (see /Code/Sandbox/Editor/ViewManager.cpp)
#define LOAD_LEGACY_RENDERER_FOR_LAUNCHER false
//////////////////////////////////////////////////////////////////////////

@ -78,7 +78,7 @@ namespace Physics
float m_minimumMovementDistance = 0.001f; //!< To avoid jittering, the controller will not attempt to move distances below this.
float m_maximumSpeed = 100.0f; //!< If the accumulated requested velocity for a tick exceeds this magnitude, it will be clamped.
AZStd::string m_colliderTag; //!< Used to identify the collider associated with the character controller.
AZStd::shared_ptr<Physics::ShapeConfiguration> m_shapeConfig = nullptr; //!< The shape to use when creating the character controller.
AZStd::shared_ptr<Physics::ShapeConfiguration> m_shapeConfig; //!< The shape to use when creating the character controller.
AZStd::vector<AZStd::shared_ptr<Physics::Shape>> m_colliders; //!< The list of colliders to attach to the character controller.
};

@ -55,7 +55,7 @@ namespace AzPhysics
//! Flag to determine if the body is part of the simulation.
//! When true the body will be affected by any forces, collisions, and found with scene queries.
bool m_simulating = true;
bool m_simulating = false;
//! Helper functions for setting user data.
//! @param userData Can be a pointer to any type as internally will be cast to a void*. Object lifetime not managed by the SimulatedBody.

@ -46,6 +46,7 @@ namespace AzPhysics
->Field("orientation", &SimulatedBodyConfiguration::m_orientation)
->Field("scale", &SimulatedBodyConfiguration::m_scale)
->Field("entityId", &SimulatedBodyConfiguration::m_entityId)
->Field("startSimulationEnabled", &SimulatedBodyConfiguration::m_startSimulationEnabled)
;
}
}

@ -39,6 +39,7 @@ namespace AzPhysics
AZ::Vector3 m_position = AZ::Vector3::CreateZero();
AZ::Quaternion m_orientation = AZ::Quaternion::CreateIdentity();
AZ::Vector3 m_scale = AZ::Vector3::CreateOne();
bool m_startSimulationEnabled = true;
// Entity/object association.
AZ::EntityId m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId);

@ -52,6 +52,11 @@ namespace Physics
}
}
RagdollConfiguration::RagdollConfiguration()
{
m_startSimulationEnabled = false; //ragdolls do not start enabled.
}
void RagdollConfiguration::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);

@ -24,6 +24,8 @@
namespace Physics
{
using ParentIndices = AZStd::vector<size_t>;
class RagdollNodeConfiguration
: public AzPhysics::RigidBodyConfiguration
{
@ -46,7 +48,7 @@ namespace Physics
AZ_RTTI(RagdollConfiguration, "{7C96D332-61D8-4C58-A2BF-707716D38D14}", AzPhysics::SimulatedBodyConfiguration);
static void Reflect(AZ::ReflectContext* context);
RagdollConfiguration() = default;
RagdollConfiguration();
explicit RagdollConfiguration(const RagdollConfiguration& settings) = default;
RagdollNodeConfiguration* FindNodeConfigByName(const AZStd::string& nodeName) const;
@ -56,6 +58,8 @@ namespace Physics
AZStd::vector<RagdollNodeConfiguration> m_nodes;
CharacterColliderConfiguration m_colliders;
RagdollState m_initialState;
ParentIndices m_parentIndices;
};
/// Represents a single rigid part of a ragdoll.
@ -79,7 +83,7 @@ namespace Physics
{
public:
AZ_CLASS_ALLOCATOR(Ragdoll, AZ::SystemAllocator, 0);
AZ_RTTI(Ragdoll, "{01F09602-80EC-4693-A0E7-C2719239044B}", AzPhysics::SimulatedBody);
AZ_RTTI(Physics::Ragdoll, "{01F09602-80EC-4693-A0E7-C2719239044B}", AzPhysics::SimulatedBody);
virtual ~Ragdoll() = default;
/// Inserts the ragdoll into the physics simulation.

@ -348,6 +348,11 @@ namespace AzToolsFramework
*/
virtual bool AreAnyEntitiesSelected() = 0;
/*!
* Returns the number of selected entities.
*/
virtual int GetSelectedEntitiesCount() = 0;
/*!
* Retrieves the set of selected entities.
* \return a list of entity Ids.

@ -395,6 +395,7 @@ namespace AzToolsFramework
->Event("MarkEntityDeselected", &ToolsApplicationRequests::MarkEntityDeselected)
->Event("IsSelected", &ToolsApplicationRequests::IsSelected)
->Event("AreAnyEntitiesSelected", &ToolsApplicationRequests::AreAnyEntitiesSelected)
->Event("GetSelectedEntitiesCount", &ToolsApplicationRequests::GetSelectedEntitiesCount)
;
behaviorContext->EBus<ToolsApplicationNotificationBus>("ToolsApplicationNotificationBus")

@ -101,6 +101,7 @@ namespace AzToolsFramework
SourceControlFileInfo GetSceneSourceControlInfo() override;
bool AreAnyEntitiesSelected() override { return !m_selectedEntities.empty(); }
int GetSelectedEntitiesCount() override { return m_selectedEntities.size(); }
const EntityIdList& GetSelectedEntities() override { return m_selectedEntities; }
const EntityIdList& GetHighlightedEntities() override { return m_highlightedEntities; }
void SetSelectedEntities(const EntityIdList& selectedEntities) override;

@ -242,19 +242,6 @@ namespace AzToolsFramework
return false;
}
}
else
{
// The template is already loaded, this is the case of either saving as same name or different name(loaded from before).
// Update the template with the changes
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
}
m_prefabSystemComponent->UpdatePrefabTemplate(templateId, dom);
}
Prefab::TemplateId prevTemplateId = m_rootInstance->GetTemplateId();
m_rootInstance->SetTemplateId(templateId);

@ -200,7 +200,7 @@ namespace AzToolsFramework
}
return context.Report(result,
result.GetProcessing() == JSR::Processing::Completed ? "Succesfully loaded instance information for prefab." :
result.GetProcessing() == JSR::Processing::Completed ? "Successfully loaded instance information for prefab." :
"Failed to load instance information for prefab");
}

@ -230,6 +230,10 @@ namespace AzToolsFramework
AZ_Assert(instanceDom.IsObject(), "Link Id '%u' cannot be added because the DOM of the instance is not an object.", m_id);
instanceDom.AddMember(rapidjson::StringRef(PrefabDomUtils::LinkIdName), rapidjson::Value().SetUint64(m_id), allocator);
}
else
{
linkIdReference->get().SetUint64(m_id);
}
}
} // namespace Prefab

@ -392,12 +392,27 @@ namespace AzToolsFramework
if (patch.IsArray() && !patch.Empty() && beforeState.IsObject())
{
// Update the state of the entity
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
state->SetParent(parentUndoBatch);
state->Capture(beforeState, afterState, entityId);
if (IsInstanceContainerEntity(entityId) && !IsLevelInstanceContainerEntity(entityId))
{
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, entityId);
// Save these changes as patches to the link
PrefabUndoLinkUpdate* linkUpdate =
aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
linkUpdate->SetParent(parentUndoBatch);
linkUpdate->Capture(patch, owningInstance->get().GetLinkId());
state->Redo();
linkUpdate->Redo();
}
else
{
// Update the state of the entity
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
state->SetParent(parentUndoBatch);
state->Capture(beforeState, afterState, entityId);
state->Redo();
}
}
// Update the cache

@ -81,12 +81,17 @@ namespace UnitTest
ToolsApplicationRequestBus::BroadcastResult(
anyEntitySelected, &ToolsApplicationRequests::AreAnyEntitiesSelected);
int selectedEntitiesCount = 0;
ToolsApplicationRequestBus::BroadcastResult(
selectedEntitiesCount, &ToolsApplicationRequests::GetSelectedEntitiesCount);
EntityIdList selectedEntityIds;
ToolsApplicationRequestBus::BroadcastResult(
selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
EXPECT_TRUE(testEntitySelected);
EXPECT_TRUE(anyEntitySelected);
EXPECT_EQ(selectedEntitiesCount, 1);
EXPECT_EQ(selectedEntityIds.size(), 1);
EXPECT_EQ(selectedEntityIds.front(), testEntityId);
@ -100,11 +105,15 @@ namespace UnitTest
ToolsApplicationRequestBus::BroadcastResult(
anyEntitySelected, &ToolsApplicationRequests::AreAnyEntitiesSelected);
ToolsApplicationRequestBus::BroadcastResult(
selectedEntitiesCount, &ToolsApplicationRequests::GetSelectedEntitiesCount);
ToolsApplicationRequestBus::BroadcastResult(
selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
EXPECT_FALSE(testEntitySelected);
EXPECT_FALSE(anyEntitySelected);
EXPECT_EQ(selectedEntitiesCount, 0);
EXPECT_TRUE(selectedEntityIds.empty());
}
@ -141,11 +150,16 @@ namespace UnitTest
ToolsApplicationRequestBus::BroadcastResult(
anyEntitySelected, &ToolsApplicationRequests::AreAnyEntitiesSelected);
int selectedEntitiesCount = 0;
ToolsApplicationRequestBus::BroadcastResult(
selectedEntitiesCount, &ToolsApplicationRequests::GetSelectedEntitiesCount);
EntityIdList actualSelectedEntityIds;
ToolsApplicationRequestBus::BroadcastResult(
actualSelectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
EXPECT_TRUE(anyEntitySelected);
EXPECT_EQ(selectedEntitiesCount, expectedSelectedEntityIds.size());
EXPECT_EQ(actualSelectedEntityIds.size(), expectedSelectedEntityIds.size());
for (auto& id : expectedSelectedEntityIds)
{
@ -160,10 +174,14 @@ namespace UnitTest
ToolsApplicationRequestBus::BroadcastResult(
anyEntitySelected, &ToolsApplicationRequests::AreAnyEntitiesSelected);
ToolsApplicationRequestBus::BroadcastResult(
selectedEntitiesCount, &ToolsApplicationRequests::GetSelectedEntitiesCount);
ToolsApplicationRequestBus::BroadcastResult(
actualSelectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities);
EXPECT_TRUE(anyEntitySelected);
EXPECT_EQ(selectedEntitiesCount, expectedSelectedEntityIds.size());
EXPECT_EQ(actualSelectedEntityIds.size(), expectedSelectedEntityIds.size());
for (auto& id : expectedSelectedEntityIds)
{

@ -1,187 +1,64 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "EditorDefs.h"
#include "PropertyMotionCtrl.h"
// Qt
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
// AzToolsFramework
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
MotionPropertyCtrl::MotionPropertyCtrl(QWidget *pParent)
: QWidget(pParent)
{
m_motionLabel = new QLabel;
m_pBrowseButton = new QToolButton;
m_pBrowseButton->setIcon(QIcon(":/reflectedPropertyCtrl/img/file_browse.png"));
m_pApplyButton = new QToolButton;
m_pApplyButton->setIcon(QIcon(":/reflectedPropertyCtrl/img/apply.png"));
m_pApplyButton->setFocusPolicy(Qt::StrongFocus);
m_pBrowseButton->setFocusPolicy(Qt::StrongFocus);
QHBoxLayout *pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0, 0, 0, 0);
pLayout->addWidget(m_motionLabel, 1);
pLayout->addWidget(m_pBrowseButton);
pLayout->addWidget(m_pApplyButton);
connect(m_pBrowseButton, &QAbstractButton::clicked, this, &MotionPropertyCtrl::OnBrowseClicked);
connect(m_pApplyButton, &QAbstractButton::clicked, this, &MotionPropertyCtrl::OnApplyClicked);
};
MotionPropertyCtrl::~MotionPropertyCtrl()
{
}
void MotionPropertyCtrl::SetValue(const CReflectedVarMotion &motion)
{
m_motion = motion;
SetLabelText(motion.m_motion);
}
CReflectedVarMotion MotionPropertyCtrl::value() const
{
return m_motion;
}
void MotionPropertyCtrl::OnBrowseClicked()
{
static AZ::Data::AssetType emotionFXMotionAssetType("{00494B8E-7578-4BA2-8B28-272E90680787}"); // from MotionAsset.h in EMotionFX Gem
// Request the AssetBrowser Dialog and set a type filter
AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection(emotionFXMotionAssetType);
selection.SetSelectedAssetId(m_motion.m_assetId);
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
if (product != nullptr)
{
m_motion.m_motion = product->GetRelativePath();
m_motion.m_assetId = product->GetAssetId();
SetLabelText(m_motion.m_motion);
emit ValueChanged(m_motion);
}
}
}
// TODO: Might be able to delete this function
void MotionPropertyCtrl::OnApplyClicked()
{
#if 0
CUIEnumerations &roGeneralProxy = CUIEnumerations::GetUIEnumerationsInstance();
QStringList cSelectedMotions;
size_t nTotalMotions(0);
size_t nCurrentMotion(0);
QString combinedString = GetIEditor()->GetResourceSelectorHost()->GetGlobalSelection("motion");
SplitString(combinedString, cSelectedMotions, ',');
nTotalMotions = cSelectedMotions.size();
for (nCurrentMotion = 0; nCurrentMotion < nTotalMotions; ++nCurrentMotion)
{
QString& rstrCurrentAnimAction = cSelectedMotions[nCurrentMotion];
if (!rstrCurrentAnimAction.isEmpty())
{
m_motion.m_motion = rstrCurrentAnimAction.toLatin1().data();
SetLabelText(m_motion.m_motion);
emit ValueChanged(m_motion);
}
}
#endif
}
QWidget* MotionPropertyCtrl::GetFirstInTabOrder()
{
return m_pBrowseButton;
}
QWidget* MotionPropertyCtrl::GetLastInTabOrder()
{
return m_pApplyButton;
}
void MotionPropertyCtrl::UpdateTabOrder()
{
setTabOrder(m_pBrowseButton, m_pApplyButton);
}
void MotionPropertyCtrl::SetLabelText(const AZStd::string& motion)
{
if (!motion.empty())
{
AZStd::string filename;
if (AzFramework::StringFunc::Path::GetFileName(motion.c_str(), filename))
{
m_motionLabel->setText(filename.c_str());
}
else
{
m_motionLabel->setText(motion.c_str());
}
}
else
{
m_motionLabel->setText("");
}
}
QWidget* MotionPropertyWidgetHandler::CreateGUI(QWidget *pParent)
QWidget* MotionPropertyWidgetHandler::CreateGUI(QWidget* pParent)
{
MotionPropertyCtrl* newCtrl = aznew MotionPropertyCtrl(pParent);
connect(newCtrl, &MotionPropertyCtrl::ValueChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
AzToolsFramework::PropertyAssetCtrl* newCtrl = aznew AzToolsFramework::PropertyAssetCtrl(pParent);
connect(
newCtrl, &AzToolsFramework::PropertyAssetCtrl::OnAssetIDChanged, this, [newCtrl]([[maybe_unused]] AZ::Data::AssetId newAssetId) {
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(
&AzToolsFramework::PropertyEditorGUIMessages::Bus::Handler::OnEditingFinished, newCtrl);
});
return newCtrl;
}
void MotionPropertyWidgetHandler::ConsumeAttribute(MotionPropertyCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
void MotionPropertyWidgetHandler::ConsumeAttribute(
[[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, [[maybe_unused]] AZ::u32 attrib,
[[maybe_unused]] AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
void MotionPropertyWidgetHandler::WriteGUIValuesIntoProperty(size_t index, MotionPropertyCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
void MotionPropertyWidgetHandler::WriteGUIValuesIntoProperty(
[[maybe_unused]] size_t index, [[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, property_t& instance,
[[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarMotion val = GUI->value();
CReflectedVarMotion val;
val.m_motion = GUI->GetCurrentAssetHint();
val.m_assetId = GUI->GetSelectedAssetID();
instance = static_cast<property_t>(val);
}
bool MotionPropertyWidgetHandler::ReadValuesIntoGUI(size_t index, MotionPropertyCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
bool MotionPropertyWidgetHandler::ReadValuesIntoGUI(
[[maybe_unused]] size_t index, [[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, const property_t& instance,
[[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarMotion val = instance;
GUI->SetValue(val);
static const AZ::Data::AssetType emotionFXMotionAssetType(
"{00494B8E-7578-4BA2-8B28-272E90680787}"); // from MotionAsset.h in EMotionFX Gem
GUI->blockSignals(true);
GUI->SetSelectedAssetID(instance.m_assetId);
GUI->SetCurrentAssetType(emotionFXMotionAssetType);
GUI->blockSignals(false);
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyMotionCtrl.cpp>

@ -1,92 +1,67 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYMOTIONCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYMOTIONCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include "ReflectedVar.h"
#include <QWidget>
#include <QPointer>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/base.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <QPointer>
#include <QWidget>
#endif
class QToolButton;
class QLabel;
class QHBoxLayout;
namespace AzToolsFramework
{
class PropertyAssetCtrl;
}
class MotionPropertyCtrl
: public QWidget
class MotionPropertyWidgetHandler : QObject,
public AzToolsFramework::PropertyHandler<CReflectedVarMotion, AzToolsFramework::PropertyAssetCtrl>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(MotionPropertyCtrl, AZ::SystemAllocator, 0);
MotionPropertyCtrl(QWidget* pParent = nullptr);
virtual ~MotionPropertyCtrl();
CReflectedVarMotion value() const;
QWidget* GetFirstInTabOrder();
QWidget* GetLastInTabOrder();
void UpdateTabOrder();
signals:
void ValueChanged(CReflectedVarMotion value);
public:
AZ_CLASS_ALLOCATOR(MotionPropertyWidgetHandler, AZ::SystemAllocator, 0);
public slots:
void SetValue(const CReflectedVarMotion& motion);
virtual AZ::u32 GetHandlerName(void) const override
{
return AZ_CRC("Motion", 0xf5fea1e8);
}
protected slots:
void OnBrowseClicked();
void OnApplyClicked();
virtual bool IsDefaultHandler() const override
{
return true;
}
private:
void SetLabelText(const AZStd::string& motion);
virtual QWidget* GetFirstInTabOrder(AzToolsFramework::PropertyAssetCtrl* widget) override
{
return widget->GetFirstInTabOrder();
}
QToolButton* m_pBrowseButton;
QToolButton* m_pApplyButton;
QLabel* m_motionLabel;
virtual QWidget* GetLastInTabOrder(AzToolsFramework::PropertyAssetCtrl* widget) override
{
return widget->GetLastInTabOrder();
}
CReflectedVarMotion m_motion;
};
class MotionPropertyWidgetHandler
: QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarMotion, MotionPropertyCtrl >
{
public:
AZ_CLASS_ALLOCATOR(MotionPropertyWidgetHandler, AZ::SystemAllocator, 0);
virtual AZ::u32 GetHandlerName(void) const override { return AZ_CRC("Motion", 0xf5fea1e8); }
virtual bool IsDefaultHandler() const override { return true; }
virtual QWidget* GetFirstInTabOrder(MotionPropertyCtrl* widget) override { return widget->GetFirstInTabOrder(); }
virtual QWidget* GetLastInTabOrder(MotionPropertyCtrl* widget) override { return widget->GetLastInTabOrder(); }
virtual void UpdateWidgetInternalTabbing(MotionPropertyCtrl* widget) override { widget->UpdateTabOrder(); }
virtual void UpdateWidgetInternalTabbing(AzToolsFramework::PropertyAssetCtrl* widget) override
{
widget->UpdateTabOrder();
}
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(MotionPropertyCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(size_t index, MotionPropertyCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(size_t index, MotionPropertyCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual void ConsumeAttribute(
AzToolsFramework::PropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue,
const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(
size_t index, AzToolsFramework::PropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(
size_t index, AzToolsFramework::PropertyAssetCtrl* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYMOTIONCTRL_H

@ -232,7 +232,6 @@ int EditorViewportWidget::OnCreate()
{
m_renderer = GetIEditor()->GetRenderer();
m_engine = GetIEditor()->Get3DEngine();
assert(m_engine);
CreateRenderContext();
@ -793,8 +792,14 @@ void EditorViewportWidget::OnRender()
// This is necessary so that automated editor tests using the null renderer to test systems like dynamic vegetation
// are still able to manipulate the current logical camera position, even if nothing is rendered.
GetIEditor()->GetSystem()->SetViewCamera(m_Camera);
GetIEditor()->GetRenderer()->SetCamera(gEnv->pSystem->GetViewCamera());
m_engine->RenderWorld(0, SRenderingPassInfo::CreateGeneralPassRenderingInfo(m_Camera), __FUNCTION__);
if (GetIEditor()->GetRenderer())
{
GetIEditor()->GetRenderer()->SetCamera(gEnv->pSystem->GetViewCamera());
}
if (m_engine)
{
m_engine->RenderWorld(0, SRenderingPassInfo::CreateGeneralPassRenderingInfo(m_Camera), __FUNCTION__);
}
return;
}
@ -886,7 +891,7 @@ void EditorViewportWidget::OnBeginPrepareRender()
fov = 2 * atanf((h * tan(fov / 2)) / maxTargetHeight);
}
}
m_Camera.SetFrustum(w, h, fov, fNearZ, gEnv->p3DEngine->GetMaxViewDistance());
m_Camera.SetFrustum(w, h, fov, fNearZ);
}
GetIEditor()->GetSystem()->SetViewCamera(m_Camera);
@ -2423,7 +2428,10 @@ void EditorViewportWidget::SetDefaultCamera()
return;
}
ResetToViewSourceType(ViewSourceType::None);
gEnv->p3DEngine->GetPostEffectBaseGroup()->SetParam("Dof_Active", 0.0f);
if (gEnv->p3DEngine)
{
gEnv->p3DEngine->GetPostEffectBaseGroup()->SetParam("Dof_Active", 0.0f);
}
GetViewManager()->SetCameraObjectId(m_cameraObjectId);
SetName(m_defaultViewName);
SetViewTM(m_defaultViewTM);
@ -2606,8 +2614,7 @@ bool EditorViewportWidget::GetActiveCameraPosition(AZ::Vector3& cameraPos)
{
if (GetIEditor()->IsInGameMode())
{
const Vec3 camPos = m_engine->GetRenderingCamera().GetPosition();
cameraPos = LYVec3ToAZVec3(camPos);
cameraPos = m_renderViewport->GetViewportContext()->GetCameraTransform().GetTranslation();
}
else
{

@ -139,7 +139,10 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE
// Make sure we unload any unused CGFs before exporting so that they don't end up in
// the level data.
pEditor->Get3DEngine()->FreeUnusedCGFResources();
if (pEditor->Get3DEngine())
{
pEditor->Get3DEngine()->FreeUnusedCGFResources();
}
CCryEditDoc* pDocument = pEditor->GetDocument();
@ -282,7 +285,7 @@ void CGameExporter::ExportVisAreas(const char* pszGamePath, EEndian eExportEndia
SHotUpdateInfo exportInfo;
I3DEngine* p3DEngine = pEditor->Get3DEngine();
if (eExportEndian == GetPlatformEndian()) // skip second export, this data is common for PC and consoles
if (p3DEngine && (eExportEndian == GetPlatformEndian())) // skip second export, this data is common for PC and consoles
{
std::vector<struct IStatObj*>* pTempBrushTable = NULL;
std::vector<_smart_ptr<IMaterial>>* pTempMatsTable = NULL;
@ -367,25 +370,28 @@ void CGameExporter::ExportLevelData(const QString& path, bool bExportMission)
QString missionFileName;
QString currentMissionFileName;
I3DEngine* p3DEngine = pEditor->Get3DEngine();
for (int i = 0; i < pDocument->GetMissionCount(); i++)
if (p3DEngine)
{
CMission* pMission = pDocument->GetMission(i);
for (int i = 0; i < pDocument->GetMissionCount(); i++)
{
CMission* pMission = pDocument->GetMission(i);
QString name = pMission->GetName();
name.replace(' ', '_');
missionFileName = QStringLiteral("Mission_%1.xml").arg(name);
QString name = pMission->GetName();
name.replace(' ', '_');
missionFileName = QStringLiteral("Mission_%1.xml").arg(name);
XmlNodeRef missionDescNode = missionsNode->newChild("Mission");
missionDescNode->setAttr("Name", pMission->GetName().toUtf8().data());
missionDescNode->setAttr("File", missionFileName.toUtf8().data());
missionDescNode->setAttr("CGFCount", p3DEngine->GetLoadedObjectCount());
XmlNodeRef missionDescNode = missionsNode->newChild("Mission");
missionDescNode->setAttr("Name", pMission->GetName().toUtf8().data());
missionDescNode->setAttr("File", missionFileName.toUtf8().data());
missionDescNode->setAttr("CGFCount", p3DEngine->GetLoadedObjectCount());
int nProgressBarRange = m_numExportedMaterials / 10 + p3DEngine->GetLoadedObjectCount();
missionDescNode->setAttr("ProgressBarRange", nProgressBarRange);
int nProgressBarRange = m_numExportedMaterials / 10 + p3DEngine->GetLoadedObjectCount();
missionDescNode->setAttr("ProgressBarRange", nProgressBarRange);
if (pMission == pCurrentMission)
{
currentMissionFileName = missionFileName;
if (pMission == pCurrentMission)
{
currentMissionFileName = missionFileName;
}
}
}
@ -413,7 +419,10 @@ void CGameExporter::ExportLevelData(const QString& path, bool bExportMission)
XmlNodeRef missionNode = rootAction->createNode("Mission");
pCurrentMission->Export(missionNode, objectsNode);
missionNode->setAttr("CGFCount", p3DEngine->GetLoadedObjectCount());
if (p3DEngine)
{
missionNode->setAttr("CGFCount", p3DEngine->GetLoadedObjectCount());
}
//if (!CFileUtil::OverwriteFile( path+currentMissionFileName ))
// return;
@ -483,6 +492,11 @@ void CGameExporter::ExportLevelInfo(const QString& path)
//////////////////////////////////////////////////////////////////////////
void CGameExporter::ExportMapInfo(XmlNodeRef& node)
{
if (!GetIEditor()->Get3DEngine())
{
return;
}
XmlNodeRef info = node->newChild("LevelInfo");
IEditor* pEditor = GetIEditor();

@ -22,7 +22,6 @@
#include "Include/ITransformManipulator.h"
#include "ActionManager.h"
#include "Settings.h"
#include "Objects/SelectionGroup.h"
#include "Include/IObjectManager.h"
#include "MathConversion.h"
@ -191,10 +190,12 @@ void CInfoBar::IdleUpdate()
Vec3 marker = GetIEditor()->GetMarkerPosition();
CSelectionGroup* selection = GetIEditor()->GetSelection();
if (selection->GetCount() != m_numSelected)
int selectedEntitiesCount = 0;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
selectedEntitiesCount, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntitiesCount);
if (selectedEntitiesCount != m_numSelected)
{
m_numSelected = selection->GetCount();
m_numSelected = selectedEntitiesCount;
updateUI = true;
}

@ -525,6 +525,11 @@ void CMaterialManager::OnEditorNotifyEvent(EEditorNotifyEvent event)
//////////////////////////////////////////////////////////////////////////
void CMaterialManager::ReloadDirtyMaterials()
{
if (!GetIEditor()->Get3DEngine())
{
return;
}
IMaterialManager* runtimeMaterialManager = GetIEditor()->Get3DEngine()->GetMaterialManager();
uint32 mtlCount = 0;
@ -743,12 +748,15 @@ int CMaterialManager::GetHighlightFlags(CMaterial* pMaterial) const
result |= eHighlight_NoSurfaceType;
}
if (ISurfaceTypeManager* pSurfaceManager = GetIEditor()->Get3DEngine()->GetMaterialManager()->GetSurfaceTypeManager())
if (GetIEditor()->Get3DEngine())
{
const ISurfaceType* pSurfaceType = pSurfaceManager->GetSurfaceTypeByName(surfaceTypeName.toUtf8().data());
if (pSurfaceType && pSurfaceType->GetBreakability() != 0)
if (ISurfaceTypeManager* pSurfaceManager = GetIEditor()->Get3DEngine()->GetMaterialManager()->GetSurfaceTypeManager())
{
result |= eHighlight_Breakable;
const ISurfaceType* pSurfaceType = pSurfaceManager->GetSurfaceTypeByName(surfaceTypeName.toUtf8().data());
if (pSurfaceType && pSurfaceType->GetBreakability() != 0)
{
result |= eHighlight_Breakable;
}
}
}

@ -212,8 +212,11 @@ void CMission::SyncContent(bool bRetrieve, bool bIgnoreObjects, [[maybe_unused]]
else
{
// Save time of day.
m_timeOfDay = XmlHelpers::CreateXmlNode("TimeOfDay");
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_timeOfDay, false);
if (GetIEditor()->Get3DEngine())
{
m_timeOfDay = XmlHelpers::CreateXmlNode("TimeOfDay");
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_timeOfDay, false);
}
if (!bIgnoreObjects)
{

@ -138,6 +138,7 @@ bool CLevelShaderCache::SaveBuffer(QString& textBuffer)
void CLevelShaderCache::Update()
{
IRenderer* pRenderer = gEnv->pRenderer;
if (pRenderer)
{
QString buf;
char* str = NULL;

@ -97,6 +97,9 @@ namespace AZ
};
} // DataTypes
} // SceneAPI
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::DataTypes::Color, "{937E3BF8-5204-4D40-A8DA-C8F083C89F9F}");
} // AZ
namespace AZStd

@ -11,6 +11,8 @@
*/
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
@ -18,6 +20,31 @@ namespace AZ
{
namespace GraphData
{
void AnimationData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AnimationData, SceneAPI::DataTypes::IAnimationData>()
->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneAPI::DataTypes::IAnimationData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetKeyFrameCount", &SceneAPI::DataTypes::IAnimationData::GetKeyFrameCount)
->Method("GetKeyFrame", &SceneAPI::DataTypes::IAnimationData::GetKeyFrame)
->Method("GetTimeStepBetweenFrames", &SceneAPI::DataTypes::IAnimationData::GetTimeStepBetweenFrames);
behaviorContext->Class<AnimationData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene");
}
}
AnimationData::AnimationData()
: m_timeStepBetweenFrames(1.0/30.0) // default value
{
@ -61,6 +88,32 @@ namespace AZ
}
void BlendShapeAnimationData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<BlendShapeAnimationData, SceneAPI::DataTypes::IBlendShapeAnimationData>()
->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneAPI::DataTypes::IBlendShapeAnimationData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetBlendShapeName", &SceneAPI::DataTypes::IBlendShapeAnimationData::GetBlendShapeName)
->Method("GetKeyFrameCount", &SceneAPI::DataTypes::IBlendShapeAnimationData::GetKeyFrameCount)
->Method("GetKeyFrame", &SceneAPI::DataTypes::IBlendShapeAnimationData::GetKeyFrame)
->Method("GetTimeStepBetweenFrames", &SceneAPI::DataTypes::IBlendShapeAnimationData::GetTimeStepBetweenFrames);
behaviorContext->Class<BlendShapeAnimationData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene");
}
}
BlendShapeAnimationData::BlendShapeAnimationData()
: m_timeStepBetweenFrames(1 / 30.0) // default value
{

@ -30,6 +30,8 @@ namespace AZ
public:
AZ_RTTI(AnimationData, "{D350732E-4727-41C8-95E0-FBAF5F2AC074}", SceneAPI::DataTypes::IAnimationData);
static void Reflect(ReflectContext* context);
SCENE_DATA_API AnimationData();
SCENE_DATA_API ~AnimationData() override = default;
SCENE_DATA_API virtual void AddKeyFrame(const SceneAPI::DataTypes::MatrixType& keyFrameTransform);
@ -53,6 +55,8 @@ namespace AZ
public:
AZ_RTTI(BlendShapeAnimationData, "{02766CCF-BDA7-46B6-9BB1-58A90C1AD6AA}", SceneAPI::DataTypes::IBlendShapeAnimationData);
static void Reflect(ReflectContext* context);
SCENE_DATA_API BlendShapeAnimationData();
SCENE_DATA_API ~BlendShapeAnimationData() override = default;
SCENE_DATA_API void CloneAttributesFrom(const IGraphObject* sourceObject) override;

@ -12,9 +12,13 @@
#include <AzCore/Casting/numeric_cast.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::DataTypes::IBlendShapeData::Face, "{C972EC9A-3A5C-47CD-9A92-ECB4C0C0451C}");
namespace SceneData
{
namespace GraphData
@ -23,6 +27,82 @@ namespace AZ
BlendShapeData::~BlendShapeData() = default;
void BlendShapeData::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<BlendShapeData, SceneAPI::DataTypes::IBlendShapeData>()
->Version(1);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneAPI::DataTypes::IBlendShapeData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetUsedControlPointCount", &SceneAPI::DataTypes::IBlendShapeData::GetUsedControlPointCount)
->Method("GetControlPointIndex", &SceneAPI::DataTypes::IBlendShapeData::GetControlPointIndex)
->Method("GetUsedPointIndexForControlPoint", &SceneAPI::DataTypes::IBlendShapeData::GetUsedPointIndexForControlPoint)
->Method("GetVertexCount", &SceneAPI::DataTypes::IBlendShapeData::GetVertexCount)
->Method("GetFaceCount", &SceneAPI::DataTypes::IBlendShapeData::GetFaceCount)
->Method("GetFaceInfo", &SceneAPI::DataTypes::IBlendShapeData::GetFaceInfo)
->Method("GetPosition", &SceneAPI::DataTypes::IBlendShapeData::GetPosition)
->Method("GetNormal", &SceneAPI::DataTypes::IBlendShapeData::GetNormal)
->Method("GetFaceVertexIndex", &SceneAPI::DataTypes::IBlendShapeData::GetFaceVertexIndex);
behaviorContext->Class<SceneAPI::DataTypes::IBlendShapeData::Face>("BlendShapeDataFace")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetVertexIndex", [](const SceneAPI::DataTypes::IBlendShapeData::Face& self, int index)
{
if (index >= 0 && index < 3)
{
return self.vertexIndex[index];
}
return aznumeric_cast<unsigned int>(0);
});
behaviorContext->Class<BlendShapeData>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("GetUV", &BlendShapeData::GetUV)
->Method("GetTangent", [](const BlendShapeData& self, size_t index)
{
if (index < self.GetTangents().size())
{
return self.GetTangents().at(index);
}
AZ_Error("SceneGraphData", false, "Cannot get to tangent at index(%zu)", index);
return Vector4::CreateZero();
})
->Method("GetBitangent", [](const BlendShapeData& self, size_t index)
{
if (index < self.GetBitangents().size())
{
return self.GetBitangents().at(index);
}
AZ_Error("SceneGraphData", false, "Cannot get to bitangents at index(%zu)", index);
return Vector3::CreateZero();
})
->Method("GetColor", [](const BlendShapeData& self, AZ::u8 colorSetIndex, AZ::u8 colorIndex)
{
SceneAPI::DataTypes::Color color(0,0,0,0);
if (colorSetIndex < MaxNumColorSets)
{
const AZStd::vector<SceneAPI::DataTypes::Color>& colorChannel = self.GetColors(colorSetIndex);
if (colorIndex < colorChannel.size())
{
return colorChannel[colorIndex];
}
}
AZ_Error("SceneGraphData", false, "Cannot get to color setIndex(%d) at colorIndex(%d)", colorSetIndex, colorIndex);
return color;
});
}
}
void BlendShapeData::AddPosition(const Vector3& position)
{
m_positions.push_back(position);

@ -31,6 +31,8 @@ namespace AZ
public:
AZ_RTTI(BlendShapeData, "{FF875C22-2E4F-4CE3-BA49-09BF78C70A09}", SceneAPI::DataTypes::IBlendShapeData)
SCENE_DATA_API static void Reflect(ReflectContext* context);
// Maximum number of color sets matches limitation set in assImp (AI_MAX_NUMBER_OF_COLOR_SETS)
static constexpr AZ::u8 MaxNumColorSets = 8;
// Maximum number of uv sets matches limitation set in assImp (AI_MAX_NUMBER_OF_TEXTURECOORDS)

@ -16,8 +16,6 @@
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::DataTypes::Color, "{937E3BF8-5204-4D40-A8DA-C8F083C89F9F}");
namespace SceneData
{
namespace GraphData
@ -40,7 +38,7 @@ namespace AZ
->Method("GetCount", &MeshVertexColorData::GetCount )
->Method("GetColor", &MeshVertexColorData::GetColor);
behaviorContext->Class<AZ::SceneAPI::DataTypes::Color>("MeshVertexColor")
behaviorContext->Class<AZ::SceneAPI::DataTypes::Color>("VertexColor")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Property("red", BehaviorValueGetter(&AZ::SceneAPI::DataTypes::Color::red), nullptr)

@ -81,8 +81,9 @@ namespace AZ
SceneData::SceneNodeSelectionList::Reflect(context);
// Graph objects
context->Class<AZ::SceneData::GraphData::AnimationData>()->Version(1);
context->Class<AZ::SceneData::GraphData::BlendShapeData>()->Version(1);
AZ::SceneData::GraphData::AnimationData::Reflect(context);
AZ::SceneData::GraphData::BlendShapeAnimationData::Reflect(context);
AZ::SceneData::GraphData::BlendShapeData::Reflect(context);
AZ::SceneData::GraphData::BoneData::Reflect(context);
AZ::SceneData::GraphData::MaterialData::Reflect(context);
AZ::SceneData::GraphData::MeshData::Reflect(context);
@ -107,6 +108,9 @@ namespace AZ
AZ::SceneData::GraphData::MeshVertexUVData::Reflect(context);
AZ::SceneData::GraphData::MeshVertexTangentData::Reflect(context);
AZ::SceneData::GraphData::MeshVertexBitangentData::Reflect(context);
AZ::SceneData::GraphData::AnimationData::Reflect(context);
AZ::SceneData::GraphData::BlendShapeAnimationData::Reflect(context);
AZ::SceneData::GraphData::BlendShapeData::Reflect(context);
}
} // namespace SceneAPI
} // namespace AZ

@ -29,6 +29,8 @@
#include <SceneAPI/SceneData/GraphData/MeshVertexColorData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexUVData.h>
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
namespace AZ
{
@ -101,6 +103,53 @@ namespace AZ
tangentData->SetTangentSetIndex(2);
return true;
}
else if (data.get_type_info().m_id == azrtti_typeid<AZ::SceneData::GraphData::AnimationData>())
{
auto* animationData = AZStd::any_cast<AZ::SceneData::GraphData::AnimationData>(&data);
animationData->ReserveKeyFrames(3);
animationData->AddKeyFrame(DataTypes::MatrixType::CreateFromValue(1.0));
animationData->AddKeyFrame(DataTypes::MatrixType::CreateFromValue(2.0));
animationData->AddKeyFrame(DataTypes::MatrixType::CreateFromValue(3.0));
animationData->SetTimeStepBetweenFrames(4.0);
return true;
}
else if (data.get_type_info().m_id == azrtti_typeid<AZ::SceneData::GraphData::BlendShapeAnimationData>())
{
auto* blendShapeAnimationData = AZStd::any_cast<AZ::SceneData::GraphData::BlendShapeAnimationData>(&data);
blendShapeAnimationData->SetBlendShapeName("mockBlendShapeName");
blendShapeAnimationData->ReserveKeyFrames(3);
blendShapeAnimationData->AddKeyFrame(1.0);
blendShapeAnimationData->AddKeyFrame(2.0);
blendShapeAnimationData->AddKeyFrame(3.0);
blendShapeAnimationData->SetTimeStepBetweenFrames(4.0);
return true;
}
else if (data.get_type_info().m_id == azrtti_typeid<AZ::SceneData::GraphData::BlendShapeData>())
{
auto* blendShapeData = AZStd::any_cast<AZ::SceneData::GraphData::BlendShapeData>(&data);
blendShapeData->AddPosition({ 1.0, 2.0, 3.0 });
blendShapeData->AddPosition({ 2.0, 3.0, 4.0 });
blendShapeData->AddPosition({ 3.0, 4.0, 5.0 });
blendShapeData->AddNormal({ 0.1, 0.2, 0.3 });
blendShapeData->AddNormal({ 0.2, 0.3, 0.4 });
blendShapeData->AddNormal({ 0.3, 0.4, 0.5 });
blendShapeData->AddTangentAndBitangent(Vector4{ 0.1f, 0.2f, 0.3f, 0.4f }, { 0.0, 0.1, 0.2 });
blendShapeData->AddTangentAndBitangent(Vector4{ 0.2f, 0.3f, 0.4f, 0.5f }, { 0.1, 0.2, 0.3 });
blendShapeData->AddTangentAndBitangent(Vector4{ 0.3f, 0.4f, 0.5f, 0.6f }, { 0.2, 0.3, 0.4 });
blendShapeData->AddUV(Vector2{ 0.9, 0.8 }, 0);
blendShapeData->AddUV(Vector2{ 0.7, 0.7 }, 1);
blendShapeData->AddUV(Vector2{ 0.6, 0.6 }, 2);
blendShapeData->AddColor(DataTypes::Color{ 0.1, 0.2, 0.3, 0.4 }, 0);
blendShapeData->AddColor(DataTypes::Color{ 0.2, 0.3, 0.4, 0.5 }, 1);
blendShapeData->AddColor(DataTypes::Color{ 0.3, 0.4, 0.5, 0.6 }, 2);
blendShapeData->AddFace({ 0, 1, 2 });
blendShapeData->AddFace({ 1, 2, 0 });
blendShapeData->AddFace({ 2, 0, 1 });
blendShapeData->SetVertexIndexToControlPointIndexMap(0, 1);
blendShapeData->SetVertexIndexToControlPointIndexMap(1, 2);
blendShapeData->SetVertexIndexToControlPointIndexMap(2, 0);
return true;
}
return false;
}
@ -296,6 +345,116 @@ namespace AZ
ExpectExecute("TestExpectIntegerEquals(meshVertexTangentData:GetTangentSetIndex(), 2)");
ExpectExecute("TestExpectTrue(meshVertexTangentData:GetTangentSpace(), MeshVertexTangentData.EMotionFX)");
}
TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_AnimationData_AccessWorks)
{
ExpectExecute("animationData = AnimationData()");
ExpectExecute("TestExpectTrue(animationData ~= nil)");
ExpectExecute("MockGraphData.FillData(animationData)");
ExpectExecute("TestExpectIntegerEquals(animationData:GetKeyFrameCount(), 3)");
ExpectExecute("TestExpectFloatEquals(animationData:GetTimeStepBetweenFrames(), 4.0)");
ExpectExecute("TestExpectFloatEquals(animationData:GetKeyFrame(0).basisX.x, 1.0)");
ExpectExecute("TestExpectFloatEquals(animationData:GetKeyFrame(1).basisX.y, 2.0)");
ExpectExecute("TestExpectFloatEquals(animationData:GetKeyFrame(2).basisX.z, 3.0)");
}
TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_BlendShapeAnimationData_AccessWorks)
{
ExpectExecute("blendShapeAnimationData = BlendShapeAnimationData()");
ExpectExecute("TestExpectTrue(blendShapeAnimationData ~= nil)");
ExpectExecute("MockGraphData.FillData(blendShapeAnimationData)");
ExpectExecute("TestExpectTrue(blendShapeAnimationData:GetBlendShapeName() == 'mockBlendShapeName')");
ExpectExecute("TestExpectIntegerEquals(blendShapeAnimationData:GetKeyFrameCount(), 3)");
ExpectExecute("TestExpectFloatEquals(blendShapeAnimationData:GetKeyFrame(0), 1.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeAnimationData:GetKeyFrame(1), 2.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeAnimationData:GetKeyFrame(2), 3.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeAnimationData:GetTimeStepBetweenFrames(), 4.0)");
}
TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_BlendShapeData_AccessWorks)
{
ExpectExecute("blendShapeData = BlendShapeData()");
ExpectExecute("TestExpectTrue(blendShapeData ~= nil)");
ExpectExecute("MockGraphData.FillData(blendShapeData)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetUsedControlPointCount(), 3)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetVertexCount(), 3)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetFaceCount(), 3)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetFaceVertexIndex(0, 2), 2)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetFaceVertexIndex(1, 0), 1)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetFaceVertexIndex(2, 1), 0)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetControlPointIndex(0), 1)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetControlPointIndex(1), 2)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetControlPointIndex(2), 0)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetUsedPointIndexForControlPoint(0), 2)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetUsedPointIndexForControlPoint(1), 0)");
ExpectExecute("TestExpectIntegerEquals(blendShapeData:GetUsedPointIndexForControlPoint(2), 1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(0).x, 1.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(0).y, 2.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(0).z, 3.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(1).x, 2.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(1).y, 3.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(1).z, 4.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(2).x, 3.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(2).y, 4.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetPosition(2).z, 5.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(0).x, 0.1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(0).y, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(0).z, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(1).x, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(1).y, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(1).z, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(2).x, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(2).y, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetNormal(2).z, 0.5)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(0):GetVertexIndex(0), 0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(0):GetVertexIndex(1), 1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(0):GetVertexIndex(2), 2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(1):GetVertexIndex(0), 1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(1):GetVertexIndex(1), 2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(1):GetVertexIndex(2), 0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(2):GetVertexIndex(0), 2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(2):GetVertexIndex(1), 0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetFaceInfo(2):GetVertexIndex(2), 1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 0).x, 0.9)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 0).y, 0.8)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 1).x, 0.7)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 1).y, 0.7)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 2).x, 0.6)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetUV(0, 2).y, 0.6)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(0, 0).red, 0.1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(0, 0).green, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(0, 0).blue, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(0, 0).alpha, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(1, 0).red, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(1, 0).green, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(1, 0).blue, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(1, 0).alpha, 0.5)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(2, 0).red, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(2, 0).green, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(2, 0).blue, 0.5)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetColor(2, 0).alpha, 0.6)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(0).x, 0.1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(0).y, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(0).z, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(0).w, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(1).x, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(1).y, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(1).z, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(1).w, 0.5)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(2).x, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(2).y, 0.4)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(2).z, 0.5)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetTangent(2).w, 0.6)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(0).x, 0.0)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(0).y, 0.1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(0).z, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(1).x, 0.1)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(1).y, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(1).z, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(2).x, 0.2)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(2).y, 0.3)");
ExpectExecute("TestExpectFloatEquals(blendShapeData:GetBitangent(2).z, 0.4)");
}
}
}
}

@ -13,6 +13,7 @@
#pragma once
#include <Atom/Features/SrgSemantics.azsli>
#include <viewsrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include "MaterialInputs/BaseColorInput.azsli"

@ -10,7 +10,6 @@
*
*/
#include <viewsrg.srgi>
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include "./EnhancedPBR_Common.azsli"
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>

@ -10,11 +10,25 @@
*
*/
#include <viewsrg.srgi>
#include "EnhancedPBR_Common.azsli"
// SRGs
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
// Pass Output
#include <Atom/Features/PBR/ForwardSubsurfacePassOutput.azsli>
// Utility
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PBR/AlphaUtils.azsli>
// Custom Surface & Lighting
#include <Atom/Features/PBR/Lighting/EnhancedLighting.azsli>
// Decals
#include <Atom/Features/PBR/Decals.azsli>
// ---------- Material Parameters ----------
@ -39,6 +53,8 @@ COMMON_OPTIONS_DETAIL_MAPS()
#include "MaterialInputs/TransmissionInput.azsli"
// ---------- Vertex Shader ----------
struct VSInput
{
// Base fields (required by the template azsli file)...
@ -67,8 +83,6 @@ struct VSOutput
float2 m_detailUv[UvSetCount] : UV3;
};
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
@ -94,6 +108,9 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
return OUT;
}
// ---------- Pixel Shader ----------
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
{
// ------- Tangents & Bitangets -------
@ -144,6 +161,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
}
}
Surface surface;
surface.position = IN.m_worldPosition;
// ------- Alpha & Clip -------
float2 baseColorUv = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
@ -172,7 +192,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
float3 normal = GetDetailedNormalInputWS(
surface.normal = GetDetailedNormalInputWS(
isFrontFace, IN.m_normal,
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_normalFactor, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, uvMatrix, o_normal_useTexture,
tangents[MaterialSrg::m_detail_allMapsUvIndex], bitangents[MaterialSrg::m_detail_allMapsUvIndex], MaterialSrg::m_detail_normal_texture, MaterialSrg::m_sampler, detailUv, detailLayerNormalFactor, MaterialSrg::m_detail_normal_flipX, MaterialSrg::m_detail_normal_flipY, MaterialSrg::m_detailUvMatrix, o_detail_normal_useTexture);
@ -196,26 +216,19 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
metallic = GetMetallicInput(MaterialSrg::m_metallicMap, MaterialSrg::m_sampler, metallicUv, MaterialSrg::m_metallicFactor, o_metallic_useTexture);
}
// ------- Roughness -------
float2 roughnessUv = IN.m_uv[MaterialSrg::m_roughnessMapUvIndex];
float roughness = GetRoughnessInput(MaterialSrg::m_roughnessMap, MaterialSrg::m_sampler, roughnessUv, MaterialSrg::m_roughnessFactor,
MaterialSrg::m_roughnessLowerBound, MaterialSrg::m_roughnessUpperBound, o_roughness_useTexture);
// ------- Specular -------
float2 specularUv = IN.m_uv[MaterialSrg::m_specularF0MapUvIndex];
float specularF0Factor = GetSpecularInput(MaterialSrg::m_specularF0Map, MaterialSrg::m_sampler, specularUv, MaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
// ------- Emissive -------
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
float2 emissiveUv = IN.m_uv[MaterialSrg::m_emissiveMapUvIndex];
float3 emissive = GetEmissiveInput(MaterialSrg::m_emissiveMap, MaterialSrg::m_sampler, emissiveUv, MaterialSrg::m_emissiveIntensity, MaterialSrg::m_emissiveColor.rgb, o_emissiveEnabled, o_emissive_useTexture);
// ------- Roughness -------
// ------- Occlusion -------
float diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture);
float specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture);
float2 roughnessUv = IN.m_uv[MaterialSrg::m_roughnessMapUvIndex];
surface.roughnessLinear = GetRoughnessInput(MaterialSrg::m_roughnessMap, MaterialSrg::m_sampler, roughnessUv, MaterialSrg::m_roughnessFactor,
MaterialSrg::m_roughnessLowerBound, MaterialSrg::m_roughnessUpperBound, o_roughness_useTexture);
surface.CalculateRoughnessA();
// ------- Subsurface -------
@ -226,33 +239,99 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
// ------- Anisotropy -------
if (o_enableAnisotropy)
{
// Convert the angle from [0..1] = [0 .. 180 degrees] to radians [0 .. PI]
const float anisotropyAngle = MaterialSrg::m_anisotropicAngle * PI;
const float anisotropyFactor = MaterialSrg::m_anisotropicFactor;
surface.anisotropy.Init(surface.normal, tangents[0], bitangents[0], anisotropyAngle, anisotropyFactor, surface.roughnessA);
}
// ------- Lighting Data -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Directional light shadow coordinates
lightingData.shadowCoords = IN.m_shadowCoords;
// ------- Occlusion -------
lightingData.diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture);
lightingData.specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture);
// ------- Emissive -------
float2 emissiveUv = IN.m_uv[MaterialSrg::m_emissiveMapUvIndex];
lightingData.emissiveLighting = GetEmissiveInput(MaterialSrg::m_emissiveMap, MaterialSrg::m_sampler, emissiveUv, MaterialSrg::m_emissiveIntensity, MaterialSrg::m_emissiveColor.rgb, o_emissiveEnabled, o_emissive_useTexture);
// ------- Clearcoat -------
float clearCoatFactor = 0.0;
float clearCoatRoughness = 0.0;
float3 clearCoatNormal = float3(0.0, 0.0, 0.0);
// TODO: Clean up the double uses of these clear coat flags
if(o_clearCoat_enabled && o_clearCoat_feature_enabled)
// [GFX TODO][ATOM-14603]: Clean up the double uses of these clear coat flags
if(o_clearCoat_feature_enabled)
{
float3x3 uvMatrix = MaterialSrg::m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
GetClearCoatInputs(MaterialSrg::m_clearCoatInfluenceMap, IN.m_uv[MaterialSrg::m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_clearCoatFactor, o_clearCoat_factor_useTexture,
MaterialSrg::m_clearCoatRoughnessMap, IN.m_uv[MaterialSrg::m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_clearCoatRoughness, o_clearCoat_roughness_useTexture,
MaterialSrg::m_clearCoatNormalMap, IN.m_uv[MaterialSrg::m_clearCoatNormalMapUvIndex], IN.m_normal, o_clearCoat_normal_useTexture, MaterialSrg::m_clearCoatNormalStrength,
uvMatrix, tangents[MaterialSrg::m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_clearCoatNormalMapUvIndex],
MaterialSrg::m_sampler, isFrontFace,
clearCoatFactor, clearCoatRoughness, clearCoatNormal);
if(o_clearCoat_enabled)
{
float3x3 uvMatrix = MaterialSrg::m_clearCoatNormalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
GetClearCoatInputs(MaterialSrg::m_clearCoatInfluenceMap, IN.m_uv[MaterialSrg::m_clearCoatInfluenceMapUvIndex], MaterialSrg::m_clearCoatFactor, o_clearCoat_factor_useTexture,
MaterialSrg::m_clearCoatRoughnessMap, IN.m_uv[MaterialSrg::m_clearCoatRoughnessMapUvIndex], MaterialSrg::m_clearCoatRoughness, o_clearCoat_roughness_useTexture,
MaterialSrg::m_clearCoatNormalMap, IN.m_uv[MaterialSrg::m_clearCoatNormalMapUvIndex], IN.m_normal, o_clearCoat_normal_useTexture, MaterialSrg::m_clearCoatNormalStrength,
uvMatrix, tangents[MaterialSrg::m_clearCoatNormalMapUvIndex], bitangents[MaterialSrg::m_clearCoatNormalMapUvIndex],
MaterialSrg::m_sampler, isFrontFace,
surface.clearCoat.factor, surface.clearCoat.roughness, surface.clearCoat.normal);
}
// manipulate base layer f0 if clear coat is enabled
// modify base layer's normal incidence reflectance
// for the derivation of the following equation please refer to:
// https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodel/baselayermodification
float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0));
surface.specularF0 = lerp(surface.specularF0, f0 * f0, surface.clearCoat.factor);
}
// Diffuse and Specular response (used in IBL calculations)
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0 - lightingData.specularResponse;
if(o_clearCoat_feature_enabled)
{
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
// ------- Multiscatter -------
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ------- Lighting Calculation -------
// Convert the angle from [0..1] = [0 .. 180 degrees] to radians [0 .. PI]
const float2 anisotropy = float2(MaterialSrg::m_anisotropicAngle * PI, MaterialSrg::m_anisotropicFactor);
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
{
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
}
PbrLightingOutput lightingOutput = PbrLighting(IN,
baseColor, metallic, roughness, specularF0Factor,
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
emissive, diffuseAmbientOcclusion, specularOcclusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
// ------- Opacity -------

@ -50,5 +50,5 @@
]
},
"DrawList" : "forward"
}
"DrawList" : "forwardWithSubsurfaceOutput"
}

@ -49,5 +49,5 @@
]
},
"DrawList" : "forward"
"DrawList" : "forwardWithSubsurfaceOutput"
}

@ -11,7 +11,6 @@
*/
#include <scenesrg.srgi>
#include <viewsrg.srgi>
#include "EnhancedPBR_Common.azsli"
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>

@ -10,11 +10,24 @@
*
*/
#include <viewsrg.srgi>
#include "Skin_Common.azsli"
// SRGs
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
// Pass Output
#include <Atom/Features/PBR/ForwardSubsurfacePassOutput.azsli>
// Utility
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PBR/AlphaUtils.azsli> // TODO: Remove this after OpacityMode is removed from LightingModel
// Custom Surface & Lighting
#include <Atom/Features/PBR/Lighting/SkinLighting.azsli>
// Decals
#include <Atom/Features/PBR/Decals.azsli>
// ---------- Material Parameters ----------
@ -53,6 +66,8 @@ option bool o_blendMask_isBound;
#include "MaterialInputs/TransmissionInput.azsli"
// ---------- Vertex Shader ----------
struct VSInput
{
// Base fields (required by the template azsli file)...
@ -89,8 +104,6 @@ struct VSOutput
float4 m_blendMask : UV8;
};
#include <Atom/Features/PBR/AlphaUtils.azsli> // TODO: Remove this after OpacityMode is removed from LightingModel
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput SkinVS(VSInput IN)
@ -131,6 +144,9 @@ VSOutput SkinVS(VSInput IN)
return OUT;
}
// ---------- Pixel Shader ----------
float3 ApplyBaseColorWrinkleMap(bool shouldApply, float3 baseColor, Texture2D map, sampler mapSampler, float2 uv, float factor)
{
if (shouldApply)
@ -177,6 +193,9 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents, startIndex);
}
Surface surface;
surface.position = IN.m_worldPosition;
// ------- Detail Layer Setup -------
// When the detail maps and the detail blend mask are on the same UV, they both use the transformed detail UVs because they are 'attached' to each other
@ -212,19 +231,18 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.a);
}
float3 normalWS;
if(o_detail_normal_useTexture)
{
float3 normalTS = GetTangentSpaceNormal(normalMapSample, uvMatrix, MaterialSrg::m_normalFactor);
bool applyOverlay = true;
normalWS = ApplyNormalMapOverlayWS(applyOverlay, IN.m_normal, normalTS, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex],
surface.normal = ApplyNormalMapOverlayWS(applyOverlay, IN.m_normal, normalTS, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex],
MaterialSrg::m_detail_normal_texture, MaterialSrg::m_sampler, IN.m_detailUv, MaterialSrg::m_detail_normal_flipX, MaterialSrg::m_detail_normal_flipY,
detailLayerNormalFactor, tangents[MaterialSrg::m_detail_allMapsUvIndex], bitangents[MaterialSrg::m_detail_allMapsUvIndex], MaterialSrg::m_detailUvMatrix);
}
else
{
normalWS = GetWorldSpaceNormal(normalMapSample, IN.m_normal, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex],
surface.normal = GetWorldSpaceNormal(normalMapSample, IN.m_normal, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex],
uvMatrix, MaterialSrg::m_normalFactor);
}
@ -265,23 +283,29 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
baseColor = ApplyTextureOverlay(o_detail_baseColor_useTexture, baseColor, MaterialSrg::m_detail_baseColor_texture, MaterialSrg::m_sampler, IN.m_detailUv, detailLayerBaseColorFactor);
// ------- Roughness -------
float2 roughnessUv = IN.m_uv[MaterialSrg::m_roughnessMapUvIndex];
float roughness = GetRoughnessInput(MaterialSrg::m_roughnessMap, MaterialSrg::m_sampler, roughnessUv, MaterialSrg::m_roughnessFactor,
MaterialSrg::m_roughnessLowerBound, MaterialSrg::m_roughnessUpperBound, o_roughness_useTexture);
// ------- Occlusion -------
float diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture);
float specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture);
if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues && o_blendMask_isBound)
{
// Overlay debug colors to highlight the different blend weights coming from the vertex color stream.
if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_blendMask.r); }
if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_blendMask.g); }
if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_blendMask.b); }
if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_blendMask.a); }
}
// ------- Specular -------
float2 specularUv = IN.m_uv[MaterialSrg::m_specularF0MapUvIndex];
float specularF0Factor = GetSpecularInput(MaterialSrg::m_specularF0Map, MaterialSrg::m_sampler, specularUv, MaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor);
// ------- Roughness -------
float2 roughnessUv = IN.m_uv[MaterialSrg::m_roughnessMapUvIndex];
surface.roughnessLinear = GetRoughnessInput(MaterialSrg::m_roughnessMap, MaterialSrg::m_sampler, roughnessUv, MaterialSrg::m_roughnessFactor,
MaterialSrg::m_roughnessLowerBound, MaterialSrg::m_roughnessUpperBound, o_roughness_useTexture);
surface.CalculateRoughnessA();
// ------- Subsurface -------
float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
@ -291,29 +315,49 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
// ------- Lighting Data -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Directional light shadow coordinates
lightingData.shadowCoords = IN.m_shadowCoords;
// Diffuse and Specular response (used in IBL calculations)
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0 - lightingData.specularResponse;
// ------- Occlusion -------
lightingData.diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture);
lightingData.specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture);
// ------- Lighting Calculation -------
if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues && o_blendMask_isBound)
{
// Overlay debug colors to highlight the different blend weights coming from the vertex color stream.
if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_blendMask.r); }
if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_blendMask.g); }
if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_blendMask.b); }
if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_blendMask.a); }
}
surface.clearCoat.factor = 0.0;
surface.clearCoat.roughness = 0.0;
surface.clearCoat.normal = float3(0.0, 0.0, 0.0);
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
float metallic = 0;
float3 emissive = float3(0,0,0);
float2 anisotropy = float2(0,0);
float clearCoatFactor = 0.0;
float clearCoatRoughness = 0.0;
float3 clearCoatNormal = float3(0.0, 0.0, 0.0);
float alpha = 1;
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
normalWS, tangents[0], bitangents[0], anisotropy,
emissive, diffuseAmbientOcclusion, specularOcclusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData);
// ------- Preparing output -------

@ -42,5 +42,5 @@
]
},
"DrawList" : "forward"
"DrawList" : "forwardWithSubsurfaceOutput"
}

@ -13,6 +13,7 @@
#pragma once
#include <Atom/Features/SrgSemantics.azsli>
#include <viewsrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include "MaterialInputs/BaseColorInput.azsli"

@ -10,10 +10,23 @@
*
*/
// SRGs
#include <viewsrg.srgi>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
// Pass Output
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
// Utility
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PBR/AlphaUtils.azsli>
// Custom Surface & Lighting
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
// Decals
#include <Atom/Features/PBR/Decals.azsli>
// ---------- Material Parameters ----------
@ -47,6 +60,9 @@ DEFINE_LAYER_OPTIONS(o_layer3_)
#include "MaterialInputs/TransmissionInput.azsli"
#include "StandardMultilayerPBR_Common.azsli"
// ---------- Vertex Shader ----------
struct VSInput
{
// Base fields (required by the template azsli file)...
@ -83,8 +99,6 @@ struct VSOutput
float3 m_blendMask : UV7;
};
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput ForwardPassVS(VSInput IN)
@ -115,6 +129,9 @@ VSOutput ForwardPassVS(VSInput IN)
return OUT;
}
// ---------- Pixel Shader ----------
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
{
depth = IN.m_position.z;
@ -144,14 +161,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
if(o_debugDrawMode == DebugDrawMode::BlendMaskValues)
{
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
return MakeDebugOutput(IN, blendMaskValues);
return DebugOutput(blendMaskValues);
}
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
{
GetDepth_Setup(IN.m_blendMask);
float depth = GetDepth(IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
return MakeDebugOutput(IN, float3(depth,depth,depth));
return DebugOutput(float3(depth,depth,depth));
}
// ------- Parallax -------
@ -179,6 +196,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
}
}
Surface surface;
surface.position = IN.m_worldPosition;
// ------- Setup the per-layer UV transforms -------
float2 uvLayer1[UvSetCount];
@ -222,7 +242,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float3 normalTS = ReorientTangentSpaceNormal(layer1_normalTS, layer2_normalTS);
normalTS = ReorientTangentSpaceNormal(normalTS, layer3_normalTS);
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
float3 normalWS = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
// ------- Base Color -------
@ -244,57 +264,74 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float layer3_metallic = GetMetallicInput(MaterialSrg::m_layer3_m_metallicMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_metallicMapUvIndex], MaterialSrg::m_layer3_m_metallicFactor, o_layer3_o_metallic_useTexture);
metallic = BlendLayers(layer1_metallic, layer2_metallic, layer3_metallic, blendMaskValues);
}
// ------- Specular -------
float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
float specularF0Factor = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
// ------- Roughness -------
float layer1_roughness = GetRoughnessInput(MaterialSrg::m_layer1_m_roughnessMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_roughnessMapUvIndex], MaterialSrg::m_layer1_m_roughnessFactor, MaterialSrg::m_layer1_m_roughnessLowerBound, MaterialSrg::m_layer1_m_roughnessUpperBound, o_layer1_o_roughness_useTexture);
float layer2_roughness = GetRoughnessInput(MaterialSrg::m_layer2_m_roughnessMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_roughnessMapUvIndex], MaterialSrg::m_layer2_m_roughnessFactor, MaterialSrg::m_layer2_m_roughnessLowerBound, MaterialSrg::m_layer2_m_roughnessUpperBound, o_layer2_o_roughness_useTexture);
float layer3_roughness = GetRoughnessInput(MaterialSrg::m_layer3_m_roughnessMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_roughnessMapUvIndex], MaterialSrg::m_layer3_m_roughnessFactor, MaterialSrg::m_layer3_m_roughnessLowerBound, MaterialSrg::m_layer3_m_roughnessUpperBound, o_layer3_o_roughness_useTexture);
float roughness = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
surface.roughnessLinear = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
// ------- Specular -------
surface.CalculateRoughnessA();
float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
float specularF0Factor = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
// ------- Subsurface -------
float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
float surfaceScatteringFactor = GetSubsurfaceInput(MaterialSrg::m_subsurfaceScatteringInfluenceMap, MaterialSrg::m_sampler, subsurfaceUv, MaterialSrg::m_subsurfaceScatteringFactor);
// ------- Transmission -------
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
// ------- Lighting Data -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Directional light shadow coordinates
lightingData.shadowCoords = IN.m_shadowCoords;
// ------- Emissive -------
float3 layer1_emissive = GetEmissiveInput(MaterialSrg::m_layer1_m_emissiveMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_emissiveMapUvIndex], MaterialSrg::m_layer1_m_emissiveIntensity, MaterialSrg::m_layer1_m_emissiveColor.rgb, o_layer1_o_emissiveEnabled, o_layer1_o_emissive_useTexture);
float3 layer2_emissive = GetEmissiveInput(MaterialSrg::m_layer2_m_emissiveMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_emissiveMapUvIndex], MaterialSrg::m_layer2_m_emissiveIntensity, MaterialSrg::m_layer2_m_emissiveColor.rgb, o_layer2_o_emissiveEnabled, o_layer2_o_emissive_useTexture);
float3 layer3_emissive = GetEmissiveInput(MaterialSrg::m_layer3_m_emissiveMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_emissiveMapUvIndex], MaterialSrg::m_layer3_m_emissiveIntensity, MaterialSrg::m_layer3_m_emissiveColor.rgb, o_layer3_o_emissiveEnabled, o_layer3_o_emissive_useTexture);
float3 emissive = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
lightingData.emissiveLighting = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
// ------- Occlusion -------
float layer1_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer1_m_diffuseOcclusionFactor, o_layer1_o_diffuseOcclusion_useTexture);
float layer2_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer2_m_diffuseOcclusionFactor, o_layer2_o_diffuseOcclusion_useTexture);
float layer3_diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_diffuseOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_diffuseOcclusionMapUvIndex], MaterialSrg::m_layer3_m_diffuseOcclusionFactor, o_layer3_o_diffuseOcclusion_useTexture);
float diffuseAmbientOcclusion = BlendLayers(layer1_diffuseAmbientOcclusion, layer2_diffuseAmbientOcclusion, layer3_diffuseAmbientOcclusion, blendMaskValues);
lightingData.diffuseAmbientOcclusion = BlendLayers(layer1_diffuseAmbientOcclusion, layer2_diffuseAmbientOcclusion, layer3_diffuseAmbientOcclusion, blendMaskValues);
float layer1_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer1_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer1_m_specularOcclusionFactor, o_layer1_o_specularOcclusion_useTexture);
float layer2_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer2_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer2_m_specularOcclusionFactor, o_layer2_o_specularOcclusion_useTexture);
float layer3_specularOcclusion = GetOcclusionInput(MaterialSrg::m_layer3_m_specularOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularOcclusionMapUvIndex], MaterialSrg::m_layer3_m_specularOcclusionFactor, o_layer3_o_specularOcclusion_useTexture);
float specularOcclusion = BlendLayers(layer1_specularOcclusion, layer2_specularOcclusion, layer3_specularOcclusion, blendMaskValues);
// ------- Subsurface -------
float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
float surfaceScatteringFactor = GetSubsurfaceInput(MaterialSrg::m_subsurfaceScatteringInfluenceMap, MaterialSrg::m_sampler, subsurfaceUv, MaterialSrg::m_subsurfaceScatteringFactor);
// ------- Transmission -------
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
lightingData.specularOcclusion = BlendLayers(layer1_specularOcclusion, layer2_specularOcclusion, layer3_specularOcclusion, blendMaskValues);
// ------- Clearcoat -------
float clearCoatFactor = 0.0f;
float clearCoatRoughness = 0.0f;
float3 clearCoatNormal = float3(0.0, 0.0, 0.0);
if(o_clearCoat_feature_enabled)
{
// --- Layer 1 ---
float layer1_clearCoatFactor = 0.0f;
float layer1_clearCoatRoughness = 0.0f;
float3 layer1_clearCoatNormal = float3(0.0, 0.0, 0.0);
@ -310,6 +347,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer1_clearCoatFactor, layer1_clearCoatRoughness, layer1_clearCoatNormal);
}
// --- Layer 2 ---
float layer2_clearCoatFactor = 0.0f;
float layer2_clearCoatRoughness = 0.0f;
float3 layer2_clearCoatNormal = float3(0.0, 0.0, 0.0);
@ -325,6 +364,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer2_clearCoatFactor, layer2_clearCoatRoughness, layer2_clearCoatNormal);
}
// --- Layer 3 ---
float layer3_clearCoatFactor = 0.0f;
float layer3_clearCoatRoughness = 0.0f;
float3 layer3_clearCoatNormal = float3(0.0, 0.0, 0.0);
@ -340,22 +381,58 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer3_clearCoatFactor, layer3_clearCoatRoughness, layer3_clearCoatNormal);
}
clearCoatFactor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
clearCoatRoughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
// --- Blend Layers ---
surface.clearCoat.factor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
surface.clearCoat.roughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
// [GFX TODO][ATOM-14592] This is not the right way to blend the normals. We need to use ReorientTangentSpaceNormal(), and that requires GetClearCoatInputs() to return the normal in TS instead of WS.
clearCoatNormal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
clearCoatNormal = normalize(clearCoatNormal);
surface.clearCoat.normal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
surface.clearCoat.normal = normalize(surface.clearCoat.normal);
// manipulate base layer f0 if clear coat is enabled
// modify base layer's normal incidence reflectance
// for the derivation of the following equation please refer to:
// https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodel/baselayermodification
float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0));
surface.specularF0 = lerp(surface.specularF0, f0 * f0, surface.clearCoat.factor);
}
// Diffuse and Specular response (used in IBL calculations)
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0 - lightingData.specularResponse;
if(o_clearCoat_feature_enabled)
{
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
// ------- Multiscatter -------
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ------- Lighting Calculation -------
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
{
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
}
PbrLightingOutput lightingOutput = PbrLighting(IN,
baseColor, metallic, roughness, specularF0Factor,
normalWS, tangents[0], bitangents[0], anisotropy,
emissive, diffuseAmbientOcclusion, specularOcclusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
// ------- Opacity -------
@ -375,7 +452,6 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961
uint factorAndQuality = dot(round(float2(saturate(surfaceScatteringFactor), MaterialSrg::m_subsurfaceScatteringQuality) * 255), float2(256, 1));
lightingOutput.m_diffuseColor.w = factorAndQuality * (o_enableSubsurfaceScattering ? 1.0 : -1.0);
lightingOutput.m_scatterDistance = MaterialSrg::m_scatterDistance;
}
@ -394,7 +470,6 @@ ForwardPassOutputWithDepth ForwardPassPS(VSOutput IN, bool isFrontFace : SV_IsFr
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = lightingOutput.m_scatterDistance;
OUT.m_depth = depth;
return OUT;
}
@ -412,7 +487,6 @@ ForwardPassOutput ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : SV_IsFrontFa
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = lightingOutput.m_scatterDistance;
return OUT;
}

@ -13,6 +13,7 @@
#pragma once
#include <Atom/Features/SrgSemantics.azsli>
#include <viewsrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include "MaterialInputs/BaseColorInput.azsli"

@ -10,7 +10,6 @@
*
*/
#include <viewsrg.srgi>
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include "./StandardPBR_Common.azsli"
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>

@ -10,11 +10,25 @@
*
*/
#include <viewsrg.srgi>
#include "StandardPBR_Common.azsli"
// SRGs
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
// Pass Output
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
// Utility
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PBR/AlphaUtils.azsli>
// Custom Surface & Lighting
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
// Decals
#include <Atom/Features/PBR/Decals.azsli>
// ---------- Material Parameters ----------
@ -38,6 +52,8 @@ COMMON_OPTIONS_PARALLAX()
#include "MaterialInputs/TransmissionInput.azsli"
// ---------- Vertex Shader ----------
struct VSInput
{
// Base fields (required by the template azsli file)...
@ -66,8 +82,6 @@ struct VSOutput
float2 m_uv[UvSetCount] : UV1;
};
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput StandardPbr_ForwardPassVS(VSInput IN)
@ -85,6 +99,9 @@ VSOutput StandardPbr_ForwardPassVS(VSInput IN)
return OUT;
}
// ---------- Pixel Shader ----------
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
{
// ------- Tangents & Bitangets -------
@ -112,7 +129,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
{
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor,
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_depthFactor,
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth);
@ -130,7 +147,6 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
Surface surface;
surface.position = IN.m_worldPosition.xyz;
// ------- Alpha & Clip -------
float2 baseColorUv = IN.m_uv[MaterialSrg::m_baseColorMapUvIndex];
@ -162,9 +178,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// ------- Specular -------
float2 specularUv = IN.m_uv[MaterialSrg::m_specularF0MapUvIndex];
float specularF0 = GetSpecularInput(MaterialSrg::m_specularF0Map, MaterialSrg::m_sampler, specularUv, MaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
float specularF0Factor = GetSpecularInput(MaterialSrg::m_specularF0Map, MaterialSrg::m_sampler, specularUv, MaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
surface.SetAlbedoAndSpecularF0(baseColor, specularF0, metallic);
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
// ------- Roughness -------
@ -175,25 +191,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
// ------- Subsurface -------
float2 subsurfaceUv = IN.m_uv[MaterialSrg::m_subsurfaceScatteringInfluenceMapUvIndex];
float surfaceScatteringFactor = GetSubsurfaceInput(MaterialSrg::m_subsurfaceScatteringInfluenceMap, MaterialSrg::m_sampler, subsurfaceUv, MaterialSrg::m_subsurfaceScatteringFactor);
// ------- Transmission -------
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
// ------- Anisotropy -------
if (o_enableAnisotropy)
{
const float anisotropyAngle = 0.0f;
const float anisotropyFactor = 0.0f;
surface.anisotropy.Init(surface.normal, tangents[0], bitangents[0], anisotropyAngle, anisotropyFactor, surface.roughnessA);
}
float surfaceScatteringFactor = 0.0f;
surface.transmission.InitializeToZero();
// ------- Lighting Data -------
@ -250,9 +249,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
// Multiscatter compensation factor
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ------- Multiscatter -------
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ------- Lighting Calculation -------
@ -312,8 +311,8 @@ ForwardPassOutputWithDepth StandardPbr_ForwardPassPS(VSOutput IN, bool isFrontFa
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = lightingOutput.m_scatterDistance;
OUT.m_depth = depth;
return OUT;
}
@ -330,7 +329,6 @@ ForwardPassOutput StandardPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace :
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = lightingOutput.m_scatterDistance;
return OUT;
}

@ -11,7 +11,6 @@
*/
#include <scenesrg.srgi>
#include <viewsrg.srgi>
#include "StandardPBR_Common.azsli"
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>

@ -148,22 +148,6 @@
},
"LoadAction": "Clear"
}
},
{
"Name": "ScatterDistanceOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
@ -258,23 +242,6 @@
"AssetRef": {
"FilePath": "Textures/BRDFTexture.attimage"
}
},
{
"Name": "ScatterDistanceImage",
"SizeSource": {
"Source": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
},
"MultisampleSource": {
"Pass": "This",
"Attachment": "DepthStencilInputOutput"
},
"ImageDescriptor": {
"Format": "R11G11B10_FLOAT",
"SharedQueueMask": "Graphics"
}
}
],
"Connections": [
@ -319,13 +286,6 @@
"Pass": "This",
"Attachment": "BRDFTexture"
}
},
{
"LocalSlot": "ScatterDistanceOutput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "ScatterDistanceImage"
}
}
]
}

@ -0,0 +1,158 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "PassAsset",
"ClassData": {
"PassTemplate": {
"Name": "ForwardSubsurfaceMSAAPassTemplate",
"PassClass": "RasterPass",
"Slots": [
// Inputs...
{
"Name": "BRDFTextureInput",
"ShaderInputName": "m_brdfMap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "DirectionalLightShadowmap",
"ShaderInputName": "m_directionalLightShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ExponentialShadowmapDirectional",
"ShaderInputName": "m_directionalLightExponentialShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ProjectedShadowmap",
"ShaderInputName": "m_projectedShadowmaps",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "ExponentialShadowmapProjected",
"ShaderInputName": "m_projectedExponentialShadowmap",
"SlotType": "Input",
"ScopeAttachmentUsage": "Shader",
"ImageViewDesc": {
"IsArray": 1
}
},
{
"Name": "TileLightData",
"SlotType": "Input",
"ShaderInputName": "m_tileLightData",
"ScopeAttachmentUsage": "Shader"
},
{
"Name": "LightListRemapped",
"SlotType": "Input",
"ShaderInputName": "m_lightListRemapped",
"ScopeAttachmentUsage": "Shader"
},
// Input/Outputs...
{
"Name": "DepthStencilInputOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "DepthStencil"
},
{
"Name": "DiffuseOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "SpecularOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "AlbedoOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "SpecularF0Output",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
{
"Name": "NormalOutput",
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
// Outputs...
{
"Name": "ScatterDistanceOutput",
"SlotType": "Output",
"ScopeAttachmentUsage": "RenderTarget",
"LoadStoreAction": {
"ClearValue": {
"Value": [
0.0,
0.0,
0.0,
0.0
]
},
"LoadAction": "Clear"
}
}
],
"ImageAttachments": [
{
"Name": "BRDFTexture",
"Lifetime": "Imported",
"AssetRef": {
"FilePath": "Textures/BRDFTexture.attimage"
}
},
{
"Name": "ScatterDistanceImage",
"SizeSource": {
"Source": {
"Pass": "Parent",
"Attachment": "SwapChainOutput"
}
},
"MultisampleSource": {
"Pass": "This",
"Attachment": "DepthStencilInputOutput"
},
"ImageDescriptor": {
"Format": "R11G11B10_FLOAT",
"SharedQueueMask": "Graphics"
}
}
],
"Connections": [
{
"LocalSlot": "BRDFTextureInput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "BRDFTexture"
}
},
{
"LocalSlot": "ScatterDistanceOutput",
"AttachmentRef": {
"Pass": "This",
"Attachment": "ScatterDistanceImage"
}
}
]
}
}
}

@ -127,6 +127,106 @@
}
}
},
{
"Name": "ForwardSubsurfaceMSAAPass",
"TemplateName": "ForwardSubsurfaceMSAAPassTemplate",
"Connections": [
// Inputs...
{
"LocalSlot": "DirectionalLightShadowmap",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DirectionalShadowmap"
}
},
{
"LocalSlot": "ExponentialShadowmapDirectional",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DirectionalESM"
}
},
{
"LocalSlot": "ProjectedShadowmap",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "ProjectedShadowmap"
}
},
{
"LocalSlot": "ExponentialShadowmapProjected",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "ProjectedESM"
}
},
{
"LocalSlot": "TileLightData",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "TileLightData"
}
},
{
"LocalSlot": "LightListRemapped",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "LightListRemapped"
}
},
// Input/Outputs...
{
"LocalSlot": "DepthStencilInputOutput",
"AttachmentRef": {
"Pass": "Parent",
"Attachment": "DepthStencil"
}
},
{
"LocalSlot": "DiffuseOutput",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Attachment": "DiffuseOutput"
}
},
{
"LocalSlot": "SpecularOutput",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Attachment": "SpecularOutput"
}
},
{
"LocalSlot": "AlbedoOutput",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Attachment": "AlbedoOutput"
}
},
{
"LocalSlot": "SpecularF0Output",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Attachment": "SpecularF0Output"
}
},
{
"LocalSlot": "NormalOutput",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Attachment": "NormalOutput"
}
}
],
"PassData": {
"$type": "RasterPassData",
"DrawListTag": "forwardWithSubsurfaceOutput",
"PipelineViewTag": "MainCamera",
"PassSrgAsset": {
"FilePath": "shaderlib/atom/features/pbr/forwardpasssrg.azsli:PassSrg"
}
}
},
{
"Name": "DiffuseGlobalIlluminationPass",
"TemplateName": "DiffuseGlobalIlluminationPassTemplate",
@ -320,7 +420,7 @@
{
"LocalSlot": "Input",
"AttachmentRef": {
"Pass": "ForwardMSAAPass",
"Pass": "ForwardSubsurfaceMSAAPass",
"Attachment": "ScatterDistanceOutput"
}
}

@ -48,6 +48,10 @@
"Name": "ForwardMSAAPassTemplate",
"Path": "Passes/ForwardMSAA.pass"
},
{
"Name": "ForwardSubsurfaceMSAAPassTemplate",
"Path": "Passes/ForwardSubsurfaceMSAA.pass"
},
{
"Name": "MainPipeline",
"Path": "Passes/MainPipeline.pass"

@ -12,7 +12,6 @@
#pragma once
// TODO: Move this to LightingModel.azsli
option enum class OpacityMode {Opaque, Cutout, Blended, TintedTransparent} o_opacity_mode;
void CheckClipping(float alpha, float opacityFactor)

@ -1,7 +1,23 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
// ------------------------------------------------------------------------------
// NOTE: The following must be included or defined before including this file:
// - Surface - LightingData
// ---------------------------------------------------------------------------------
#include <Atom/Features/PBR/LightingOptions.azsli>
#include <Atom/Features/PBR/Surface.azsli>
// Analytical integation (approximation) of diffusion profile over radius, could be replaced by other pre integrated kernels
// such as sum of Gaussian

@ -12,23 +12,27 @@
#pragma once
// ------------------------------------------------------------------------------
// NOTE: The following must be included or defined before including this file:
// - Surface
// ---------------------------------------------------------------------------------
#include <Atom/Features/MatrixUtility.azsli>
#include <Atom/Features/Decals/DecalTextureUtil.azsli>
#include <Atom/Features/LightCulling/LightCullingTileIterator.azsli>
#include <Atom/Features/PBR/Surface.azsli>
void ApplyDecal(uint currDecalIndex, inout Surface surface);
void ApplyDecals(inout LightCullingTileIterator tileIterator, inout Surface surface)
{
tileIterator.LoadAdvance();
while( !tileIterator.IsDone() )
{
uint currDecalIndex = tileIterator.GetValue();
while( !tileIterator.IsDone() )
{
uint currDecalIndex = tileIterator.GetValue();
tileIterator.LoadAdvance();
ApplyDecal(currDecalIndex, surface);
ApplyDecal(currDecalIndex, surface);
}
}
@ -44,13 +48,13 @@ float GetDecalAttenuation(float3 surfNormal, float3 decalUp, float decalAngleAtt
void ApplyDecal(uint currDecalIndex, inout Surface surface)
{
ViewSrg::Decal decal = ViewSrg::m_decals[currDecalIndex];
ViewSrg::Decal decal = ViewSrg::m_decals[currDecalIndex];
float3x3 decalRot = MatrixFromQuaternion(decal.m_quaternion);
float3 localPos = surface.position - decal.m_position;
float3 localPos = surface.position - decal.m_position;
localPos = mul(localPos, decalRot);
float3 decalUVW = localPos * rcp(decal.m_halfSize);
if(decalUVW.x >= -1.0f && decalUVW.x <= 1.0f &&
decalUVW.y >= -1.0f && decalUVW.y <= 1.0f &&
@ -70,25 +74,23 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface)
switch(textureArrayIndex)
{
case 0:
baseMap = ViewSrg::m_decalTextureArray0.Sample(PassSrg::LinearSampler, decalUV);
baseMap = ViewSrg::m_decalTextureArray0.Sample(PassSrg::LinearSampler, decalUV);
break;
case 1:
baseMap = ViewSrg::m_decalTextureArray1.Sample(PassSrg::LinearSampler, decalUV);
baseMap = ViewSrg::m_decalTextureArray1.Sample(PassSrg::LinearSampler, decalUV);
break;
case 2:
baseMap = ViewSrg::m_decalTextureArray2.Sample(PassSrg::LinearSampler, decalUV);
baseMap = ViewSrg::m_decalTextureArray2.Sample(PassSrg::LinearSampler, decalUV);
break;
case 3:
baseMap = ViewSrg::m_decalTextureArray3.Sample(PassSrg::LinearSampler, decalUV);
baseMap = ViewSrg::m_decalTextureArray3.Sample(PassSrg::LinearSampler, decalUV);
break;
case 4:
baseMap = ViewSrg::m_decalTextureArray4.Sample(PassSrg::LinearSampler, decalUV);
baseMap = ViewSrg::m_decalTextureArray4.Sample(PassSrg::LinearSampler, decalUV);
break;
}
float opacity = baseMap.a * decal.m_opacity * GetDecalAttenuation(surface.normal, decalRot[2], decal.m_angleAttenuation);
surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity);
}
float opacity = baseMap.a * decal.m_opacity * GetDecalAttenuation(surface.normal, decalRot[2], decal.m_angleAttenuation);
surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity);
}
}

@ -17,7 +17,6 @@ struct ForwardPassOutput
float4 m_albedo : SV_Target2; //!< RGB = Surface albedo pre-multiplied by other factors that will be multiplied later by diffuse GI, A = specularOcclusion
float4 m_specularF0 : SV_Target3; //!< RGB = Specular F0, A = roughness
float4 m_normal : SV_Target4; //!< RGB10 = EncodeNormalSignedOctahedron(worldNormal), A2 = multiScatterCompensationEnabled
float3 m_scatterDistance : SV_Target5;
};
struct ForwardPassOutputWithDepth
@ -29,6 +28,5 @@ struct ForwardPassOutputWithDepth
float4 m_albedo : SV_Target2;
float4 m_specularF0 : SV_Target3;
float4 m_normal : SV_Target4;
float3 m_scatterDistance : SV_Target5;
float m_depth : SV_Depth;
};

@ -0,0 +1,34 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
struct ForwardPassOutput
{
// m_diffuseColor.a should be encoded with subsurface scattering's strength factor and quality factor if enabled
float4 m_diffuseColor : SV_Target0;
float4 m_specularColor : SV_Target1;
float4 m_albedo : SV_Target2;
float4 m_specularF0 : SV_Target3;
float4 m_normal : SV_Target4;
float3 m_scatterDistance : SV_Target5;
};
struct ForwardPassOutputWithDepth
{
// m_diffuseColor.a should be encoded with subsurface scattering's strength factor and quality factor if enabled
float4 m_diffuseColor : SV_Target0;
float4 m_specularColor : SV_Target1;
float4 m_albedo : SV_Target2;
float4 m_specularF0 : SV_Target3;
float4 m_normal : SV_Target4;
float3 m_scatterDistance : SV_Target5;
float m_depth : SV_Depth;
};

@ -0,0 +1,115 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
// Include options first
#include <Atom/Features/PBR/LightingOptions.azsli>
// Then include custom surface and lighting data types
#include <Atom/Features/PBR/Lighting/LightingData.azsli>
#include <Atom/Features/PBR/Surfaces/EnhancedSurface.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/Features/PBR/Microfacet/Brdf.azsli>
// Then define the Diffuse and Specular lighting functions
float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight)
{
float3 diffuse;
if(o_enableSubsurfaceScattering)
{
// Use diffuse brdf contains double Fresnel (enter/exit surface) terms if subsurface scattering is enabled
diffuse = NormalizedDisneyDiffuse(surface.albedo, surface.normal, lightingData.dirToCamera, dirToLight, surface.roughnessLinear);
}
else
{
diffuse = DiffuseLambertian(surface.albedo, surface.normal, dirToLight);
}
if(o_clearCoat_feature_enabled)
{
// Attenuate diffuse term by clear coat's fresnel term to account for energy loss
float HdotV = saturate(dot(normalize(dirToLight + lightingData.dirToCamera), lightingData.dirToCamera));
diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoat.factor);
}
diffuse *= lightIntensity;
return diffuse;
}
float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight)
{
float3 specular;
if (o_enableAnisotropy)
{
specular = AnisotropicGGX( lightingData.dirToCamera, dirToLight, surface.normal, surface.anisotropy.tangent, surface.anisotropy.bitangent, surface.anisotropy.anisotropyFactors,
surface.specularF0, lightingData.NdotV, lightingData.multiScatterCompensation );
}
else
{
specular = SpecularGGX(lightingData.dirToCamera, dirToLight, surface.normal, surface.specularF0, lightingData.NdotV, surface.roughnessA2, lightingData.multiScatterCompensation);
}
if(o_clearCoat_feature_enabled)
{
float3 halfVector = normalize(dirToLight + lightingData.dirToCamera);
float NdotH = saturate(dot(surface.clearCoat.normal, halfVector));
float NdotL = saturate(dot(surface.clearCoat.normal, dirToLight));
float HdotL = saturate(dot(halfVector, dirToLight));
// HdotV = HdotL due to the definition of half vector
float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor;
float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f);
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF );
specular = specular * (1.0 - clearCoatF) * (1.0 - clearCoatF) + clearCoatSpecular;
}
specular *= lightIntensity;
return specular;
}
// Then include everything else
#include <Atom/Features/PBR/Lights/Lights.azsli>
#include <Atom/Features/PBR/Lights/Ibl.azsli>
struct PbrLightingOutput
{
float4 m_diffuseColor;
float4 m_specularColor;
float4 m_albedo;
float4 m_specularF0;
float4 m_normal;
float3 m_scatterDistance;
};
PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingData, float alpha)
{
PbrLightingOutput lightingOutput;
lightingOutput.m_diffuseColor = float4(lightingData.diffuseLighting, alpha);
lightingOutput.m_specularColor = float4(lightingData.specularLighting, 1.0);
// albedo, specularF0, roughness, and normals for later passes (specular IBL, Diffuse GI, SSR, AO, etc)
lightingOutput.m_specularF0 = float4(surface.specularF0, surface.roughnessLinear);
lightingOutput.m_albedo.rgb = surface.albedo * lightingData.diffuseResponse * lightingData.diffuseAmbientOcclusion;
lightingOutput.m_albedo.a = lightingData.specularOcclusion;
lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(surface.normal);
lightingOutput.m_normal.a = o_specularF0_enableMultiScatterCompensation ? 1.0f : 0.0f;
return lightingOutput;
}

@ -0,0 +1,106 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
// Include options first
#include <Atom/Features/PBR/LightingOptions.azsli>
// Then include custom surface and lighting data types
#include <Atom/Features/PBR/Lighting/LightingData.azsli>
#include <Atom/Features/PBR/Surfaces/SkinSurface.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/Features/PBR/Microfacet/Brdf.azsli>
// Then define the Diffuse and Specular lighting functions
float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight)
{
float3 diffuse;
if(o_enableSubsurfaceScattering)
{
// Use diffuse brdf contains double Fresnel (enter/exit surface) terms if subsurface scattering is enabled
diffuse = NormalizedDisneyDiffuse(surface.albedo, surface.normal, lightingData.dirToCamera, dirToLight, surface.roughnessLinear);
}
else
{
diffuse = DiffuseLambertian(surface.albedo, surface.normal, dirToLight);
}
if(o_clearCoat_feature_enabled)
{
// Attenuate diffuse term by clear coat's fresnel term to account for energy loss
float HdotV = saturate(dot(normalize(dirToLight + lightingData.dirToCamera), lightingData.dirToCamera));
diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoat.factor);
}
diffuse *= lightIntensity;
return diffuse;
}
float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight)
{
float3 specular = SpecularGGX(lightingData.dirToCamera, dirToLight, surface.normal, surface.specularF0, lightingData.NdotV, surface.roughnessA2, lightingData.multiScatterCompensation);
if(o_clearCoat_feature_enabled)
{
float3 halfVector = normalize(dirToLight + lightingData.dirToCamera);
float NdotH = saturate(dot(surface.clearCoat.normal, halfVector));
float NdotL = saturate(dot(surface.clearCoat.normal, dirToLight));
float HdotL = saturate(dot(halfVector, dirToLight));
// HdotV = HdotL due to the definition of half vector
float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor;
float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f);
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF );
specular = specular * (1.0 - clearCoatF) * (1.0 - clearCoatF) + clearCoatSpecular;
}
specular *= lightIntensity;
return specular;
}
// Then include everything else
#include <Atom/Features/PBR/Lights/Lights.azsli>
#include <Atom/Features/PBR/Lights/Ibl.azsli>
struct PbrLightingOutput
{
float4 m_diffuseColor;
float4 m_specularColor;
float4 m_albedo;
float4 m_specularF0;
float4 m_normal;
float3 m_scatterDistance;
};
PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingData)
{
PbrLightingOutput lightingOutput;
lightingOutput.m_diffuseColor = float4(lightingData.diffuseLighting, 1.0f);
lightingOutput.m_specularColor = float4(lightingData.specularLighting, 1.0f);
// albedo, specularF0, roughness, and normals for later passes (specular IBL, Diffuse GI, SSR, AO, etc)
lightingOutput.m_specularF0 = float4(surface.specularF0, surface.roughnessLinear);
lightingOutput.m_albedo.rgb = surface.albedo * lightingData.diffuseResponse * lightingData.diffuseAmbientOcclusion;
lightingOutput.m_albedo.a = lightingData.specularOcclusion;
lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(surface.normal);
lightingOutput.m_normal.a = o_specularF0_enableMultiScatterCompensation ? 1.0f : 0.0f;
return lightingOutput;
}

@ -19,6 +19,50 @@
#include <Atom/Features/PBR/Lighting/LightingData.azsli>
#include <Atom/Features/PBR/Surfaces/StandardSurface.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/Features/PBR/Microfacet/Brdf.azsli>
// Then define the Diffuse and Specular lighting functions
float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight)
{
float3 diffuse = DiffuseLambertian(surface.albedo, surface.normal, dirToLight);
if(o_clearCoat_feature_enabled)
{
// Attenuate diffuse term by clear coat's fresnel term to account for energy loss
float HdotV = saturate(dot(normalize(dirToLight + lightingData.dirToCamera), lightingData.dirToCamera));
diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoat.factor);
}
diffuse *= lightIntensity;
return diffuse;
}
float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight)
{
float3 specular = SpecularGGX(lightingData.dirToCamera, dirToLight, surface.normal, surface.specularF0, lightingData.NdotV, surface.roughnessA2, lightingData.multiScatterCompensation);
if(o_clearCoat_feature_enabled)
{
float3 halfVector = normalize(dirToLight + lightingData.dirToCamera);
float NdotH = saturate(dot(surface.clearCoat.normal, halfVector));
float NdotL = saturate(dot(surface.clearCoat.normal, dirToLight));
float HdotL = saturate(dot(halfVector, dirToLight));
// HdotV = HdotL due to the definition of half vector
float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor;
float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f);
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF );
specular = specular * (1.0 - clearCoatF) * (1.0 - clearCoatF) + clearCoatSpecular;
}
specular *= lightIntensity;
return specular;
}
// Then include everything else
#include <Atom/Features/PBR/Lights/Lights.azsli>
#include <Atom/Features/PBR/Lights/Ibl.azsli>
@ -31,7 +75,6 @@ struct PbrLightingOutput
float4 m_albedo;
float4 m_specularF0;
float4 m_normal;
float4 m_clearCoatNormal;
float3 m_scatterDistance;
};
@ -50,11 +93,17 @@ PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingDat
lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(surface.normal);
lightingOutput.m_normal.a = o_specularF0_enableMultiScatterCompensation ? 1.0f : 0.0f;
// layout: (packedNormal.x, packedNormal.y, strength factor, clear coat roughness (not base material's roughness))
lightingOutput.m_clearCoatNormal = float4(EncodeNormalSphereMap(surface.clearCoat.normal), o_clearCoat_feature_enabled ? surface.clearCoat.factor : 0.0, surface.clearCoat.roughness);
return lightingOutput;
}
PbrLightingOutput DebugOutput(float3 color)
{
PbrLightingOutput output = (PbrLightingOutput)0;
float defaultNormal = float3(0.0f, 0.0f, 1.0f);
output.m_diffuseColor = float4(color.rgb, 1.0f);
output.m_normal.rgb = EncodeNormalSignedOctahedron(defaultNormal);
return output;
}

@ -1,205 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/Features/PBR/LightingOptions.azsli>
#include <viewsrg.srgi>
#include <scenesrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include <Atom/RPI/Math.azsli>
#include <Atom/RPI/TangentSpace.azsli>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
#include <Atom/Features/PBR/Decals.azsli>
// VSInput, VSOutput, ObjectSrg must be defined before including this file.
// DEPRECATED: Please use the VertexHelper(...) function in VertexHelper.azsli instead.
//! @param skipShadowCoords can be useful for example when PixelDepthOffset is enable, because the pixel shader will have to run before the final world position is known
void PbrVsHelper(in VSInput IN, inout VSOutput OUT, float3 worldPosition, bool skipShadowCoords = false)
{
OUT.m_worldPosition = worldPosition;
OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPosition, 1.0));
float4x4 objectToWorld = ObjectSrg::GetWorldMatrix();
float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose();
ConstructTBN(IN.m_normal, IN.m_tangent, IN.m_bitangent, objectToWorld, objectToWorldIT, OUT.m_normal, OUT.m_tangent, OUT.m_bitangent);
// directional light shadow
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
if (o_enableShadows && !skipShadowCoords && shadowIndex < SceneSrg::m_directionalLightCount)
{
DirectionalLightShadow::GetShadowCoords(
shadowIndex,
worldPosition,
OUT.m_shadowCoords);
}
}
// DEPRECATED: Please use the functions in StandardLighting.azsli instead.
// For an example on how to use those functions, see StandardPBR_forwardPass.azsl
PbrLightingOutput PbrLighting( VSOutput IN,
float3 baseColor,
float metallic,
float roughness,
float specularF0Factor,
float3 normal,
float3 vtxTangent,
float3 vtxBitangent,
float2 anisotropy, // angle and factor
float3 emissive,
float diffuseAmbientOcclusion,
float specularOcclusion,
float4 transmissionTintThickness,
float4 transmissionParams,
float clearCoatFactor,
float clearCoatRoughness,
float3 clearCoatNormal,
float alpha,
OpacityMode opacityMode)
{
float3 worldPosition = IN.m_worldPosition;
float4 position = IN.m_position;
float3 shadowCoords[ViewSrg::MaxCascadeCount] = IN.m_shadowCoords;
// ______________________________________________________________________________________________
// Surface
Surface surface;
surface.position = worldPosition;
surface.normal = normal;
surface.roughnessLinear = roughness;
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = transmissionParams;
surface.clearCoat.factor = clearCoatFactor;
surface.clearCoat.roughness = clearCoatRoughness;
surface.clearCoat.normal = clearCoatNormal;
surface.CalculateRoughnessA();
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
surface.anisotropy.Init(normal, vtxTangent, vtxBitangent, anisotropy.x, anisotropy.y, surface.roughnessA);
// ______________________________________________________________________________________________
// LightingData
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
lightingData.emissiveLighting = emissive;
lightingData.diffuseAmbientOcclusion = diffuseAmbientOcclusion;
lightingData.specularOcclusion = specularOcclusion;
// Directional light shadow coordinates
lightingData.shadowCoords = shadowCoords;
// manipulate base layer f0 if clear coat is enabled
if(o_clearCoat_feature_enabled)
{
// modify base layer's normal incidence reflectance
// for the derivation of the following equation please refer to:
// https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodel/baselayermodification
float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0));
surface.specularF0 = lerp(surface.specularF0, f0 * f0, clearCoatFactor);
}
// Diffuse and Specular response (used in IBL calculations)
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0 - lightingData.specularResponse;
if(o_clearCoat_feature_enabled)
{
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
// Multiscatter compensation factor
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ______________________________________________________________________________________________
// Lighting
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
{
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
}
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
return lightingOutput;
}
//! Populates a PbrLightingOutput struct with values that can be used to render a simple debug color in the PBR pipeline.
//! Note that this will not give you a the exact color screen pixels since it is used in the PBR pipeline, it may
//! still have lighting or other affects applied on top of it. But this is still a convenient way to quickly get some
//! colors on screen.
//! @param IN the pixel shader input structure
//! @param debugColor the color to be drawn
//! @param normalWS world space normal vector
//! @return a PbrLightingOutput as returned by the main PbrLighting() function
PbrLightingOutput MakeDebugOutput(VSOutput IN, float3 debugColor, float3 normalWS)
{
// We happen to set this up initially using baseColor, but we could consider adding an option to use
// emissive instead to avoid depending on scene lighting.
const float3 baseColor = debugColor;
const float metallic = 0;
const float roughness = 1;
const float specularF0Factor = 0.5;
const float3 normal = normalWS;
const float3 emissive = {0,0,0};
const float occlusion = 1;
const float clearCoatFactor = 0.0f;
const float clearCoatRoughness = 0.0f;
const float3 clearCoatNormal = {0,0,0};
const float4 transmissionTintThickness = {0,0,0,0};
const float4 transmissionParams = {0,0,0,0};
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
const float alpha = 1.0;
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
emissive, occlusion, occlusion, transmissionTintThickness, transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, OpacityMode::Opaque);
return lightingOutput;
}
//! Same as above, using the vertex normal
PbrLightingOutput MakeDebugOutput(VSOutput IN, float3 debugColor)
{
return MakeDebugOutput(IN, debugColor, normalize(IN.m_normal));
}

@ -16,71 +16,9 @@
#include <Atom/Features/PBR/BackLighting.azsli>
#include <Atom/Features/PBR/Hammersley.azsli>
#include <Atom/Features/PBR/LightingUtils.azsli>
#include <Atom/Features/PBR/Surface.azsli>
#include <Atom/Features/PBR/Microfacet/Brdf.azsli>
option bool o_area_light_validation = false;
float3 GetDiffuseLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight)
{
float3 diffuse;
if(o_enableSubsurfaceScattering)
{
// Use diffuse brdf contains double Fresnel (enter/exit surface) terms if subsurface scattering is enabled
diffuse = NormalizedDisneyDiffuse(surface.albedo, surface.normal, lightingData.dirToCamera, dirToLight, surface.roughnessLinear);
}
else
{
diffuse = DiffuseLambertian(surface.albedo, surface.normal, dirToLight);
}
if(o_clearCoat_feature_enabled)
{
// Attenuate diffuse term by clear coat's fresnel term to account for energy loss
float HdotV = saturate(dot(normalize(dirToLight + lightingData.dirToCamera), lightingData.dirToCamera));
diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoat.factor);
}
diffuse *= lightIntensity;
return diffuse;
}
float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight)
{
float3 specular;
if (o_enableAnisotropy)
{
//AnisotropicGGX( float3 dirToCamera, float3 dirToLight, float3 normal, float3 tangent, float3 bitangent, float2 anisotropyFactors,
// float3 specularF0, float NdotV, float multiScatterCompensation )
specular = AnisotropicGGX( lightingData.dirToCamera, dirToLight, surface.normal, surface.anisotropy.tangent, surface.anisotropy.bitangent, surface.anisotropy.anisotropyFactors,
surface.specularF0, lightingData.NdotV, lightingData.multiScatterCompensation );
}
else
{
specular = SpecularGGX(lightingData.dirToCamera, dirToLight, surface.normal, surface.specularF0, lightingData.NdotV, surface.roughnessA2, lightingData.multiScatterCompensation);
}
if(o_clearCoat_feature_enabled)
{
float3 halfVector = normalize(dirToLight + lightingData.dirToCamera);
float NdotH = saturate(dot(surface.clearCoat.normal, halfVector));
float NdotL = saturate(dot(surface.clearCoat.normal, dirToLight));
float HdotL = saturate(dot(halfVector, dirToLight));
// HdotV = HdotL due to the definition of half vector
float3 clearCoatF = FresnelSchlick(HdotL, 0.04) * surface.clearCoat.factor;
float clearCoatRoughness = max(surface.clearCoat.roughness * surface.clearCoat.roughness, 0.0005f);
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoat.normal, clearCoatRoughness, clearCoatF );
specular = specular * (1.0 - clearCoatF) * (1.0 - clearCoatF) + clearCoatSpecular;
}
specular *= lightIntensity;
return specular;
}
//! Adjust the intensity of specular light based on the radius of the light source and roughness of the surface to approximate energy conservation.
float GetIntensityAdjustedByRadiusAndRoughness(float roughnessA, float radius, float distance2)

@ -18,7 +18,6 @@
* rather than transmit.
**/
#include <Atom/Features/PBR/Surface.azsli>
#include <Atom/RPI/Math.azsli>
#include "Ggx.azsli"
#include "Fresnel.azsli"
@ -81,9 +80,6 @@ float3 DiffuseTitanfall(float roughnessA, float3 albedo, float3 normal, float3 d
}
// ------- Specular Lighting -------
//! Computes specular response from surfaces with microgeometry. The common form for microfacet

@ -1,68 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
// //! The surface struct should contain all the info for a pixel that can be
// //! passed onto the rendering logic for shading.
// //! Note that metallic workflow can be supported by first converting to these physical properties first.
// struct Surface
// {
// float3 position;
// float3 normal;
// float3 tangentAniso; //! surface space tangent for anisotropic use
// float3 bitangentAniso; //! surface space bitangent for anisotropic use
// float2 anisotropyFactors; //! anisotory factors along the tangent and the bitangent directions
// float3 albedo;
// float3 specularF0; //!< actual fresnel f0 spectral value of the surface (as opposed to a "factor")
// float3 multiScatterCompensation; //!< the constant scaling term to approximate multiscattering contribution in specular BRDF
// float roughnessLinear; //!< perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
// float roughnessA; //!< actual roughness value ( a.k.a. "alpha roughness") to be used in microfacet calculations
// float thickness; //!< pre baked local thickness, used for transmission
// float4 transmissionParams; //!< parameters: thick mode->(attenuation coefficient, power, distortion, scale), thin mode: (float3 scatter distance, scale)
// float clearCoatFactor; //!< clear coat strength factor
// float clearCoatRoughness; //!< clear coat linear roughness (not base layer one)
// float3 clearCoatNormal; //!< normal used for top layer clear coat
// };
//
// //! Calculate and fill the data required for fast directional anisotropty surface response.
// //! Assumption: the normal and roughnessA surface properties were filled and are valid
// //! Notice that since the newly created surface tangent and bitangent will be rotated
// //! according to the anisotropy direction and should not be used for other purposes uness
// //! rotated back.
// void CalculateSurfaceDirectionalAnisotropicData(
// inout Surface surface, float2 anisotropyAngleAndFactor,
// float3 vtxTangent, float3 vtxBitangent )
// {
// const float anisotropyAngle = anisotropyAngleAndFactor.x;
// const float anisotropyFactor = anisotropyAngleAndFactor.y;
//
// surface.anisotropyFactors = max( 0.01,
// float2( surface.roughnessA * (1.0 + anisotropyFactor),
// surface.roughnessA * (1.0 - anisotropyFactor) )
// );
//
// if (anisotropyAngle > 0.01)
// {
// // Base rotation according to anisotropic main direction
// float aniSin, aniCos;
// sincos(anisotropyAngle, aniSin, aniCos);
//
// // Rotate the vertex tangent to get new aligned to surface normal tangent
// vtxTangent = aniCos * vtxTangent - aniSin * vtxBitangent;
// }
//
// // Now create the new surface base according to the surface normal
// // If rotation was required it was already applied to the tangent, hence to the bitangent
// surface.bitangentAniso = normalize(cross(surface.normal, vtxTangent));
// surface.tangentAniso = cross(surface.bitangentAniso, surface.normal);
// }

@ -43,7 +43,7 @@ class BasePbrSurfaceData
void CalculateRoughnessA();
//! Sets albedo and specularF0 using metallic workflow
void SetAlbedoAndSpecularF0(float3 baseColor, float inSpecularF0, float metallic);
void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic);
};
// ------- Functions -------
@ -63,6 +63,9 @@ void BasePbrSurfaceData::ApplySpecularAA()
float kernelRoughnessA2 = min(2.0 * variance , varianceThresh );
float filteredRoughnessA2 = saturate ( roughnessA2 + kernelRoughnessA2 );
roughnessA2 = filteredRoughnessA2;
roughnessA = sqrt(roughnessA2);
roughnessLinear = sqrt(roughnessA);
}
void BasePbrSurfaceData::CalculateRoughnessA()
@ -82,9 +85,9 @@ void BasePbrSurfaceData::CalculateRoughnessA()
}
}
void BasePbrSurfaceData::SetAlbedoAndSpecularF0(float3 baseColor, float inSpecularF0, float metallic)
void BasePbrSurfaceData::SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic)
{
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * inSpecularF0;
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor;
// Compute albedo and specularF0 based on metalness
albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);

@ -17,4 +17,13 @@ class ClearCoatSurfaceData
float factor; //!< clear coat strength factor
float roughness; //!< clear coat linear roughness (not base layer one)
float3 normal; //!< normal used for top layer clear coat
void InitializeToZero();
};
void ClearCoatSurfaceData::InitializeToZero()
{
factor = 0.0f;
roughness = 0.0f;
normal = float3(0.0f, 0.0f, 0.0f);
}

@ -0,0 +1,90 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/Features/PBR/Surfaces/AnisotropicSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/BasePbrSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/ClearCoatSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/TransmissionSurfaceData.azsli>
class Surface
{
AnisotropicSurfaceData anisotropy;
ClearCoatSurfaceData clearCoat;
TransmissionSurfaceData transmission;
// ------- BasePbrSurfaceData -------
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
float roughnessA; //!< Actual roughness value ( a.k.a. "alpha roughness") to be used in microfacet calculations
float roughnessA2; //!< Alpha roughness ^ 2 (i.e. roughnessA * roughnessA), used in GGX, cached here for perfromance
//! Applies specular anti-aliasing to roughnessA2
void ApplySpecularAA();
//! Calculates roughnessA and roughnessA2 after roughness has been set
void CalculateRoughnessA();
//! Sets albedo and specularF0 using metallic workflow
void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic);
};
// Specular Anti-Aliasing technique from this paper:
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
void Surface::ApplySpecularAA()
{
// Constants for formula below
const float screenVariance = 0.25f;
const float varianceThresh = 0.18f;
// Specular Anti-Aliasing
float3 dndu = ddx_fine( normal );
float3 dndv = ddy_fine( normal );
float variance = screenVariance * (dot( dndu , dndu ) + dot( dndv , dndv ));
float kernelRoughnessA2 = min(2.0 * variance , varianceThresh );
float filteredRoughnessA2 = saturate ( roughnessA2 + kernelRoughnessA2 );
roughnessA2 = filteredRoughnessA2;
}
void Surface::CalculateRoughnessA()
{
// The roughness value in microfacet calculations (called "alpha" in the literature) does not give perceptually
// linear results. Disney found that squaring the roughness value before using it in microfacet equations causes
// the user-provided roughness parameter to be more perceptually linear. We keep both values available as some
// equations need roughnessLinear (i.e. IBL sampling) while others need roughnessA (i.e. GGX equations).
// See Burley's Disney PBR: https://pdfs.semanticscholar.org/eeee/3b125c09044d3e2f58ed0e4b1b66a677886d.pdf
roughnessA = max(roughnessLinear * roughnessLinear, MinRoughnessA);
roughnessA2 = roughnessA * roughnessA;
if(o_applySpecularAA)
{
ApplySpecularAA();
}
}
void Surface::SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic)
{
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor;
// Compute albedo and specularF0 based on metalness
albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);
specularF0 = lerp(dielectricSpecularF0, baseColor, metallic);
}

@ -0,0 +1,86 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/Features/PBR/Surfaces/AnisotropicSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/BasePbrSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/ClearCoatSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/TransmissionSurfaceData.azsli>
class Surface
{
ClearCoatSurfaceData clearCoat;
TransmissionSurfaceData transmission;
// ------- BasePbrSurfaceData -------
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
float roughnessA; //!< Actual roughness value ( a.k.a. "alpha roughness") to be used in microfacet calculations
float roughnessA2; //!< Alpha roughness ^ 2 (i.e. roughnessA * roughnessA), used in GGX, cached here for perfromance
//! Applies specular anti-aliasing to roughnessA2
void ApplySpecularAA();
//! Calculates roughnessA and roughnessA2 after roughness has been set
void CalculateRoughnessA();
//! Sets albedo and specularF0 using metallic workflow
void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor);
};
// Specular Anti-Aliasing technique from this paper:
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
void Surface::ApplySpecularAA()
{
// Constants for formula below
const float screenVariance = 0.25f;
const float varianceThresh = 0.18f;
// Specular Anti-Aliasing
float3 dndu = ddx_fine( normal );
float3 dndv = ddy_fine( normal );
float variance = screenVariance * (dot( dndu , dndu ) + dot( dndv , dndv ));
float kernelRoughnessA2 = min(2.0 * variance , varianceThresh );
float filteredRoughnessA2 = saturate ( roughnessA2 + kernelRoughnessA2 );
roughnessA2 = filteredRoughnessA2;
}
void Surface::CalculateRoughnessA()
{
// The roughness value in microfacet calculations (called "alpha" in the literature) does not give perceptually
// linear results. Disney found that squaring the roughness value before using it in microfacet equations causes
// the user-provided roughness parameter to be more perceptually linear. We keep both values available as some
// equations need roughnessLinear (i.e. IBL sampling) while others need roughnessA (i.e. GGX equations).
// See Burley's Disney PBR: https://pdfs.semanticscholar.org/eeee/3b125c09044d3e2f58ed0e4b1b66a677886d.pdf
roughnessA = max(roughnessLinear * roughnessLinear, MinRoughnessA);
roughnessA2 = roughnessA * roughnessA;
if(o_applySpecularAA)
{
ApplySpecularAA();
}
}
void Surface::SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor)
{
albedo = baseColor;
specularF0 = MaxDielectricSpecularF0 * specularF0Factor;
}

@ -17,10 +17,8 @@
#include <Atom/Features/PBR/Surfaces/ClearCoatSurfaceData.azsli>
#include <Atom/Features/PBR/Surfaces/TransmissionSurfaceData.azsli>
class Surface //: BasePbrSurfaceData
class Surface
{
//BasePbrSurfaceData pbr;
AnisotropicSurfaceData anisotropy;
ClearCoatSurfaceData clearCoat;
TransmissionSurfaceData transmission;
@ -41,7 +39,7 @@ class Surface //: BasePbrSurfaceData
void CalculateRoughnessA();
//! Sets albedo and specularF0 using metallic workflow
void SetAlbedoAndSpecularF0(float3 baseColor, float inSpecularF0, float metallic);
void SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic);
};
@ -80,9 +78,9 @@ void Surface::CalculateRoughnessA()
}
}
void Surface::SetAlbedoAndSpecularF0(float3 baseColor, float inSpecularF0, float metallic)
void Surface::SetAlbedoAndSpecularF0(float3 baseColor, float specularF0Factor, float metallic)
{
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * inSpecularF0;
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor;
// Compute albedo and specularF0 based on metalness
albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);

@ -17,4 +17,13 @@ class TransmissionSurfaceData
float3 tint;
float thickness; //!< pre baked local thickness, used for transmission
float4 transmissionParams; //!< parameters: thick mode->(attenuation coefficient, power, distortion, scale), thin mode: (float3 scatter distance, scale)
void InitializeToZero();
};
void TransmissionSurfaceData::InitializeToZero()
{
tint = float3(0.0f, 0.0f, 0.0f);
thickness = 0.0f;
transmissionParams = float4(0.0f, 0.0f, 0.0f, 0.0f);
}

@ -13,7 +13,9 @@
#pragma once
// ------------------------------------------------------------------------------
// NOTE: VSInput, VSOutput, ObjectSrg must be defined before including this file.
// NOTE: The following must be included or defined before including this file:
// - VSInput - ObjectSrg
// - VSOutput - PassSrg
// ---------------------------------------------------------------------------------
// Options
@ -23,8 +25,6 @@
#include <viewsrg.srgi>
#include <scenesrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
// Math
#include <Atom/RPI/Math.azsli>
@ -33,7 +33,6 @@
// Shadow Coords
#include <Atom/Features/Shadow/DirectionalLightShadow.azsli>
//! @param skipShadowCoords can be useful for example when PixelDepthOffset is enable, because the pixel shader will have to run before the final world position is known
void VertexHelper(in VSInput IN, inout VSOutput OUT, float3 worldPosition, bool skipShadowCoords = false)
{

@ -140,6 +140,7 @@ set(FILES
Passes/Forward.pass
Passes/ForwardCheckerboard.pass
Passes/ForwardMSAA.pass
Passes/ForwardSubsurfaceMSAA.pass
Passes/FullscreenCopy.pass
Passes/FullscreenOutputOnly.pass
Passes/ImGui.pass
@ -164,6 +165,7 @@ set(FILES
Passes/MSAAResolveDepth.pass
Passes/OpaqueParent.pass
Passes/PostProcessParent.pass
Passes/ProjectedShadowmaps.pass
Passes/RayTracingAccelerationStructure.pass
Passes/ReflectionComposite.pass
Passes/ReflectionCopyFrameBuffer.pass
@ -190,7 +192,6 @@ set(FILES
Passes/SMAAConvertToPerceptualColor.pass
Passes/SMAAEdgeDetection.pass
Passes/SMAANeighborhoodBlending.pass
Passes/ProjectedShadowmaps.pass
Passes/SsaoCompute.pass
Passes/SsaoHalfRes.pass
Passes/SsaoParent.pass
@ -229,14 +230,15 @@ set(FILES
ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli
ShaderLib/Atom/Features/PBR/ForwardPassOutput.azsli
ShaderLib/Atom/Features/PBR/ForwardPassSrg.azsli
ShaderLib/Atom/Features/PBR/ForwardSubsurfacePassOutput.azsli
ShaderLib/Atom/Features/PBR/Hammersley.azsli
ShaderLib/Atom/Features/PBR/LightingModel.azsli
ShaderLib/Atom/Features/PBR/LightingOptions.azsli
ShaderLib/Atom/Features/PBR/LightingUtils.azsli
ShaderLib/Atom/Features/PBR/Surface.azsli
ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli
ShaderLib/Atom/Features/PBR/Lighting/DualSpecularLighting.azsli
ShaderLib/Atom/Features/PBR/Lighting/EnhancedLighting.azsli
ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli
ShaderLib/Atom/Features/PBR/Lighting/SkinLighting.azsli
ShaderLib/Atom/Features/PBR/Lighting/StandardLighting.azsli
ShaderLib/Atom/Features/PBR/Lights/CapsuleLight.azsli
ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli
@ -248,6 +250,8 @@ set(FILES
ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli
ShaderLib/Atom/Features/PBR/Lights/PolygonLight.azsli
ShaderLib/Atom/Features/PBR/Lights/QuadLight.azsli
ShaderLib/Atom/Features/PBR/Lights/SimplePointLight.azsli
ShaderLib/Atom/Features/PBR/Lights/SimpleSpotLight.azsli
ShaderLib/Atom/Features/PBR/Microfacet/Brdf.azsli
ShaderLib/Atom/Features/PBR/Microfacet/Fresnel.azsli
ShaderLib/Atom/Features/PBR/Microfacet/Ggx.azsli
@ -255,6 +259,8 @@ set(FILES
ShaderLib/Atom/Features/PBR/Surfaces/BasePbrSurfaceData.azsli
ShaderLib/Atom/Features/PBR/Surfaces/ClearCoatSurfaceData.azsli
ShaderLib/Atom/Features/PBR/Surfaces/DualSpecularSurface.azsli
ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli
ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli
ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
ShaderLib/Atom/Features/PBR/Surfaces/TransmissionSurfaceData.azsli
ShaderLib/Atom/Features/PostProcessing/Aces.azsli
@ -270,9 +276,12 @@ set(FILES
ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli
ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli
ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli
ShaderLib/Atom/Features/Shadow/Shadow.azsli
ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli
ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli
ShaderLib/Atom/Features/Vertex/VertexHelper.azsli
ShaderResourceGroups/RayTracingSceneSrg.azsli
ShaderResourceGroups/RayTracingSceneSrgAll.azsli
ShaderResourceGroups/SceneSrg.azsli
ShaderResourceGroups/SceneSrgAll.azsli
ShaderResourceGroups/SceneTimeSrg.azsli

@ -1,6 +1,6 @@
{
"description": "",
"materialType": "Materials/Types/StandardPBR.materialtype",
"materialType": "Materials/Types/EnhancedPBR.materialtype",
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
@ -9,8 +9,8 @@
"influenceMap": "TestData/Textures/checker8x8_512.png",
"scatterColor": [
1.0,
0.19937437772750855,
0.07179369777441025,
0.20000000298023225,
0.07058823853731156,
1.0
],
"scatterDistance": 40.0,

@ -1,11 +1,12 @@
{
"description": "",
"materialType": "Materials/Types/StandardPBR.materialtype",
"materialType": "Materials/Types/EnhancedPBR.materialtype",
"parentMaterial": "",
"propertyLayoutVersion": 3,
"properties": {
"subsurfaceScattering": {
"enableSubsurfaceScattering": true,
"enableTransmission": true,
"scatterDistance": 64.6464614868164,
"subsurfaceScatterFactor": 1.0,
"thicknessMap": "TestData/Textures/checker8x8_512.png",

@ -14,9 +14,12 @@
#include "AutoBrick_Common.azsli"
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/ParallaxMapping.azsli>
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
#include <Atom/Features/PBR/Decals.azsli>
struct VSInput
{
@ -38,7 +41,6 @@ struct VSOutput
float2 m_uv : UV1;
};
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput AutoBrick_ForwardPassVS(VSInput IN)
@ -129,8 +131,6 @@ float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
{
ForwardPassOutput OUT;
float3x3 identityUvMatrix =
{ 1,0,0,
0,1,0,
@ -164,23 +164,62 @@ ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
GetSurfaceShape(IN.m_uv, surfaceDepth, surfaceNormal);
const float3 normal = TangentSpaceToWorld(surfaceNormal, normalize(IN.m_normal), normalize(IN.m_tangent), normalize(IN.m_bitangent));
const float diffuseAmbientOcclusion = 1.0f - surfaceDepth * AutoBrickSrg::m_aoFactor;
const float specularOcclusion = 1;
const float metallic = 0;
const float roughness = 1;
const float specularF0Factor = 0.5;
const float3 emissive = {0,0,0};
const float clearCoatFactor = 0.0;
const float clearCoatRoughness = 0.0;
const float3 clearCoatNormal = {0,0,0};
const float4 transmissionTintThickness = {0,0,0,0};
const float4 transmissionParams = {0,0,0,0};
const float2 anisotropy = 0.0;
const float alpha = 1.0;
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
emissive, diffuseAmbientOcclusion, specularOcclusion, transmissionTintThickness, transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, OpacityMode::Opaque);
// ------- Surface -------
Surface surface;
// Position, Normal, Roughness
surface.position = IN.m_worldPosition.xyz;
surface.normal = normalize(normal);
surface.roughnessLinear = 1.0f;
surface.CalculateRoughnessA();
// Albedo, SpecularF0
const float metallic = 0.0f;
const float specularF0Factor = 0.5f;
surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
// Clear Coat, Transmission
surface.clearCoat.InitializeToZero();
surface.transmission.InitializeToZero();
// ------- LightingData -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Shadow
lightingData.shadowCoords = IN.m_shadowCoords;
lightingData.diffuseAmbientOcclusion = 1.0f - surfaceDepth * AutoBrickSrg::m_aoFactor;
// Diffuse and Specular response
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0f - lightingData.specularResponse;
const float alpha = 1.0f;
// ------- Lighting Calculation -------
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
// ------- Output -------
ForwardPassOutput OUT;
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_diffuseColor.w = -1; // Subsurface scattering is disabled
@ -188,7 +227,6 @@ ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = float3(0,0,0);
return OUT;
}

@ -12,10 +12,13 @@
#include <viewsrg.srgi>
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
#include <Atom/Features/PBR/ForwardPassOutput.azsli>
#include <Atom/Features/PBR/AlphaUtils.azsli>
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/ColorManagement/TransformColor.azsli>
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
#include <Atom/Features/PBR/Decals.azsli>
ShaderResourceGroup MinimalPBRSrg : SRG_PerMaterial
{
@ -42,7 +45,6 @@ struct VSOutput
float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV3;
};
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput MinimalPBR_MainPassVS(VSInput IN)
@ -58,26 +60,60 @@ VSOutput MinimalPBR_MainPassVS(VSInput IN)
ForwardPassOutput MinimalPBR_MainPassPS(VSOutput IN)
{
ForwardPassOutput OUT;
// ------- Surface -------
Surface surface;
const float3 baseColor = MinimalPBRSrg::m_baseColor;
const float metallic = MinimalPBRSrg::m_metallic;
const float roughness = MinimalPBRSrg::m_roughness;
const float specularF0Factor = 0.5;
const float3 normal = normalize(IN.m_normal);
const float3 emissive = {0,0,0};
const float occlusion = 1;
const float clearCoatFactor = 0.0;
const float clearCoatRoughness = 0.0;
const float3 clearCoatNormal = {0,0,0};
const float4 transmissionTintThickness = {0,0,0,0};
const float4 transmissionParams = {0,0,0,0};
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
const float alpha = 1.0;
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
emissive, occlusion, occlusion, transmissionTintThickness, transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, OpacityMode::Opaque);
// Position, Normal, Roughness
surface.position = IN.m_worldPosition.xyz;
surface.normal = normalize(IN.m_normal);
surface.roughnessLinear = MinimalPBRSrg::m_roughness;
surface.CalculateRoughnessA();
// Albedo, SpecularF0
const float specularF0Factor = 0.5f;
surface.SetAlbedoAndSpecularF0(MinimalPBRSrg::m_baseColor, specularF0Factor, MinimalPBRSrg::m_metallic);
// Clear Coat, Transmission
surface.clearCoat.InitializeToZero();
surface.transmission.InitializeToZero();
// ------- LightingData -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Shadow, Occlusion
lightingData.shadowCoords = IN.m_shadowCoords;
// Diffuse and Specular response
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0f - lightingData.specularResponse;
const float alpha = 1.0f;
// ------- Lighting Calculation -------
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
// ------- Output -------
ForwardPassOutput OUT;
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_diffuseColor.w = -1; // Subsurface scattering is disabled
@ -85,7 +121,6 @@ ForwardPassOutput MinimalPBR_MainPassPS(VSOutput IN)
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_scatterDistance = float3(0,0,0);
return OUT;
}

@ -53,16 +53,20 @@ namespace AZ
->Attribute(AZ::Edit::Attributes::ViewportIcon, "editor/icons/components/viewport/component_placeholder.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<RPI::ModelAsset>::Uuid())
->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap")
->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap Bake")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnUseBakedCubemapChanged)
->UIElement(AZ::Edit::UIHandlers::Button, "Bake Reflection Probe", "Bake Reflection Probe")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
->Attribute(AZ::Edit::Attributes::ButtonText, "Bake Reflection Probe")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap")
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorReflectionProbeComponent::OnUseBakedCubemapValidate)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnUseBakedCubemapChanged)
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath, "Baked Cubemap Path", "Baked Cubemap Path")
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
@ -188,6 +192,16 @@ namespace AZ
return false;
}
AZ::Outcome<void, AZStd::string> EditorReflectionProbeComponent::OnUseBakedCubemapValidate([[maybe_unused]] void* newValue, [[maybe_unused]] const AZ::Uuid& valueType)
{
if (!m_controller.m_featureProcessor)
{
return AZ::Failure(AZStd::string("This Reflection Probe entity is hidden, it must be visible in order to change the cubemap type."));
}
return AZ::Success();
}
AZ::u32 EditorReflectionProbeComponent::OnUseBakedCubemapChanged()
{
// save setting to the configuration

@ -47,6 +47,9 @@ namespace AZ
void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
private:
// validation
AZ::Outcome<void, AZStd::string> OnUseBakedCubemapValidate(void* newValue, const AZ::Uuid& valueType);
// change notifications
AZ::u32 OnUseBakedCubemapChanged();
AZ::u32 OnAuthoredCubemapChanged();

@ -443,9 +443,12 @@ namespace DebugDraw
AZ::TransformBus::EventResult(sphereElement.m_worldLocation, sphereElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
}
ColorB lyColor(sphereElement.m_color.ToU32());
Vec3 worldLocation(AZVec3ToLYVec3(sphereElement.m_worldLocation));
gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(worldLocation, sphereElement.m_radius, lyColor, true);
if (gEnv->pRenderer)
{
ColorB lyColor(sphereElement.m_color.ToU32());
Vec3 worldLocation(AZVec3ToLYVec3(sphereElement.m_worldLocation));
gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(worldLocation, sphereElement.m_radius, lyColor, true);
}
}
removeExpiredDebugElementsFromVector(m_activeSpheres);

@ -303,7 +303,8 @@ namespace EMotionFX
if (GetFinalNode() == nodeToRemove)
{
SetFinalNodeId(AnimGraphNodeId::InvalidId);
m_finalNodeId = AnimGraphNodeId::InvalidId;
m_finalNode = nullptr;
}
// call it for all children

@ -68,6 +68,8 @@ namespace EMotionFX
&actorSettings,
"");
assetData->ReleaseEMotionFXData();
if (!assetData->m_emfxActor)
{
AZ_Error("EMotionFX", false, "Failed to initialize actor asset %s", asset.ToString<AZStd::string>().c_str());
@ -77,7 +79,6 @@ namespace EMotionFX
assetData->m_emfxActor->SetIsOwnedByRuntime(true);
// Note: Render actor depends on the mesh asset, so we need to manually create it after mesh asset has been loaded.
return static_cast<bool>(assetData->m_emfxActor);
}

@ -90,6 +90,7 @@ namespace EMotionFX
}
}
assetData->ReleaseEMotionFXData();
AZ_Error("EMotionFX", assetData->m_emfxAnimGraph, "Failed to initialize anim graph asset %s", asset.GetHint().c_str());
return static_cast<bool>(assetData->m_emfxAnimGraph);
}

@ -36,6 +36,12 @@ namespace EMotionFX
: AZ::Data::AssetData(id)
{}
void ReleaseEMotionFXData()
{
m_emfxNativeData.clear();
m_emfxNativeData.shrink_to_fit();
}
AZStd::vector<AZ::u8> m_emfxNativeData;
};

@ -47,6 +47,7 @@ namespace EMotionFX
assetData->m_emfxMotion->SetIsOwnedByRuntime(true);
}
assetData->ReleaseEMotionFXData();
AZ_Error("EMotionFX", assetData->m_emfxMotion, "Failed to initialize motion asset %s", asset.GetHint().c_str());
return (assetData->m_emfxMotion);
}

@ -232,6 +232,7 @@ namespace EMotionFX
// Set motion set's motion load callback, so if EMotion FX queries back for a motion,
// we can pull the one managed through an AZ::Asset.
assetData->m_emfxMotionSet->SetCallback(aznew CustomMotionSetCallback(asset));
assetData->ReleaseEMotionFXData();
return true;
}

@ -43,6 +43,7 @@ namespace EMotionFX
->Field("BlendIn", &Configuration::m_blendInTime)
->Field("BlendOut", &Configuration::m_blendOutTime)
->Field("PlayOnActivation", &Configuration::m_playOnActivation)
->Field("InPlace", &Configuration::m_inPlace)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
@ -61,7 +62,9 @@ namespace EMotionFX
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_blendOutTime, "Blend Out Time", "Determines the blend out time in seconds")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_playOnActivation, "Play on active", "Playing animation immediately after activition.")
->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_playOnActivation, "Play on active", "Playing animation immediately after activation.")
->DataElement(AZ::Edit::UIHandlers::Default, &Configuration::m_inPlace, "In-place",
"Plays the animation in-place and removes any positional and rotational changes from root joints.")
;
}
}
@ -128,6 +131,7 @@ namespace EMotionFX
, m_blendInTime(0.0f)
, m_blendOutTime(0.0f)
, m_playOnActivation(true)
, m_inPlace(false)
{
}
@ -235,7 +239,7 @@ namespace EMotionFX
void SimpleMotionComponent::PlayMotion()
{
m_motionInstance = PlayMotionInternal(m_actorInstance.get(), m_configuration, /*deleteOnZeroWeight*/true, /*inPlace*/false);
m_motionInstance = PlayMotionInternal(m_actorInstance.get(), m_configuration, /*deleteOnZeroWeight*/true);
}
void SimpleMotionComponent::RemoveMotionInstanceFromActor(EMotionFX::MotionInstance* motionInstance)
@ -425,7 +429,7 @@ namespace EMotionFX
return m_configuration.m_blendOutTime;
}
EMotionFX::MotionInstance* SimpleMotionComponent::PlayMotionInternal(const EMotionFX::ActorInstance* actorInstance, const SimpleMotionComponent::Configuration& cfg, bool deleteOnZeroWeight, bool inPlace)
EMotionFX::MotionInstance* SimpleMotionComponent::PlayMotionInternal(const EMotionFX::ActorInstance* actorInstance, const SimpleMotionComponent::Configuration& cfg, bool deleteOnZeroWeight)
{
if (!actorInstance || !cfg.m_motionAsset.IsReady())
{
@ -439,6 +443,7 @@ namespace EMotionFX
auto* motionAsset = cfg.m_motionAsset.GetAs<MotionAsset>();
if (!motionAsset)
{
AZ_Error("EMotionFX", motionAsset, "Motion asset is not valid.");
return nullptr;
@ -456,7 +461,7 @@ namespace EMotionFX
info.mCanOverwrite = false;
info.mBlendInTime = cfg.m_blendInTime;
info.mBlendOutTime = cfg.m_blendOutTime;
info.mInPlace = inPlace;
info.mInPlace = cfg.m_inPlace;
return actorInstance->GetMotionSystem()->PlayMotion(motionAsset->m_emfxMotion.get(), &info);
}

@ -46,7 +46,7 @@ namespace EMotionFX
struct Configuration
{
AZ_TYPE_INFO(Configuration, "{DA661C5F-E79E-41C3-B055-5F5A4E353F84}")
Configuration();
Configuration();
AZ::Data::Asset<MotionAsset> m_motionAsset; ///< Assigned motion asset
bool m_loop; ///< Toggles looping of the motion
@ -56,7 +56,8 @@ namespace EMotionFX
float m_playspeed; ///< Determines the rate at which the motion is played
float m_blendInTime; ///< Determines the blend in time in seconds.
float m_blendOutTime; ///< Determines the blend out time in seconds.
bool m_playOnActivation; ///< Determines if the motion should be played immediately
bool m_playOnActivation; ///< Determines if the motion should be played immediately
bool m_inPlace; ///< Determines if the motion should be played in-place.
static void Reflect(AZ::ReflectContext* context);
};
@ -121,7 +122,7 @@ namespace EMotionFX
void RemoveMotionInstanceFromActor(EMotionFX::MotionInstance* motionInstance);
static EMotionFX::MotionInstance* PlayMotionInternal(const EMotionFX::ActorInstance* actorInstance, const SimpleMotionComponent::Configuration& cfg, bool deleteOnZeroWeight, bool inPlace);
static EMotionFX::MotionInstance* PlayMotionInternal(const EMotionFX::ActorInstance* actorInstance, const SimpleMotionComponent::Configuration& cfg, bool deleteOnZeroWeight);
Configuration m_configuration; ///< Component configuration.
EMotionFXPtr<EMotionFX::ActorInstance> m_actorInstance; ///< Associated actor instance (retrieved from Actor Component).

@ -170,7 +170,7 @@ namespace EMotionFX
// The Editor allows scrubbing back and forth on animation blending transitions, so don't delete
// motion instances if it's blend weight is zero.
// The Editor preview should preview the motion in place to prevent off center movement.
m_motionInstance = SimpleMotionComponent::PlayMotionInternal(m_actorInstance, m_configuration, /*deleteOnZeroWeight*/false, /*inPlace*/true);
m_motionInstance = SimpleMotionComponent::PlayMotionInternal(m_actorInstance, m_configuration, /*deleteOnZeroWeight*/false);
}
}

@ -805,7 +805,10 @@ namespace LmbrCentral
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect();
gEnv->p3DEngine->FreeRenderNodeState(&m_cubemapPreview);
if (gEnv->p3DEngine)
{
gEnv->p3DEngine->FreeRenderNodeState(&m_cubemapPreview);
}
m_light.DestroyRenderLight();
m_light.SetEntity(AZ::EntityId());
@ -903,6 +906,11 @@ namespace LmbrCentral
void EditorLightComponent::OnViewCubemapChanged()
{
if (!gEnv->p3DEngine)
{
return;
}
if (m_viewCubemap)
{
gEnv->p3DEngine->RegisterEntity(&m_cubemapPreview);
@ -1944,6 +1952,11 @@ namespace LmbrCentral
AzToolsFramework::EditorRequestBus::BroadcastResult(m_editor, &AzToolsFramework::EditorRequests::GetEditor);
}
if (!m_editor->Get3DEngine())
{
return;
}
if (!m_materialManager)
{
m_materialManager = m_editor->Get3DEngine()->GetMaterialManager();

@ -136,13 +136,16 @@ namespace
const char* texturePath = configuration.m_projectorTexture.GetAssetPath().c_str();
const int flags = FT_DONT_STREAM;
lightParams.m_pLightImage = gEnv->pRenderer->EF_LoadTexture(texturePath, flags);
if (!lightParams.m_pLightImage || !lightParams.m_pLightImage->IsTextureLoaded())
if (gEnv->pRenderer)
{
GetISystem()->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, 0, texturePath,
"Light projector texture not found: %s", texturePath);
lightParams.m_pLightImage = gEnv->pRenderer->EF_LoadTexture("Textures/defaults/red.dds", flags);
lightParams.m_pLightImage = gEnv->pRenderer->EF_LoadTexture(texturePath, flags);
if (!lightParams.m_pLightImage || !lightParams.m_pLightImage->IsTextureLoaded())
{
GetISystem()->Warning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, 0, texturePath,
"Light projector texture not found: %s", texturePath);
lightParams.m_pLightImage = gEnv->pRenderer->EF_LoadTexture("Textures/defaults/red.dds", flags);
}
}
}
break;
@ -180,8 +183,11 @@ namespace
diffuseMap.insert(dotPos, "_diff");
}
lightParams.SetSpecularCubemap(gEnv->pRenderer->EF_LoadCubemapTexture(specularMap.c_str(), FT_DONT_STREAM));
lightParams.SetDiffuseCubemap(gEnv->pRenderer->EF_LoadCubemapTexture(diffuseMap.c_str(), FT_DONT_STREAM));
if (gEnv->pRenderer)
{
lightParams.SetSpecularCubemap(gEnv->pRenderer->EF_LoadCubemapTexture(specularMap.c_str(), FT_DONT_STREAM));
lightParams.SetDiffuseCubemap(gEnv->pRenderer->EF_LoadCubemapTexture(diffuseMap.c_str(), FT_DONT_STREAM));
}
if (lightParams.GetDiffuseCubemap() && lightParams.GetSpecularCubemap())
{
@ -401,7 +407,7 @@ namespace LmbrCentral
template <typename ConfigurationType, typename ConfigToLightParamsFunc>
void LightInstance::CreateRenderLightInternal(const ConfigurationType& configuration, ConfigToLightParamsFunc configToLightParams)
{
if (m_renderLight || !configuration.m_visible)
if (m_renderLight || !configuration.m_visible || !gEnv->p3DEngine)
{
return;
}

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

Loading…
Cancel
Save