Integrating github/staging through commit b0dd7ed
This commit is contained in:
@@ -71,10 +71,14 @@ COMPILE_TIME_ASSERT(sizeof(uint32) == 4);
|
||||
COMPILE_TIME_ASSERT(sizeof(sint32) == 4);
|
||||
|
||||
typedef slonglong int64;
|
||||
|
||||
#ifndef O3DE_INT64_DEFINED
|
||||
#define O3DE_INT64_DEFINED
|
||||
typedef slonglong sint64;
|
||||
typedef ulonglong uint64;
|
||||
COMPILE_TIME_ASSERT(sizeof(uint64) == 8);
|
||||
COMPILE_TIME_ASSERT(sizeof(sint64) == 8);
|
||||
#endif
|
||||
|
||||
|
||||
typedef float f32;
|
||||
|
||||
@@ -19,6 +19,6 @@ ly_add_target(
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::FreeType2
|
||||
3rdParty::freetype
|
||||
Legacy::CryCommon
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#endif
|
||||
|
||||
#if !(defined(ANDROID) || defined(IOS) || defined(LINUX)) && AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO // Rally US1050 - Compile libtiff for Android and IOS
|
||||
#include <libtiff/tiffio.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
static_assert(sizeof(thandle_t) >= sizeof(AZ::IO::HandleType), "Platform defines thandle_t to be smaller than required");
|
||||
#endif
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace AZ
|
||||
{
|
||||
const static AZ::Crc32 RuntimeEBusAttribute = AZ_CRC("RuntimeEBus", 0x466b899b); ///< Signals that this reflected ebus should only be available at runtime, helps tools filter out data driven ebuses
|
||||
|
||||
constexpr const char* k_PropertyNameGetterSuffix = "::Getter";
|
||||
constexpr const char* k_PropertyNameSetterSuffix = "::Setter";
|
||||
|
||||
/// Typedef for class unwrapping callback (i.e. used for things like smart_ptr<T> to unwrap for T)
|
||||
using BehaviorClassUnwrapperFunction = void(*)(void* /*classPtr*/, void*& /*unwrappedClass*/, AZ::Uuid& /*unwrappedClassTypeId*/, void* /*userData*/);
|
||||
|
||||
@@ -2525,7 +2528,7 @@ namespace AZ
|
||||
getterPropertyName += "::";
|
||||
}
|
||||
getterPropertyName += m_name;
|
||||
getterPropertyName += "::Getter";
|
||||
getterPropertyName += k_PropertyNameGetterSuffix;
|
||||
m_getter = aznew GetterType(getter, context, getterPropertyName);
|
||||
|
||||
if (AZStd::is_class<typename GetterType::ClassType>::value)
|
||||
@@ -2603,7 +2606,7 @@ namespace AZ
|
||||
setterPropertyName += "::";
|
||||
}
|
||||
setterPropertyName += m_name;
|
||||
setterPropertyName += "::Setter";
|
||||
setterPropertyName += k_PropertyNameSetterSuffix;
|
||||
m_setter = aznew SetterType(setter, context, setterPropertyName);
|
||||
if (AZStd::is_class<typename SetterType::ClassType>::value)
|
||||
{
|
||||
|
||||
@@ -243,6 +243,28 @@ namespace AZ
|
||||
return variance;
|
||||
}
|
||||
|
||||
void RemovePropertyGetterNameArtifacts(AZStd::string& name)
|
||||
{
|
||||
if (name.ends_with(k_PropertyNameGetterSuffix))
|
||||
{
|
||||
AZ::StringFunc::Replace(name, k_PropertyNameGetterSuffix, "");
|
||||
}
|
||||
}
|
||||
|
||||
void RemovePropertySetterNameArtifacts(AZStd::string& name)
|
||||
{
|
||||
if (name.ends_with(k_PropertyNameSetterSuffix))
|
||||
{
|
||||
AZ::StringFunc::Replace(name, k_PropertyNameSetterSuffix, "");
|
||||
}
|
||||
}
|
||||
|
||||
void RemovePropertyNameArtifacts(AZStd::string& name)
|
||||
{
|
||||
RemovePropertyGetterNameArtifacts(name);
|
||||
RemovePropertySetterNameArtifacts(name);
|
||||
}
|
||||
|
||||
AZStd::string ReplaceCppArtifacts(AZStd::string_view sourceName)
|
||||
{
|
||||
using namespace AZ::StringFunc;
|
||||
|
||||
@@ -68,6 +68,12 @@ namespace AZ
|
||||
|
||||
AZStd::vector<AZStd::pair<const BehaviorMethod*, const BehaviorClass*>> OverloadsToVector(const BehaviorMethod&, const BehaviorClass*);
|
||||
|
||||
void RemovePropertyGetterNameArtifacts(AZStd::string& name);
|
||||
|
||||
void RemovePropertySetterNameArtifacts(AZStd::string& name);
|
||||
|
||||
void RemovePropertyNameArtifacts(AZStd::string& name);
|
||||
|
||||
AZStd::string ReplaceCppArtifacts(AZStd::string_view sourceName);
|
||||
|
||||
void StripQualifiers(AZStd::string& name);
|
||||
|
||||
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CameraInput.h"
|
||||
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Math/Plane.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void CameraSystem::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& cursor_motion = AZStd::get_if<CursorMotionEvent>(&event))
|
||||
{
|
||||
m_currentCursorPosition = cursor_motion->m_position;
|
||||
}
|
||||
else if (const auto& scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
m_scrollDelta = scroll->m_delta;
|
||||
}
|
||||
|
||||
m_cameras.HandleEvents(event);
|
||||
}
|
||||
|
||||
Camera CameraSystem::StepCamera(const Camera& targetCamera, float deltaTime)
|
||||
{
|
||||
const auto cursorDelta = m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value()
|
||||
? m_currentCursorPosition.value() - m_lastCursorPosition.value()
|
||||
: ScreenVector(0, 0);
|
||||
|
||||
if (m_currentCursorPosition.has_value())
|
||||
{
|
||||
m_lastCursorPosition = m_currentCursorPosition;
|
||||
}
|
||||
|
||||
const auto nextCamera = m_cameras.StepCamera(targetCamera, cursorDelta, m_scrollDelta, deltaTime);
|
||||
|
||||
m_scrollDelta = 0.0f;
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> camera_input)
|
||||
{
|
||||
m_idleCameraInputs.push_back(AZStd::move(camera_input));
|
||||
}
|
||||
|
||||
void Cameras::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
}
|
||||
|
||||
for (auto& camera_input : m_idleCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
}
|
||||
}
|
||||
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, const float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < m_idleCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_idleCameraInputs[i];
|
||||
const bool can_begin = camera_input->Beginning() &&
|
||||
std::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
|
||||
[](const auto& input) { return !input->Exclusive(); }) &&
|
||||
(!camera_input->Exclusive() || (camera_input->Exclusive() && m_activeCameraInputs.empty()));
|
||||
if (can_begin)
|
||||
{
|
||||
m_activeCameraInputs.push_back(camera_input);
|
||||
using AZStd::swap;
|
||||
swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
|
||||
m_idleCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// accumulate
|
||||
Camera nextCamera = targetCamera;
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
{
|
||||
nextCamera = camera_input->StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_activeCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_activeCameraInputs[i];
|
||||
if (camera_input->Ending())
|
||||
{
|
||||
camera_input->ClearActivation();
|
||||
m_idleCameraInputs.push_back(camera_input);
|
||||
using AZStd::swap;
|
||||
swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
camera_input->ContinueActivation();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void Cameras::Reset()
|
||||
{
|
||||
for (int i = 0; i < m_activeCameraInputs.size();)
|
||||
{
|
||||
m_activeCameraInputs[i]->Reset();
|
||||
m_idleCameraInputs.push_back(m_activeCameraInputs[i]);
|
||||
m_activeCameraInputs[i] = m_activeCameraInputs[m_activeCameraInputs.size() - 1];
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void RotateCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == m_channelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera RotateCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
nextCamera.m_pitch += float(cursorDelta.m_y) * m_props.m_rotateSpeed;
|
||||
nextCamera.m_yaw += float(cursorDelta.m_x) * m_props.m_rotateSpeed;
|
||||
|
||||
auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoOverPi, AZ::Constants::TwoOverPi); };
|
||||
|
||||
nextCamera.m_yaw = clamp_rotation(nextCamera.m_yaw);
|
||||
// clamp pitch to be +-90 degrees
|
||||
nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::Pi * 0.5f, AZ::Constants::Pi * 0.5f);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void PanCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Middle)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera PanCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto pan_axes = m_panAxesFn(nextCamera);
|
||||
|
||||
const auto delta_pan_x = float(cursorDelta.m_x) * pan_axes.m_horizontalAxis * m_props.m_panSpeed;
|
||||
const auto delta_pan_y = float(cursorDelta.m_y) * pan_axes.m_verticalAxis * m_props.m_panSpeed;
|
||||
|
||||
const auto inv = [](const bool invert) {
|
||||
constexpr float Dir[] = {1.0f, -1.0f};
|
||||
return Dir[static_cast<int>(invert)];
|
||||
};
|
||||
|
||||
nextCamera.m_lookAt += delta_pan_x * inv(m_props.m_panInvertX);
|
||||
nextCamera.m_lookAt += delta_pan_y * -inv(m_props.m_panInvertY);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
TranslateCameraInput::TranslationType TranslateCameraInput::translationFromKey(InputChannelId channelId)
|
||||
{
|
||||
// note: remove hard-coded InputDevice keys
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericW)
|
||||
{
|
||||
return TranslationType::Forward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericS)
|
||||
{
|
||||
return TranslationType::Backward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericA)
|
||||
{
|
||||
return TranslationType::Left;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericD)
|
||||
{
|
||||
return TranslationType::Right;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericQ)
|
||||
{
|
||||
return TranslationType::Down;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericE)
|
||||
{
|
||||
return TranslationType::Up;
|
||||
}
|
||||
|
||||
return TranslationType::Nil;
|
||||
}
|
||||
|
||||
void TranslateCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Updated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_translation |= translationFromKey(input->m_channelId);
|
||||
if (m_translation != TranslationType::Nil)
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
{
|
||||
m_boost = true;
|
||||
}
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
m_translation ^= translationFromKey(input->m_channelId);
|
||||
if (m_translation == TranslationType::Nil)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
{
|
||||
m_boost = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera TranslateCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
|
||||
const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto translation_basis = m_translationAxesFn(nextCamera);
|
||||
const auto axisX = translation_basis.GetBasisX();
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
const auto axisZ = translation_basis.GetBasisZ();
|
||||
|
||||
const float speed = [boost = m_boost, props = m_props]() {
|
||||
return props.m_translateSpeed * (boost ? props.m_boostMultiplier : 1.0f);
|
||||
}();
|
||||
|
||||
if ((m_translation & TranslationType::Forward) == TranslationType::Forward)
|
||||
{
|
||||
nextCamera.m_lookAt += axisY * speed * deltaTime;
|
||||
}
|
||||
|
||||
if ((m_translation & TranslationType::Backward) == TranslationType::Backward)
|
||||
{
|
||||
nextCamera.m_lookAt -= axisY * speed * deltaTime;
|
||||
}
|
||||
|
||||
if ((m_translation & TranslationType::Left) == TranslationType::Left)
|
||||
{
|
||||
nextCamera.m_lookAt -= axisX * speed * deltaTime;
|
||||
}
|
||||
|
||||
if ((m_translation & TranslationType::Right) == TranslationType::Right)
|
||||
{
|
||||
nextCamera.m_lookAt += axisX * speed * deltaTime;
|
||||
}
|
||||
|
||||
if ((m_translation & TranslationType::Up) == TranslationType::Up)
|
||||
{
|
||||
nextCamera.m_lookAt += axisZ * speed * deltaTime;
|
||||
}
|
||||
|
||||
if ((m_translation & TranslationType::Down) == TranslationType::Down)
|
||||
{
|
||||
nextCamera.m_lookAt -= axisZ * speed * deltaTime;
|
||||
}
|
||||
|
||||
if (Ending())
|
||||
{
|
||||
m_translation = TranslationType::Nil;
|
||||
}
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void TranslateCameraInput::ResetImpl()
|
||||
{
|
||||
m_translation = TranslationType::Nil;
|
||||
m_boost = false;
|
||||
}
|
||||
|
||||
void OrbitCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierAltL)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Updated)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (Active())
|
||||
{
|
||||
m_orbitCameras.HandleEvents(event);
|
||||
}
|
||||
}
|
||||
|
||||
Camera OrbitCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
if (Beginning())
|
||||
{
|
||||
float hit_distance = 0.0f;
|
||||
if (AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateZero())
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY() * m_props.m_maxOrbitDistance, hit_distance))
|
||||
{
|
||||
nextCamera.m_lookDist = -hit_distance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCamera.m_lookDist = -m_props.m_defaultOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * m_props.m_defaultOrbitDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (Active())
|
||||
{
|
||||
// todo: need to return nested cameras to idle state when ending
|
||||
nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
if (Ending())
|
||||
{
|
||||
m_orbitCameras.Reset();
|
||||
|
||||
nextCamera.m_lookAt = nextCamera.Translation();
|
||||
nextCamera.m_lookDist = 0.0f;
|
||||
}
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void OrbitDollyScrollCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
}
|
||||
|
||||
Camera OrbitDollyScrollCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
|
||||
[[maybe_unused]] float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * m_props.m_dollySpeed, 0.0f);
|
||||
EndActivation();
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void OrbitDollyCursorMoveCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Right)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera OrbitDollyCursorMoveCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * m_props.m_dollySpeed, 0.0f);
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void ScrollTranslationCameraInput::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
BeginActivation();
|
||||
}
|
||||
}
|
||||
|
||||
Camera ScrollTranslationCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto translation_basis = LookTranslation(nextCamera);
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
|
||||
nextCamera.m_lookAt += axisY * scrollDelta * m_props.m_translateSpeed;
|
||||
|
||||
EndActivation();
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, const float deltaTime)
|
||||
{
|
||||
const auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
|
||||
// keep yaw in 0 - 360 range
|
||||
float target_yaw = clamp_rotation(targetCamera.m_yaw);
|
||||
const float current_yaw = clamp_rotation(currentCamera.m_yaw);
|
||||
|
||||
auto sign = [](const float value) { return static_cast<float>((0.0f < value) - (value < 0.0f)); };
|
||||
|
||||
// ensure smooth transition when moving across 0 - 360 boundary
|
||||
const float yaw_delta = target_yaw - current_yaw;
|
||||
if (std::abs(yaw_delta) >= AZ::Constants::Pi)
|
||||
{
|
||||
target_yaw -= AZ::Constants::TwoPi * sign(yaw_delta);
|
||||
}
|
||||
|
||||
Camera camera;
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
|
||||
const float lookRate = std::exp2(props.m_lookSmoothness);
|
||||
const float lookT = std::exp2(-lookRate * deltaTime);
|
||||
camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookT);
|
||||
camera.m_yaw = AZ::Lerp(target_yaw, current_yaw, lookT);
|
||||
const float moveRate = std::exp2(props.m_moveSmoothness);
|
||||
const float moveT = std::exp2(-moveRate * deltaTime);
|
||||
camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveT);
|
||||
camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveT);
|
||||
return camera;
|
||||
}
|
||||
|
||||
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize)
|
||||
{
|
||||
const auto& inputChannelId = inputChannel.GetInputChannelId();
|
||||
const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
|
||||
|
||||
if (inputChannelId == InputDeviceMouse::SystemCursorPosition)
|
||||
{
|
||||
AZ::Vector2 systemCursorPositionNormalized = AZ::Vector2::CreateZero();
|
||||
InputSystemCursorRequestBus::EventResult(
|
||||
systemCursorPositionNormalized, inputDeviceId, &InputSystemCursorRequestBus::Events::GetSystemCursorPositionNormalized);
|
||||
|
||||
return CursorMotionEvent{ScreenPoint(
|
||||
systemCursorPositionNormalized.GetX() * windowSize.m_width, systemCursorPositionNormalized.GetY() * windowSize.m_height)};
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Movement::Z)
|
||||
{
|
||||
return ScrollEvent{inputChannel.GetValue()};
|
||||
}
|
||||
else if (InputDeviceMouse::IsMouseDevice(inputDeviceId) || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
|
||||
{
|
||||
return DiscreteInputEvent{inputChannelId, inputChannel.GetState()};
|
||||
}
|
||||
|
||||
return AZStd::monostate{};
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Input/Channels/InputChannel.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct WindowSize;
|
||||
|
||||
struct Camera
|
||||
{
|
||||
AZ::Vector3 m_lookAt = AZ::Vector3::CreateZero(); //!< Position of camera when m_lookDist is zero,
|
||||
//!< or position of m_lookAt when m_lookDist is greater
|
||||
//!< than zero.
|
||||
float m_yaw{0.0};
|
||||
float m_pitch{0.0};
|
||||
float m_lookDist{0.0}; //!< Zero gives first person free look, otherwise orbit about m_lookAt
|
||||
|
||||
//! View camera transform (v in MVP).
|
||||
AZ::Transform View() const;
|
||||
//! World camera transform.
|
||||
AZ::Transform Transform() const;
|
||||
//! World rotation.
|
||||
AZ::Matrix3x3 Rotation() const;
|
||||
//! World translation.
|
||||
AZ::Vector3 Translation() const;
|
||||
};
|
||||
|
||||
inline AZ::Transform Camera::View() const
|
||||
{
|
||||
return Transform().GetInverse();
|
||||
}
|
||||
|
||||
inline AZ::Transform Camera::Transform() const
|
||||
{
|
||||
return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationX(m_pitch) *
|
||||
AZ::Transform::CreateRotationZ(m_yaw) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisZ(m_lookDist));
|
||||
}
|
||||
|
||||
inline AZ::Matrix3x3 Camera::Rotation() const
|
||||
{
|
||||
return AZ::Matrix3x3::CreateFromQuaternion(Transform().GetRotation());
|
||||
}
|
||||
|
||||
inline AZ::Vector3 Camera::Translation() const
|
||||
{
|
||||
return Transform().GetTranslation();
|
||||
}
|
||||
|
||||
struct CursorMotionEvent
|
||||
{
|
||||
ScreenPoint m_position;
|
||||
};
|
||||
|
||||
struct ScrollEvent
|
||||
{
|
||||
float m_delta;
|
||||
};
|
||||
|
||||
struct DiscreteInputEvent
|
||||
{
|
||||
InputChannelId m_channelId; //!< Channel type. (e.g. Keyboard key, mouse button or other device input).
|
||||
InputChannel::State m_state; //!< Channel state. (e.g. Begin/update/end event).
|
||||
};
|
||||
|
||||
using InputEvent = AZStd::variant<AZStd::monostate, CursorMotionEvent, ScrollEvent, DiscreteInputEvent>;
|
||||
|
||||
class CameraInput
|
||||
{
|
||||
public:
|
||||
enum class Activation
|
||||
{
|
||||
Idle,
|
||||
Begin,
|
||||
Active,
|
||||
End
|
||||
};
|
||||
|
||||
virtual ~CameraInput() = default;
|
||||
|
||||
bool Beginning() const
|
||||
{
|
||||
return m_activation == Activation::Begin;
|
||||
}
|
||||
|
||||
bool Ending() const
|
||||
{
|
||||
return m_activation == Activation::End;
|
||||
}
|
||||
|
||||
bool Idle() const
|
||||
{
|
||||
return m_activation == Activation::Idle;
|
||||
}
|
||||
|
||||
bool Active() const
|
||||
{
|
||||
return m_activation == Activation::Active;
|
||||
}
|
||||
|
||||
void BeginActivation()
|
||||
{
|
||||
m_activation = Activation::Begin;
|
||||
}
|
||||
|
||||
void EndActivation()
|
||||
{
|
||||
m_activation = Activation::End;
|
||||
}
|
||||
|
||||
void ContinueActivation()
|
||||
{
|
||||
m_activation = Activation::Active;
|
||||
}
|
||||
|
||||
void ClearActivation()
|
||||
{
|
||||
m_activation = Activation::Idle;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ClearActivation();
|
||||
ResetImpl();
|
||||
}
|
||||
|
||||
virtual void HandleEvents(const InputEvent& event) = 0;
|
||||
virtual Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) = 0;
|
||||
|
||||
virtual bool Exclusive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ResetImpl()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Activation m_activation = Activation::Idle;
|
||||
};
|
||||
|
||||
struct SmoothProps
|
||||
{
|
||||
float m_lookSmoothness = 5.0f;
|
||||
float m_moveSmoothness = 5.0f;
|
||||
};
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, float deltaTime);
|
||||
|
||||
class Cameras
|
||||
{
|
||||
public:
|
||||
void AddCamera(AZStd::shared_ptr<CameraInput> cameraInput);
|
||||
void HandleEvents(const InputEvent& event);
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime);
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
AZStd::vector<AZStd::shared_ptr<CameraInput>> m_activeCameraInputs;
|
||||
AZStd::vector<AZStd::shared_ptr<CameraInput>> m_idleCameraInputs;
|
||||
};
|
||||
|
||||
class CameraSystem
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event);
|
||||
Camera StepCamera(const Camera& targetCamera, float deltaTime);
|
||||
|
||||
Cameras m_cameras;
|
||||
|
||||
private:
|
||||
float m_scrollDelta = 0.0f;
|
||||
AZStd::optional<ScreenPoint> m_lastCursorPosition;
|
||||
AZStd::optional<ScreenPoint> m_currentCursorPosition;
|
||||
};
|
||||
|
||||
class RotateCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit RotateCameraInput(const InputChannelId channelId)
|
||||
: m_channelId(channelId)
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
InputChannelId m_channelId;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_rotateSpeed = 0.005f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
struct PanAxes
|
||||
{
|
||||
AZ::Vector3 m_horizontalAxis;
|
||||
AZ::Vector3 m_verticalAxis;
|
||||
};
|
||||
|
||||
using PanAxesFn = AZStd::function<PanAxes(const Camera& camera)>;
|
||||
|
||||
inline PanAxes LookPan(const Camera& camera)
|
||||
{
|
||||
const AZ::Matrix3x3 orientation = camera.Rotation();
|
||||
return {orientation.GetBasisX(), orientation.GetBasisZ()};
|
||||
}
|
||||
|
||||
inline PanAxes OrbitPan(const Camera& camera)
|
||||
{
|
||||
const AZ::Matrix3x3 orientation = camera.Rotation();
|
||||
|
||||
const auto basisX = orientation.GetBasisX();
|
||||
const auto basisY = [&orientation] {
|
||||
const auto forward = orientation.GetBasisY();
|
||||
return AZ::Vector3(forward.GetX(), forward.GetY(), 0.0f).GetNormalized();
|
||||
}();
|
||||
|
||||
return {basisX, basisY};
|
||||
}
|
||||
|
||||
class PanCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit PanCameraInput(PanAxesFn panAxesFn)
|
||||
: m_panAxesFn(AZStd::move(panAxesFn))
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_panSpeed = 0.01f;
|
||||
bool m_panInvertX = true;
|
||||
bool m_panInvertY = true;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
PanAxesFn m_panAxesFn;
|
||||
};
|
||||
|
||||
using TranslationAxesFn = AZStd::function<AZ::Matrix3x3(const Camera& camera)>;
|
||||
|
||||
inline AZ::Matrix3x3 LookTranslation(const Camera& camera)
|
||||
{
|
||||
const AZ::Matrix3x3 orientation = camera.Rotation();
|
||||
|
||||
const auto basisX = orientation.GetBasisX();
|
||||
const auto basisY = orientation.GetBasisY();
|
||||
const auto basisZ = AZ::Vector3::CreateAxisZ();
|
||||
|
||||
return AZ::Matrix3x3::CreateFromColumns(basisX, basisY, basisZ);
|
||||
}
|
||||
|
||||
inline AZ::Matrix3x3 OrbitTranslation(const Camera& camera)
|
||||
{
|
||||
const AZ::Matrix3x3 orientation = camera.Rotation();
|
||||
|
||||
const auto basisX = orientation.GetBasisX();
|
||||
const auto basisY = [&orientation] {
|
||||
const auto forward = orientation.GetBasisY();
|
||||
return AZ::Vector3(forward.GetX(), forward.GetY(), 0.0f).GetNormalized();
|
||||
}();
|
||||
const auto basisZ = AZ::Vector3::CreateAxisZ();
|
||||
|
||||
return AZ::Matrix3x3::CreateFromColumns(basisX, basisY, basisZ);
|
||||
}
|
||||
|
||||
class TranslateCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit TranslateCameraInput(TranslationAxesFn translationAxesFn)
|
||||
: m_translationAxesFn(AZStd::move(translationAxesFn))
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
void ResetImpl() override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 10.0f;
|
||||
float m_boostMultiplier = 3.0f;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
enum class TranslationType
|
||||
{
|
||||
// clang-format off
|
||||
Nil = 0,
|
||||
Forward = 1 << 0,
|
||||
Backward = 1 << 1,
|
||||
Left = 1 << 2,
|
||||
Right = 1 << 3,
|
||||
Up = 1 << 4,
|
||||
Down = 1 << 5,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
friend TranslationType operator|(const TranslationType lhs, const TranslationType rhs)
|
||||
{
|
||||
return static_cast<TranslationType>(
|
||||
static_cast<std::underlying_type_t<TranslationType>>(lhs) | static_cast<std::underlying_type_t<TranslationType>>(rhs));
|
||||
}
|
||||
|
||||
friend TranslationType& operator|=(TranslationType& lhs, const TranslationType rhs)
|
||||
{
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend TranslationType operator^(const TranslationType lhs, const TranslationType rhs)
|
||||
{
|
||||
return static_cast<TranslationType>(
|
||||
static_cast<std::underlying_type_t<TranslationType>>(lhs) ^ static_cast<std::underlying_type_t<TranslationType>>(rhs));
|
||||
}
|
||||
|
||||
friend TranslationType& operator^=(TranslationType& lhs, const TranslationType rhs)
|
||||
{
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend TranslationType operator&(const TranslationType lhs, const TranslationType rhs)
|
||||
{
|
||||
return static_cast<TranslationType>(
|
||||
static_cast<std::underlying_type_t<TranslationType>>(lhs) & static_cast<std::underlying_type_t<TranslationType>>(rhs));
|
||||
}
|
||||
|
||||
friend TranslationType& operator&=(TranslationType& lhs, const TranslationType rhs)
|
||||
{
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
static TranslationType translationFromKey(InputChannelId channelId);
|
||||
|
||||
TranslationType m_translation = TranslationType::Nil;
|
||||
TranslationAxesFn m_translationAxesFn;
|
||||
bool m_boost = false;
|
||||
};
|
||||
|
||||
class OrbitDollyScrollCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitDollyCursorMoveCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.1f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class ScrollTranslationCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
bool Exclusive() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Cameras m_orbitCameras;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_defaultOrbitDistance = 15.0f;
|
||||
float m_maxOrbitDistance = 100.0f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize);
|
||||
} // namespace AzFramework
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
@@ -60,17 +61,18 @@ namespace AzFramework
|
||||
{
|
||||
//! The viewport ID this event was dispatched to.
|
||||
ViewportId m_viewportId;
|
||||
//! The native window handle for the application.
|
||||
NativeWindowHandle m_windowHandle;
|
||||
//! The input channel data for this event.
|
||||
const AzFramework::InputChannel& m_inputChannel;
|
||||
//! The priority this event was dispatched at.
|
||||
ViewportControllerPriority m_priority;
|
||||
|
||||
ViewportControllerInputEvent(
|
||||
ViewportId viewportId,
|
||||
const AzFramework::InputChannel& inputChannel,
|
||||
ViewportControllerPriority priority = ViewportControllerPriority::DispatchToAllPriorities
|
||||
)
|
||||
ViewportId viewportId, NativeWindowHandle windowHandle, const AzFramework::InputChannel& inputChannel,
|
||||
ViewportControllerPriority priority = ViewportControllerPriority::DispatchToAllPriorities)
|
||||
: m_viewportId(viewportId)
|
||||
, m_windowHandle(windowHandle)
|
||||
, m_inputChannel(inputChannel)
|
||||
, m_priority(priority)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,8 @@ set(FILES
|
||||
Viewport/ScreenGeometry.cpp
|
||||
Viewport/CameraState.h
|
||||
Viewport/CameraState.cpp
|
||||
Viewport/CameraInput.h
|
||||
Viewport/CameraInput.cpp
|
||||
Viewport/DisplayContextRequestBus.h
|
||||
Entity/BehaviorEntity.cpp
|
||||
Entity/BehaviorEntity.h
|
||||
|
||||
+2
-4
@@ -43,14 +43,12 @@ namespace AzToolsFramework
|
||||
const PrefabDom& modifiedState, const LinkId linkId) = 0;
|
||||
|
||||
//! Updates the affected template for a given entityId using the providedPatch
|
||||
virtual bool PatchEntityInTemplate(PrefabDomValue& providedPatch, const AZ::EntityId& entityId) = 0;
|
||||
|
||||
virtual bool PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId) = 0;
|
||||
virtual bool PatchEntityInTemplate(PrefabDom& providedPatch, AZ::EntityId entityId) = 0;
|
||||
|
||||
virtual void AppendEntityAliasToPatchPaths(PrefabDom& providedPatch, const AZ::EntityId& entityId) = 0;
|
||||
|
||||
//! Updates the template links (updating instances) for the given templateId using the providedPatch
|
||||
virtual void PatchTemplate(PrefabDomValue& providedPatch, const TemplateId& templateId) = 0;
|
||||
virtual bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId) = 0;
|
||||
|
||||
virtual void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) = 0;
|
||||
|
||||
|
||||
+14
-52
@@ -107,7 +107,7 @@ namespace AzToolsFramework
|
||||
return result.GetProcessing() != AZ::JsonSerializationResult::Processing::Halted;
|
||||
}
|
||||
|
||||
bool InstanceToTemplatePropagator::PatchEntityInTemplate(PrefabDomValue& providedPatch, const AZ::EntityId& entityId)
|
||||
bool InstanceToTemplatePropagator::PatchEntityInTemplate(PrefabDom& providedPatch, AZ::EntityId entityId)
|
||||
{
|
||||
InstanceOptionalReference instanceOptionalReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||
|
||||
@@ -119,53 +119,10 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
//get template space associated with instance
|
||||
Instance& instance = instanceOptionalReference->get();
|
||||
TemplateId templateId = instance.GetTemplateId();
|
||||
|
||||
//alias entity goes by in template -> get via owning instance map
|
||||
AZStd::optional<EntityAlias> entityAlias = instance.GetEntityAlias(entityId);
|
||||
|
||||
if (!entityAlias)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to find an entity alias for the provided entity");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return PatchEntityInTemplate(providedPatch, entityAlias.value(), templateId);
|
||||
}
|
||||
|
||||
bool InstanceToTemplatePropagator::PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId)
|
||||
{
|
||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
//query into the template dom for the alias
|
||||
PrefabDomValueReference entityList = PrefabDomUtils::FindPrefabDomValue(templateDomReference, PrefabDomUtils::EntitiesName);
|
||||
|
||||
if (!entityList)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Cannot patch entity in Template with id [%llu] because entity couldn't be found in the template", templateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
PrefabDomValueReference entity = PrefabDomUtils::FindPrefabDomValue(entityList->get(), entityAlias.c_str());
|
||||
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to aquire entity value reference");
|
||||
return false;
|
||||
}
|
||||
|
||||
//apply patch to section
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(entity->get(),
|
||||
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
|
||||
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success, "Patch was not successfully applied")
|
||||
|
||||
//trigger propagation
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId);
|
||||
return true;
|
||||
//get template id associated with instance
|
||||
TemplateId templateId = instanceOptionalReference->get().GetTemplateId();
|
||||
AppendEntityAliasToPatchPaths(providedPatch, entityId);
|
||||
return PatchTemplate(providedPatch, templateId);
|
||||
}
|
||||
|
||||
void InstanceToTemplatePropagator::AppendEntityAliasToPatchPaths(PrefabDom& providedPatch, const AZ::EntityId& entityId)
|
||||
@@ -215,7 +172,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, const TemplateId& templateId)
|
||||
bool InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId)
|
||||
{
|
||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
@@ -223,14 +180,17 @@ namespace AzToolsFramework
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference,
|
||||
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
|
||||
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
||||
"Patch was not successfully applied");
|
||||
|
||||
//trigger propagation
|
||||
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success)
|
||||
{
|
||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab", false, "Patch was not successfully applied");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +247,8 @@ namespace AzToolsFramework
|
||||
|
||||
AddPatchesToLink(patches, linkToApplyPatches);
|
||||
linkToApplyPatches.UpdateTarget();
|
||||
|
||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(linkToApplyPatches.GetTargetTemplateId(), true);
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(linkToApplyPatches.GetTargetTemplateId());
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -31,21 +31,19 @@ namespace AzToolsFramework
|
||||
bool GeneratePatch(PrefabDom& generatedPatch, const PrefabDom& initialState, const PrefabDom& modifiedState) override;
|
||||
bool GeneratePatchForLink(PrefabDom& generatedPatch, const PrefabDom& initialState,
|
||||
const PrefabDom& modifiedState, LinkId linkId) override;
|
||||
bool PatchEntityInTemplate(PrefabDomValue& providedPatch, const AZ::EntityId& entityId) override;
|
||||
bool PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId) override;
|
||||
bool PatchEntityInTemplate(PrefabDom& providedPatch, AZ::EntityId entityId) override;
|
||||
|
||||
void AppendEntityAliasToPatchPaths(PrefabDom& providedPatch, const AZ::EntityId& entityId) override;
|
||||
|
||||
InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId);
|
||||
|
||||
void PatchTemplate(PrefabDomValue& providedPatch, const AzToolsFramework::Prefab::TemplateId& templateId) override;
|
||||
bool PatchTemplate(PrefabDomValue& providedPatch, TemplateId templateId) override;
|
||||
|
||||
void ApplyPatchesToInstance(const AZ::EntityId& entityId, PrefabDom& patches, const Instance& instanceToAddPatches) override;
|
||||
|
||||
void AddPatchesToLink(PrefabDom& patches, Link& link);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface;
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface;
|
||||
|
||||
@@ -127,12 +127,12 @@ namespace AzToolsFramework
|
||||
InstanceEntityScrubber instanceEntityScrubber(newlyAddedEntities);
|
||||
settings.m_metadata.Add(&instanceEntityScrubber);
|
||||
|
||||
AZ::JsonSerializationResult::ResultCode result =
|
||||
AZ::JsonSerialization::Load(instance, prefabDom, settings);
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings);
|
||||
|
||||
if (result.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"Failed to de-serialize Prefab Instance from Prefab DOM. "
|
||||
"Unable to proceed.");
|
||||
|
||||
|
||||
@@ -348,8 +348,7 @@ namespace AzToolsFramework
|
||||
"Prefab", false,
|
||||
"PrefabLoader::SaveTemplate - Unable to save Prefab Template with id: %llu. "
|
||||
"Template with that id is invalid",
|
||||
templateId
|
||||
);
|
||||
templateId);
|
||||
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
@@ -79,13 +79,16 @@ namespace AzToolsFramework
|
||||
|
||||
//generate undo/redo patches
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_redoPatch, initialState, endState);
|
||||
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(m_redoPatch, entityId);
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_undoPatch, endState, initialState);
|
||||
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(m_undoPatch, entityId);
|
||||
}
|
||||
|
||||
void PrefabUndoEntityUpdate::Undo()
|
||||
{
|
||||
[[maybe_unused]] bool isPatchApplicationSuccessful =
|
||||
m_instanceToTemplateInterface->PatchEntityInTemplate(m_undoPatch, m_entityAlias, m_templateId);
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", isPatchApplicationSuccessful,
|
||||
"Applying the undo patch on the entity with alias '%s' in template with id '%llu' was unsuccessful", m_entityAlias.c_str(),
|
||||
@@ -95,7 +98,8 @@ namespace AzToolsFramework
|
||||
void PrefabUndoEntityUpdate::Redo()
|
||||
{
|
||||
[[maybe_unused]] bool isPatchApplicationSuccessful =
|
||||
m_instanceToTemplateInterface->PatchEntityInTemplate(m_redoPatch, m_entityAlias, m_templateId);
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", isPatchApplicationSuccessful,
|
||||
"Applying the redo patch on the entity with alias '%s' in template with id '%llu' was unsuccessful", m_entityAlias.c_str(),
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
class QPoint;
|
||||
class QPoint; // LYN-2315 in-progress, remove this
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct ScreenPoint;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -235,12 +240,12 @@ namespace AzToolsFramework
|
||||
/// Restores the cursor and ends locking it in place, allowing it to be moved freely.
|
||||
virtual void EndCursorCapture() = 0;
|
||||
/// Gets the most recent recorded cursor position in the viewport in screen space coordinates.
|
||||
virtual QPoint ViewportCursorScreenPosition() = 0;
|
||||
virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0;
|
||||
/// Gets the cursor position recorded prior to the most recent cursor position.
|
||||
/// Note: The cursor may be captured by the viewport, in which case this may not correspond to the last result
|
||||
/// from ViewportCursorScreenPosition. This method will always return the correct position to generate a mouse
|
||||
/// position delta.
|
||||
virtual AZStd::optional<QPoint> PreviousViewportCursorScreenPosition() = 0;
|
||||
virtual AZStd::optional<AzFramework::ScreenPoint> PreviousViewportCursorScreenPosition() = 0;
|
||||
|
||||
protected:
|
||||
~ViewportMouseCursorRequests() = default;
|
||||
|
||||
@@ -202,12 +202,18 @@ namespace AzToolsFramework
|
||||
return mouseInteractionEvent.m_wheelDelta;
|
||||
}
|
||||
|
||||
/// Return Qt QPoint from an Viewport ScreenPoint.
|
||||
/// Return QPoint from AzFramework::ScreenPoint.
|
||||
inline QPoint QPointFromScreenPoint(const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
return {screenPoint.m_x, screenPoint.m_y};
|
||||
}
|
||||
|
||||
/// Return AzFramework::ScreenPoint from QPoint.
|
||||
inline AzFramework::ScreenPoint ScreenPointFromQPoint(const QPoint& qpoint)
|
||||
{
|
||||
return AzFramework::ScreenPoint{qpoint.x(), qpoint.y()};
|
||||
}
|
||||
|
||||
/// Map from Qt -> Lumberyard buttons.
|
||||
inline AZ::u32 TranslateMouseButtons(const Qt::MouseButtons buttons)
|
||||
{
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace UnitTest
|
||||
EntityAlias entityAlias = entityAliasRef.value();
|
||||
|
||||
//update template
|
||||
ASSERT_TRUE(m_instanceToTemplateInterface->PatchEntityInTemplate(patch, entityAlias, templateId));
|
||||
ASSERT_TRUE(m_instanceToTemplateInterface->PatchEntityInTemplate(patch, entityId));
|
||||
|
||||
//undo change
|
||||
instanceEntityUndo.Undo();
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
|
||||
set(LY_BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
3rdParty::FreeType2
|
||||
3rdParty::freetype
|
||||
)
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#include "EditorPreferencesPageGeneral.h"
|
||||
#include "ViewportManipulatorController.h"
|
||||
#include "LegacyViewportCameraController.h"
|
||||
#include "ModernViewportCameraController.h"
|
||||
|
||||
#include "ViewPane.h"
|
||||
#include "CustomResolutionDlg.h"
|
||||
@@ -92,6 +93,7 @@
|
||||
// Atom
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Public/ViewportContextManager.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
@@ -106,6 +108,10 @@ void StartFixedCursorMode(QObject *viewport);
|
||||
#define RENDER_MESH_TEST_DISTANCE (0.2f)
|
||||
#define CURSOR_FONT_HEIGHT 8.0f
|
||||
|
||||
AZ_CVAR(
|
||||
bool, ed_useNewCameraSystem, false, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"Use the new Editor camera system (the Atom-native Editor viewport (experimental) must also be enabled)");
|
||||
|
||||
namespace AZ::ViewportHelpers
|
||||
{
|
||||
static const char TextCantCreateCameraNoLevel[] = "Cannot create camera when no level is loaded.";
|
||||
@@ -1236,7 +1242,16 @@ void EditorViewportWidget::SetViewportId(int id)
|
||||
viewportContext->ConnectProjectionMatrixChangedHandler(m_cameraProjectionMatrixChangeHandler);
|
||||
|
||||
m_renderViewport->GetControllerList()->Add(AZStd::make_shared<SandboxEditor::ViewportManipulatorController>());
|
||||
m_renderViewport->GetControllerList()->Add(AZStd::make_shared<SandboxEditor::LegacyViewportCameraController>());
|
||||
|
||||
if (ed_useNewCameraSystem)
|
||||
{
|
||||
m_renderViewport->GetControllerList()->Add(AZStd::make_shared<SandboxEditor::ModernViewportCameraController>());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderViewport->GetControllerList()->Add(AZStd::make_shared<SandboxEditor::LegacyViewportCameraController>());
|
||||
}
|
||||
|
||||
UpdateScene();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
*/
|
||||
|
||||
#include "LegacyViewportCameraController.h"
|
||||
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
@@ -73,7 +75,8 @@ AZ::RPI::ViewportContextPtr LegacyViewportCameraControllerInstance::GetViewportC
|
||||
return viewportContextManager->GetViewportContextById(GetViewportId());
|
||||
}
|
||||
|
||||
bool LegacyViewportCameraControllerInstance::HandleMouseMove(const QPoint& currentMousePos, const QPoint& previousMousePos)
|
||||
bool LegacyViewportCameraControllerInstance::HandleMouseMove(
|
||||
const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos)
|
||||
{
|
||||
if (previousMousePos == currentMousePos)
|
||||
{
|
||||
@@ -100,7 +103,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(const QPoint& curre
|
||||
Vec3 ydir = m.GetColumn1().GetNormalized();
|
||||
Vec3 pos = m.GetTranslation();
|
||||
|
||||
const float posDelta = 0.2f * (previousMousePos.y() - currentMousePos.y()) * speedScale;
|
||||
const float posDelta = 0.2f * (previousMousePos.m_y - currentMousePos.m_y) * speedScale;
|
||||
pos = pos - ydir * posDelta;
|
||||
m_orbitDistance = m_orbitDistance + posDelta;
|
||||
m_orbitDistance = fabs(m_orbitDistance);
|
||||
@@ -111,7 +114,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(const QPoint& curre
|
||||
}
|
||||
else if (m_inRotateMode)
|
||||
{
|
||||
Ang3 angles(-currentMousePos.y() + previousMousePos.y(), 0, -currentMousePos.x() + previousMousePos.x());
|
||||
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x);
|
||||
angles = angles * 0.002f * gSettings.cameraRotateSpeed;
|
||||
if (gSettings.invertYRotation)
|
||||
{
|
||||
@@ -143,7 +146,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(const QPoint& curre
|
||||
}
|
||||
|
||||
Vec3 pos = m.GetTranslation();
|
||||
pos += 0.1f * xdir * (currentMousePos.x() - previousMousePos.x()) * speedScale + 0.1f * zdir * (previousMousePos.y() - currentMousePos.y()) * speedScale;
|
||||
pos += 0.1f * xdir * (currentMousePos.m_x - previousMousePos.m_x) * speedScale + 0.1f * zdir * (previousMousePos.m_y - currentMousePos.m_y) * speedScale;
|
||||
m.SetTranslation(pos);
|
||||
|
||||
AZ::Transform transform = viewportContext->GetCameraTransform();
|
||||
@@ -153,7 +156,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(const QPoint& curre
|
||||
}
|
||||
else if (m_inOrbitMode)
|
||||
{
|
||||
Ang3 angles(-currentMousePos.y() + previousMousePos.y(), 0, -currentMousePos.x() + previousMousePos.x());
|
||||
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x);
|
||||
angles = angles * 0.002f * gSettings.cameraRotateSpeed;
|
||||
|
||||
if (gSettings.invertPan)
|
||||
@@ -289,14 +292,13 @@ bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFra
|
||||
|
||||
if (id == AzFramework::InputDeviceMouse::SystemCursorPosition)
|
||||
{
|
||||
QPoint screenPosition = QPoint();
|
||||
bool result = false;
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
|
||||
GetViewportId(),
|
||||
[this, &result](AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequests* mouseRequests)
|
||||
{
|
||||
auto previousMousePosition = mouseRequests->PreviousViewportCursorScreenPosition();
|
||||
if (previousMousePosition.has_value())
|
||||
if (auto previousMousePosition = mouseRequests->PreviousViewportCursorScreenPosition();
|
||||
previousMousePosition.has_value())
|
||||
{
|
||||
result = HandleMouseMove(mouseRequests->ViewportCursorScreenPosition(), previousMousePosition.value());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include <QtCore/qnamespace.h>
|
||||
#include <QPoint>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct ScreenPoint;
|
||||
}
|
||||
|
||||
namespace SandboxEditor
|
||||
{
|
||||
class LegacyViewportCameraControllerInstance final
|
||||
@@ -45,7 +50,7 @@ namespace SandboxEditor
|
||||
|
||||
AZ::RPI::ViewportContextPtr GetViewportContext();
|
||||
|
||||
bool HandleMouseMove(const QPoint& currentMousePos, const QPoint& previousMousePos);
|
||||
bool HandleMouseMove(const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos);
|
||||
bool HandleMouseWheel(float zDelta);
|
||||
bool IsKeyDown(Qt::Key key) const;
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ModernViewportCameraController.h"
|
||||
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
namespace SandboxEditor
|
||||
{
|
||||
static AZ::RPI::ViewportContextPtr RetrieveViewportContext(const AzFramework::ViewportId viewportId)
|
||||
{
|
||||
auto viewportContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
|
||||
if (!viewportContextManager)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto viewportContext = viewportContextManager->GetViewportContextById(viewportId);
|
||||
if (!viewportContext)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return viewportContext;
|
||||
}
|
||||
|
||||
ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance(const AzFramework::ViewportId viewportId)
|
||||
: MultiViewportControllerInstanceInterface(viewportId)
|
||||
{
|
||||
// LYN-2315 TODO - move setup out of constructor, pass cameras in
|
||||
auto firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Right);
|
||||
auto firstPersonPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(AzFramework::LookPan);
|
||||
auto firstPersonTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(AzFramework::LookTranslation);
|
||||
auto firstPersonWheelCamera = AZStd::make_shared<AzFramework::ScrollTranslationCameraInput>();
|
||||
|
||||
auto orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>();
|
||||
auto orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Left);
|
||||
auto orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(AzFramework::OrbitTranslation);
|
||||
auto orbitDollyWheelCamera = AZStd::make_shared<AzFramework::OrbitDollyScrollCameraInput>();
|
||||
auto orbitDollyMoveCamera = AZStd::make_shared<AzFramework::OrbitDollyCursorMoveCameraInput>();
|
||||
auto orbitPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(AzFramework::OrbitPan);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitDollyWheelCamera);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitDollyMoveCamera);
|
||||
orbitCamera->m_orbitCameras.AddCamera(orbitPanCamera);
|
||||
|
||||
m_cameraSystem.m_cameras.AddCamera(firstPersonRotateCamera);
|
||||
m_cameraSystem.m_cameras.AddCamera(firstPersonPanCamera);
|
||||
m_cameraSystem.m_cameras.AddCamera(firstPersonTranslateCamera);
|
||||
m_cameraSystem.m_cameras.AddCamera(firstPersonWheelCamera);
|
||||
m_cameraSystem.m_cameras.AddCamera(orbitCamera);
|
||||
|
||||
if (const auto viewportContext = RetrieveViewportContext(viewportId))
|
||||
{
|
||||
// set position but not orientation
|
||||
m_targetCamera.m_lookAt = viewportContext->GetCameraTransform().GetTranslation();
|
||||
|
||||
// LYN-2315 TODO https://www.geometrictools.com/Documentation/EulerAngles.pdf
|
||||
|
||||
m_camera = m_targetCamera;
|
||||
}
|
||||
}
|
||||
|
||||
bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
AzFramework::WindowSize windowSize;
|
||||
AzFramework::WindowRequestBus::EventResult(
|
||||
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
|
||||
m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel, windowSize));
|
||||
return true; // consume event
|
||||
}
|
||||
|
||||
void ModernViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
|
||||
{
|
||||
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
|
||||
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_smoothProps, event.m_deltaTime.count());
|
||||
|
||||
viewportContext->SetCameraTransform(m_camera.Transform());
|
||||
}
|
||||
}
|
||||
} // namespace SandboxEditor
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 <AzFramework/Viewport/CameraInput.h>
|
||||
#include <AzFramework/Viewport/MultiViewportController.h>
|
||||
|
||||
namespace SandboxEditor
|
||||
{
|
||||
class ModernViewportCameraControllerInstance final : public AzFramework::MultiViewportControllerInstanceInterface
|
||||
{
|
||||
public:
|
||||
explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId);
|
||||
|
||||
// MultiViewportControllerInstanceInterface overrides ...
|
||||
bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
|
||||
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
|
||||
|
||||
private:
|
||||
AzFramework::Camera m_camera;
|
||||
AzFramework::Camera m_targetCamera;
|
||||
AzFramework::SmoothProps m_smoothProps;
|
||||
AzFramework::CameraSystem m_cameraSystem;
|
||||
};
|
||||
|
||||
using ModernViewportCameraController = AzFramework::MultiViewportController<ModernViewportCameraControllerInstance>;
|
||||
} // namespace SandboxEditor
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "ImageTIF.h"
|
||||
|
||||
/// libTiff
|
||||
#include <libtiff/tiffio.h> // TIFF library
|
||||
#include <tiffio.h> // TIFF library
|
||||
|
||||
// Function prototypes
|
||||
static tsize_t libtiffDummyReadProc (thandle_t fd, tdata_t buf, tsize_t size);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzCore/Script/ScriptTimePoint.h>
|
||||
|
||||
#include <QApplication>
|
||||
@@ -99,18 +100,16 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram
|
||||
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
|
||||
if (event.m_priority == ManipulatorPriority)
|
||||
{
|
||||
QPoint screenPosition = QPoint();
|
||||
AzFramework::ScreenPoint screenPosition = AzFramework::ScreenPoint(0, 0);
|
||||
ViewportMouseCursorRequestBus::EventResult(
|
||||
screenPosition, GetViewportId(),
|
||||
&ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition
|
||||
);
|
||||
m_state.m_mousePick.m_screenCoordinates = AzFramework::ScreenPoint{screenPosition.x(), screenPosition.y()};
|
||||
screenPosition, GetViewportId(), &ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition);
|
||||
|
||||
m_state.m_mousePick.m_screenCoordinates = screenPosition;
|
||||
AZStd::optional<ProjectedViewportRay> ray;
|
||||
ViewportInteractionRequestBus::EventResult(
|
||||
ray, GetViewportId(),
|
||||
&ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay,
|
||||
screenPosition
|
||||
);
|
||||
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay,
|
||||
QPoint(screenPosition.m_x, screenPosition.m_y));
|
||||
|
||||
if (ray.has_value())
|
||||
{
|
||||
m_state.m_mousePick.m_rayOrigin = ray.value().origin;
|
||||
|
||||
@@ -996,6 +996,8 @@ set(FILES
|
||||
ViewportManipulatorController.h
|
||||
LegacyViewportCameraController.cpp
|
||||
LegacyViewportCameraController.h
|
||||
ModernViewportCameraController.cpp
|
||||
ModernViewportCameraController.h
|
||||
RenderViewport.cpp
|
||||
RenderViewport.h
|
||||
TopRendererWnd.cpp
|
||||
|
||||
@@ -41,6 +41,65 @@
|
||||
|
||||
#include <AzQtComponents/Utilities/QtWindowUtilities.h>
|
||||
|
||||
// Class to implement the WindowRequestBus::Handler instead of the QViewport class.
|
||||
// This is to bypass a link warning that occurs in unity builds if EditorCommon dll
|
||||
// is linked along with a gem that also implements WindowRequestBus::Handler. The
|
||||
// issue is that QViewport has a dllexport so it causes duplicate code to be linked
|
||||
// in and a warning that there will be two of the same symbol in memory
|
||||
class QViewportRequests
|
||||
: public AzFramework::WindowRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
QViewportRequests(QViewport& viewport)
|
||||
: m_viewport(viewport)
|
||||
{
|
||||
}
|
||||
|
||||
~QViewportRequests() override
|
||||
{
|
||||
AzFramework::WindowRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
// WindowRequestBus::Handler...
|
||||
void SetWindowTitle(const AZStd::string& title) override
|
||||
{
|
||||
m_viewport.SetWindowTitle(title);
|
||||
}
|
||||
|
||||
AzFramework::WindowSize GetClientAreaSize() const override
|
||||
{
|
||||
return m_viewport.GetClientAreaSize();
|
||||
}
|
||||
|
||||
void ResizeClientArea(AzFramework::WindowSize clientAreaSize) override
|
||||
{
|
||||
m_viewport.ResizeClientArea(clientAreaSize);
|
||||
}
|
||||
|
||||
bool GetFullScreenState() const override
|
||||
{
|
||||
return m_viewport.GetFullScreenState();
|
||||
}
|
||||
|
||||
void SetFullScreenState(bool fullScreenState) override
|
||||
{
|
||||
m_viewport.SetFullScreenState(fullScreenState);
|
||||
}
|
||||
|
||||
bool CanToggleFullScreenState() const override
|
||||
{
|
||||
return m_viewport.CanToggleFullScreenState();
|
||||
}
|
||||
|
||||
void ToggleFullScreenState() override
|
||||
{
|
||||
m_viewport.ToggleFullScreenState();
|
||||
}
|
||||
|
||||
private:
|
||||
QViewport& m_viewport;
|
||||
};
|
||||
|
||||
struct QViewport::SPreviousContext
|
||||
{
|
||||
CCamera renderCamera;
|
||||
@@ -188,6 +247,8 @@ QViewport::QViewport(QWidget* parent, StartupMode startupMode)
|
||||
, m_private(new SPrivate())
|
||||
, m_cameraControlMode(CameraControlMode::NONE)
|
||||
{
|
||||
m_viewportRequests = AZStd::make_unique<QViewportRequests>(*this);
|
||||
|
||||
if (startupMode & StartupMode_Immediate)
|
||||
Startup();
|
||||
}
|
||||
@@ -213,6 +274,8 @@ void QViewport::Startup()
|
||||
QViewport::~QViewport()
|
||||
{
|
||||
DestroyRenderContext();
|
||||
|
||||
m_viewportRequests.reset();
|
||||
}
|
||||
|
||||
void QViewport::UpdateBackgroundColor()
|
||||
@@ -316,7 +379,7 @@ bool QViewport::CreateRenderContext()
|
||||
|
||||
if (AZ::Interface<AzFramework::AtomActiveInterface>::Get())
|
||||
{
|
||||
AzFramework::WindowRequestBus::Handler::BusConnect(windowHandle);
|
||||
m_viewportRequests.get()->BusConnect(windowHandle);
|
||||
AzFramework::WindowSystemNotificationBus::Broadcast(&AzFramework::WindowSystemNotificationBus::Handler::OnWindowCreated, windowHandle);
|
||||
|
||||
m_lastHwnd = windowHandle;
|
||||
@@ -346,7 +409,7 @@ void QViewport::DestroyRenderContext()
|
||||
m_renderContextCreated = false;
|
||||
|
||||
AzFramework::WindowNotificationBus::Event(windowHandle, &AzFramework::WindowNotificationBus::Handler::OnWindowClosed);
|
||||
AzFramework::WindowRequestBus::Handler::BusDisconnect();
|
||||
m_viewportRequests.get()->BusDisconnect();
|
||||
m_lastHwnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ struct SMouseEvent;
|
||||
struct SViewportSettings;
|
||||
struct SViewportState;
|
||||
class QElapsedTimer;
|
||||
class QViewportRequests;
|
||||
|
||||
class EDITOR_COMMON_API QViewport;
|
||||
struct SRenderContext
|
||||
@@ -66,7 +67,6 @@ AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
class EDITOR_COMMON_API QViewport
|
||||
: public QWidget
|
||||
, public AzFramework::WindowRequestBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
@@ -107,14 +107,14 @@ public:
|
||||
void SetSize(const QSize& size);
|
||||
void GetImageOffscreen(CImageEx& image, const QSize& customSize);
|
||||
|
||||
// WindowRequestBus::Handler...
|
||||
void SetWindowTitle(const AZStd::string& title) override;
|
||||
AzFramework::WindowSize GetClientAreaSize() const override;
|
||||
void ResizeClientArea(AzFramework::WindowSize clientAreaSize) override;
|
||||
bool GetFullScreenState() const override;
|
||||
void SetFullScreenState(bool fullScreenState) override;
|
||||
bool CanToggleFullScreenState() const override;
|
||||
void ToggleFullScreenState() override;
|
||||
// WindowRequestBus::Handler... (handler moved to cpp to resolve link issues in unity builds)
|
||||
void SetWindowTitle(const AZStd::string& title);
|
||||
AzFramework::WindowSize GetClientAreaSize() const;
|
||||
void ResizeClientArea(AzFramework::WindowSize clientAreaSize);
|
||||
bool GetFullScreenState() const;
|
||||
void SetFullScreenState(bool fullScreenState);
|
||||
bool CanToggleFullScreenState() const;
|
||||
void ToggleFullScreenState();
|
||||
|
||||
public slots:
|
||||
void Update();
|
||||
@@ -197,6 +197,7 @@ private:
|
||||
std::unique_ptr<SViewportSettings> m_settings;
|
||||
std::unique_ptr<SViewportState> m_state;
|
||||
std::vector<QViewportConsumer*> m_consumers;
|
||||
AZStd::unique_ptr<QViewportRequests> m_viewportRequests;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
HWND m_lastHwnd = 0;
|
||||
bool m_resizeWindowEvent = false;
|
||||
|
||||
@@ -170,7 +170,9 @@ bool CCrySimpleJob::ExecuteCommand(const std::string& rCmd, std::string& outErro
|
||||
threadIdStream << threadId;
|
||||
|
||||
// Multiple threads could execute a command, therefore the temporary file has to be unique per thread.
|
||||
std::string stdErrorTempFilename = SEnviropment::Instance().m_TempPath + "stderr_" + threadIdStream.str() + ".log";
|
||||
AZ::IO::Path errorTempFilePath = SEnviropment::Instance().m_TempPath / AZStd::string::format("stderr_%s.log", threadIdStream.str().c_str());
|
||||
std::string stdErrorTempFilename{ errorTempFilePath.c_str(), errorTempFilePath.Native().size() };
|
||||
|
||||
CCrySimpleFileGuard FGTmpOutput(stdErrorTempFilename); // Delete file at the end of this function
|
||||
|
||||
std::string systemCmd = rCmd;
|
||||
|
||||
+2
-2
@@ -105,7 +105,7 @@ namespace ImageProcessingAtom
|
||||
{
|
||||
}
|
||||
|
||||
explicit ColorRGBA16(uint64 a_u)
|
||||
explicit ColorRGBA16(AZ::u64 a_u)
|
||||
: u(a_u)
|
||||
{
|
||||
}
|
||||
@@ -152,7 +152,7 @@ namespace ImageProcessingAtom
|
||||
uint16 b;
|
||||
uint16 a;
|
||||
};
|
||||
uint64 u;
|
||||
AZ::u64 u;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace ImageProcessingAtom
|
||||
srcImage->GetImagePointer(mip, srcMem, srcPitch);
|
||||
|
||||
const pvrtexture::CPVRTextureHeader srcHeader(
|
||||
srcPixelType.PixelTypeID, // uint64 u64PixelFormat,
|
||||
srcPixelType.PixelTypeID, // AZ::u64 u64PixelFormat,
|
||||
width, // uint32 u32Height=1,
|
||||
height, // uint32 u32Width=1,
|
||||
1, // uint32 u32Depth=1,
|
||||
@@ -315,7 +315,7 @@ namespace ImageProcessingAtom
|
||||
|
||||
// Preparing source compressed data
|
||||
const pvrtexture::CPVRTextureHeader compressedHeader(
|
||||
FindPvrPixelFormat(fmtSrc), // uint64 u64PixelFormat,
|
||||
FindPvrPixelFormat(fmtSrc), // AZ::u64 u64PixelFormat,
|
||||
width, // uint32 u32Height=1,
|
||||
height, // uint32 u32Width=1,
|
||||
1, // uint32 u32Depth=1,
|
||||
|
||||
@@ -25,9 +25,5 @@ typedef AZ::s32 int32;
|
||||
typedef AZ::s32 sint32;
|
||||
typedef AZ::u32 uint32;
|
||||
|
||||
typedef AZ::s64 int64;
|
||||
typedef AZ::s64 sint64;
|
||||
typedef AZ::u64 uint64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <libtiff/tiffio.h> // TIFF library
|
||||
#include <tiffio.h> // TIFF library
|
||||
|
||||
namespace ImageProcessingAtom
|
||||
{
|
||||
|
||||
@@ -106,4 +106,4 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
float GetDepth(float2 uv, float2 uv_ddx, float2 uv_ddy)
|
||||
{
|
||||
return SampleDepthOrHeightMap(MaterialSrg::m_depthInverted, MaterialSrg::m_depthMap, MaterialSrg::m_sampler, uv, uv_ddx, uv_ddy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ struct VSOutput
|
||||
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/LightingModel.azsli>
|
||||
#include <Atom/Features/Vertex/VertexHelper.azsli>
|
||||
|
||||
VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
|
||||
{
|
||||
@@ -88,7 +89,7 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
|
||||
OUT.m_detailUv[0] = mul(MaterialSrg::m_detailUvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_detailUv[1] = mul(MaterialSrg::m_detailUvMatrix, float3(IN.m_uv1, 1.0)).xy;
|
||||
|
||||
PbrVsHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
VertexHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -248,7 +249,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
// Convert the angle from [0..1] = [0 .. 180 degrees] to radians [0 .. PI]
|
||||
const float2 anisotropy = float2(MaterialSrg::m_anisotropicAngle * PI, MaterialSrg::m_anisotropicFactor);
|
||||
|
||||
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
|
||||
PbrLightingOutput lightingOutput = PbrLighting(IN,
|
||||
baseColor, metallic, roughness, specularF0Factor,
|
||||
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
|
||||
emissive, occlusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ void GetClearCoatInputs(Texture2D influenceMap, float2 influenceUV, float clearC
|
||||
if (useNormalMap)
|
||||
{
|
||||
float4 sampledValue = normalMap.Sample(mapSampler, normalUV);
|
||||
clearCoatNormal = GetWorldSpaceNormal(sampledValue, normal, tangent, bitangent, uvMatrix, normalStrength);
|
||||
clearCoatNormal = GetWorldSpaceNormal(sampledValue.xy, normal, tangent, bitangent, uvMatrix, normalStrength);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -91,6 +91,7 @@ struct VSOutput
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -125,7 +126,7 @@ VSOutput SkinVS(VSInput IN)
|
||||
OUT.m_blendMask = float4(0,1,0,0);
|
||||
}
|
||||
|
||||
PbrVsHelper(IN, OUT, worldPosition, false);
|
||||
VertexHelper(IN, OUT, worldPosition, false);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
+4
-2
@@ -85,6 +85,7 @@ struct VSOutput
|
||||
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/LightingModel.azsli>
|
||||
#include <Atom/Features/Vertex/VertexHelper.azsli>
|
||||
|
||||
VSOutput ForwardPassVS(VSInput IN)
|
||||
{
|
||||
@@ -109,7 +110,7 @@ VSOutput ForwardPassVS(VSInput IN)
|
||||
// We can skip per-vertex shadow coords when parallax is enabled because we need to calculate per-pixel shadow coords anyway.
|
||||
// We cannot skip shadow coords when o_debugDrawMode is on because some debug draw modes return before parallax.
|
||||
bool skipShadowCoords = o_debugDrawMode == DebugDrawMode::None && o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset;
|
||||
PbrVsHelper(IN, OUT, worldPosition, skipShadowCoords);
|
||||
VertexHelper(IN, OUT, worldPosition, skipShadowCoords);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -346,7 +347,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
|
||||
|
||||
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
|
||||
PbrLightingOutput lightingOutput = PbrLighting(IN,
|
||||
baseColor, metallic, roughness, specularF0Factor,
|
||||
normalWS, tangents[0], bitangents[0], anisotropy,
|
||||
emissive, occlusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
|
||||
|
||||
|
||||
@@ -68,18 +68,19 @@ struct VSOutput
|
||||
|
||||
#include <Atom/Features/PBR/AlphaUtils.azsli>
|
||||
#include <Atom/Features/PBR/LightingModel.azsli>
|
||||
#include <Atom/Features/Vertex/VertexHelper.azsli>
|
||||
|
||||
VSOutput StandardPbr_ForwardPassVS(VSInput IN)
|
||||
{
|
||||
VSOutput OUT;
|
||||
|
||||
|
||||
float3 worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz;
|
||||
|
||||
// By design, only UV0 is allowed to apply transforms.
|
||||
OUT.m_uv[0] = mul(MaterialSrg::m_uvMatrix, float3(IN.m_uv0, 1.0)).xy;
|
||||
OUT.m_uv[1] = IN.m_uv1;
|
||||
|
||||
PbrVsHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
VertexHelper(IN, OUT, worldPosition, o_parallax_feature_enabled && o_parallax_enablePixelDepthOffset);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -126,6 +127,10 @@ 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];
|
||||
@@ -137,7 +142,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
|
||||
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
|
||||
|
||||
float3 normalWS = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal,
|
||||
surface.normal = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal,
|
||||
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], uvMatrix, o_normal_useTexture, MaterialSrg::m_normalFactor);
|
||||
|
||||
// ------- Base Color -------
|
||||
@@ -154,26 +159,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);
|
||||
float specularF0 = GetSpecularInput(MaterialSrg::m_specularF0Map, MaterialSrg::m_sampler, specularUv, MaterialSrg::m_specularF0Factor, o_specularF0_useTexture);
|
||||
|
||||
// ------- Emissive -------
|
||||
surface.SetAlbedoAndSpecularF0(baseColor, specularF0, 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 -------
|
||||
|
||||
float2 occlusionUv = IN.m_uv[MaterialSrg::m_ambientOcclusionMapUvIndex];
|
||||
float occlusion = GetOcclusionInput(MaterialSrg::m_ambientOcclusionMap, MaterialSrg::m_sampler, occlusionUv, MaterialSrg::m_ambientOcclusionFactor, o_ambientOcclusion_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 -------
|
||||
|
||||
@@ -184,31 +182,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)
|
||||
{
|
||||
const float anisotropyAngle = 0.0f;
|
||||
const float anisotropyFactor = 0.0f;
|
||||
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;
|
||||
|
||||
// ------- 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);
|
||||
|
||||
// ------- Occlusion -------
|
||||
|
||||
float2 occlusionUv = IN.m_uv[MaterialSrg::m_ambientOcclusionMapUvIndex];
|
||||
lightingData.occlusion = GetOcclusionInput(MaterialSrg::m_ambientOcclusionMap, MaterialSrg::m_sampler, occlusionUv, MaterialSrg::m_ambientOcclusionFactor, o_ambientOcclusion_useTexture);
|
||||
|
||||
// ------- Clearcoat -------
|
||||
|
||||
float clearCoatFactor = 0.0;
|
||||
float clearCoatRoughness = 0.0;
|
||||
float3 clearCoatNormal = float3(0.0, 0.0, 0.0);
|
||||
// [GFX TODO][ATOM-14603]: Clean up the double uses of these clear coat flags
|
||||
if(o_clearCoat_enabled && o_clearCoat_feature_enabled)
|
||||
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 compensation factor
|
||||
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);
|
||||
|
||||
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
|
||||
normalWS, tangents[0], bitangents[0], anisotropy,
|
||||
emissive, occlusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
|
||||
// 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);
|
||||
|
||||
// ------- Opacity -------
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"CompilerHints" : {
|
||||
"DisableOptimizations" : false
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
@@ -10,29 +11,36 @@ float3 TransmissionKernel(float t, float3 s)
|
||||
return 0.25 * (1.0 / exp(exponent) + 3.0 / exp(exponent / 3.0));
|
||||
}
|
||||
|
||||
float3 GetBackLighting(Surface surface, float3 lightIntensity, float3 dirToCamera, float3 dirToLight, float shadowRatio)
|
||||
float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightIntensity, float3 dirToLight, float shadowRatio)
|
||||
{
|
||||
float3 result = float3(0.0, 0.0, 0.0);
|
||||
float thickness = 0.0;
|
||||
float4 transmissionParams = surface.transmission.transmissionParams;
|
||||
|
||||
switch(o_transmission_mode)
|
||||
{
|
||||
case TransmissionMode::None:
|
||||
break;
|
||||
// Thick object mode, using back lighting approximation proposed by Brisebois B. C. and Bouchard M. 2011
|
||||
// https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/
|
||||
|
||||
case TransmissionMode::ThickObject:
|
||||
thickness = max(shadowRatio, surface.thickness);
|
||||
// (transmittance) * (Lambert's attenuation) * light intensity
|
||||
result = (pow(saturate(dot(dirToCamera, -normalize(dirToLight + surface.normal * surface.transmissionParams.z))), surface.transmissionParams.y) * surface.transmissionParams.w) *
|
||||
(exp(-thickness * surface.transmissionParams.x) * saturate(1.0 - thickness)) *
|
||||
lightIntensity;
|
||||
// Thick object mode, using back lighting approximation proposed by Brisebois B. C. and Bouchard M. 2011
|
||||
// https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/
|
||||
|
||||
{
|
||||
thickness = max(shadowRatio, surface.transmission.thickness);
|
||||
float transmittance = pow( saturate( dot( lightingData.dirToCamera, -normalize( dirToLight + surface.normal * transmissionParams.z ) ) ), transmissionParams.y ) * transmissionParams.w;
|
||||
float lamberAttenuation = exp(-thickness * transmissionParams.x) * saturate(1.0 - thickness);
|
||||
result = transmittance * lamberAttenuation * lightIntensity;
|
||||
}
|
||||
break;
|
||||
// Thin object mode, using thin-film assumption proposed by Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency"
|
||||
// http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf
|
||||
|
||||
case TransmissionMode::ThinObject:
|
||||
result = shadowRatio ? float3(0.0, 0.0, 0.0) : TransmissionKernel(surface.thickness * surface.transmissionParams.w, rcp(surface.transmissionParams.xyz)) *
|
||||
// Thin object mode, using thin-film assumption proposed by Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency"
|
||||
// http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf
|
||||
|
||||
result = shadowRatio ? float3(0.0, 0.0, 0.0) : TransmissionKernel(surface.transmission.thickness * transmissionParams.w, rcp(transmissionParams.xyz)) *
|
||||
saturate(dot(-surface.normal, dirToLight)) * lightIntensity * shadowRatio;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 <viewsrg.srgi>
|
||||
#include <Atom/Features/LightCulling/LightCullingTileIterator.azsli>
|
||||
#include <Atom/Features/PBR/LightingUtils.azsli>
|
||||
|
||||
class LightingData
|
||||
{
|
||||
LightCullingTileIterator tileIterator;
|
||||
|
||||
// Lighting outputs
|
||||
float3 diffuseLighting;
|
||||
float3 specularLighting;
|
||||
float3 translucentBackLighting;
|
||||
|
||||
// Factors for the amount of diffuse and specular lighting applied
|
||||
float3 diffuseResponse;
|
||||
float3 specularResponse;
|
||||
|
||||
// Direction light shadow coordinates
|
||||
float3 shadowCoords[ViewSrg::MaxCascadeCount];
|
||||
|
||||
// Normalized direction from surface to camera
|
||||
float3 dirToCamera;
|
||||
|
||||
// Scaling term to approximate multiscattering contribution in specular BRDF
|
||||
float3 multiScatterCompensation;
|
||||
|
||||
// Lighting emitted from the surface
|
||||
float3 emissiveLighting;
|
||||
|
||||
// BRDF texture values
|
||||
float2 brdf;
|
||||
|
||||
// Normal . View
|
||||
float NdotV;
|
||||
|
||||
// 0 = dark, 1 = light
|
||||
float occlusion;
|
||||
|
||||
void Init(float3 positionWS, float3 normal, float roughnessLinear);
|
||||
void CalculateMultiscatterCompensation(float3 specularF0, bool enabled);
|
||||
void FinalizeLighting(float3 transmissionTint);
|
||||
};
|
||||
|
||||
void LightingData::Init(float3 positionWS, float3 normal, float roughnessLinear)
|
||||
{
|
||||
diffuseLighting = 0;
|
||||
specularLighting = 0;
|
||||
translucentBackLighting = 0;
|
||||
multiScatterCompensation = 1.0f;
|
||||
emissiveLighting = float3(0.0f, 0.0f, 0.0f);
|
||||
occlusion = 1.0f;
|
||||
|
||||
dirToCamera = normalize(ViewSrg::m_worldPosition.xyz - positionWS);
|
||||
|
||||
// sample BRDF map (indexed by smoothness values rather than roughness)
|
||||
NdotV = saturate(dot(normal, dirToCamera));
|
||||
float2 brdfUV = float2(NdotV, (1.0f - roughnessLinear));
|
||||
brdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, brdfUV).rg;
|
||||
}
|
||||
|
||||
void LightingData::CalculateMultiscatterCompensation(float3 specularF0, bool enabled)
|
||||
{
|
||||
multiScatterCompensation = GetMultiScatterCompensation(specularF0, brdf, enabled);
|
||||
}
|
||||
|
||||
void LightingData::FinalizeLighting(float3 transmissionTint)
|
||||
{
|
||||
specularLighting += emissiveLighting;
|
||||
|
||||
// Transmitted light
|
||||
if(o_transmission_mode != TransmissionMode::None)
|
||||
{
|
||||
diffuseLighting += translucentBackLighting * transmissionTint;
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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/StandardSurface.azsli>
|
||||
|
||||
// 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;
|
||||
float4 m_clearCoatNormal;
|
||||
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;
|
||||
lightingOutput.m_albedo.a = lightingData.occlusion;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,17 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
option bool o_specularF0_enableMultiScatterCompensation;
|
||||
option bool o_enableShadows = true;
|
||||
option bool o_enableDirectionalLights = true;
|
||||
option bool o_enablePunctualLights = true;
|
||||
option bool o_enableAreaLights = true;
|
||||
option bool o_enableIBL = true;
|
||||
option bool o_enableSubsurfaceScattering;
|
||||
option bool o_clearCoat_feature_enabled;
|
||||
option enum class TransmissionMode {None, ThickObject, ThinObject} o_transmission_mode;
|
||||
option bool o_meshUseForwardPassIBLSpecular = false;
|
||||
option bool o_materialUseForwardPassIBLSpecular = false;
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
#include <viewsrg.srgi>
|
||||
#include <scenesrg.srgi>
|
||||
@@ -35,26 +25,12 @@ option bool o_materialUseForwardPassIBLSpecular = false;
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
|
||||
|
||||
#include <Atom/Features/PBR/Surface.azsli>
|
||||
#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
|
||||
#include <Atom/Features/PBR/Decals.azsli>
|
||||
#include <Atom/Features/PBR/Lights/DirectionalLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/PointLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/SpotLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/DiskLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/CapsuleLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/PolygonLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/QuadLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/Ibl.azsli>
|
||||
|
||||
/**
|
||||
* The StandardPBR Material Template provides a foundation for creating PBR base materials.
|
||||
* A default StandardPBR base material is provided as well, built on top of this template, and
|
||||
* should suit many needs. Additional base materials can created as needed, using StandardPBR.material
|
||||
* as a reference.
|
||||
*/
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -77,18 +53,10 @@ void PbrVsHelper(in VSInput IN, inout VSOutput OUT, float3 worldPosition, bool s
|
||||
}
|
||||
}
|
||||
|
||||
struct PbrLightingOutput
|
||||
{
|
||||
float4 m_diffuseColor;
|
||||
float4 m_specularColor;
|
||||
float4 m_albedo;
|
||||
float4 m_specularF0;
|
||||
float4 m_normal;
|
||||
float4 m_clearCoatNormal;
|
||||
float3 m_scatterDistance;
|
||||
};
|
||||
|
||||
PbrLightingOutput PbrLighting( in VSOutput IN,
|
||||
// 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,
|
||||
@@ -107,24 +75,43 @@ PbrLightingOutput PbrLighting( in VSOutput IN,
|
||||
float alpha,
|
||||
OpacityMode opacityMode)
|
||||
{
|
||||
static const float3 MaxDielectricSpecularF0 = 0.08f;
|
||||
float3 dirToCamera = normalize(ViewSrg::m_worldPosition.xyz - IN.m_worldPosition);
|
||||
float3 worldPosition = IN.m_worldPosition;
|
||||
float4 position = IN.m_position;
|
||||
float3 shadowCoords[ViewSrg::MaxCascadeCount] = IN.m_shadowCoords;
|
||||
|
||||
// sample BRDF map (indexed by smoothness values rather than roughness)
|
||||
float NdotV = dot(normal, dirToCamera);
|
||||
float2 brdfUV = float2(saturate(NdotV), (1.0f - roughness));
|
||||
float2 brdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, brdfUV).rg;
|
||||
// ______________________________________________________________________________________________
|
||||
// Surface
|
||||
|
||||
// compute albedo and specularF0 based on metalness
|
||||
float3 albedo = (o_enableSubsurfaceScattering) ? baseColor : lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);
|
||||
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);
|
||||
|
||||
// since the left hand side value of this interpolation is achromatic color, this value doesn't convert a color space.
|
||||
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * specularF0Factor;
|
||||
lightingData.emissiveLighting = emissive;
|
||||
lightingData.occlusion = occlusion;
|
||||
|
||||
// because most of metal material theoratically conflicts with subsurface scattering
|
||||
// (electrons hit to a conductor will be either 'absorbed' or reflected hence no chance to transmit),
|
||||
// metallic is disabled if subsurface scattering turned on
|
||||
float3 specularF0 = (o_enableSubsurfaceScattering) ? dielectricSpecularF0 : lerp(dielectricSpecularF0, baseColor, metallic);
|
||||
// Directional light shadow coordinates
|
||||
lightingData.shadowCoords = shadowCoords;
|
||||
|
||||
// manipulate base layer f0 if clear coat is enabled
|
||||
if(o_clearCoat_feature_enabled)
|
||||
@@ -132,140 +119,44 @@ PbrLightingOutput PbrLighting( in VSOutput IN,
|
||||
// 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(specularF0)) / (5.0 - sqrt(specularF0));
|
||||
specularF0 = lerp(specularF0, f0 * f0, clearCoatFactor);
|
||||
float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0));
|
||||
surface.specularF0 = lerp(surface.specularF0, f0 * f0, clearCoatFactor);
|
||||
}
|
||||
|
||||
// compute specular and diffuse response
|
||||
float3 specularResponse = FresnelSchlickWithRoughness(NdotV, specularF0, roughness);
|
||||
float3 diffuseResponse = 1.0 - specularResponse;
|
||||
|
||||
if (o_clearCoat_feature_enabled)
|
||||
// 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
|
||||
diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(NdotV, float3(0.04, 0.04, 0.04), clearCoatRoughness) * clearCoatFactor);
|
||||
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
|
||||
}
|
||||
|
||||
// Set up the surface parameters.
|
||||
Surface surface = (Surface)0.0;
|
||||
surface.position = IN.m_worldPosition.xyz;
|
||||
surface.normal = normal;
|
||||
surface.albedo = albedo;
|
||||
surface.specularF0 = specularF0;
|
||||
surface.multiScatterCompensation = GetMultiScatterCompensation(NdotV, surface.specularF0, brdf, o_specularF0_enableMultiScatterCompensation);
|
||||
// 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
|
||||
surface.roughnessLinear = roughness;
|
||||
surface.thickness = transmissionTintThickness.w;
|
||||
|
||||
// Thick object mode: (attenuation coefficient, power, distortion, scale)
|
||||
// Thin object mode: (float3 scatter distance, scale)
|
||||
surface.transmissionParams = transmissionParams;
|
||||
// Multiscatter compensation factor
|
||||
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
|
||||
|
||||
// Parameters: (clear coat factor, perceptual roughness)
|
||||
surface.clearCoatFactor = clearCoatFactor;
|
||||
surface.clearCoatRoughness = clearCoatRoughness;
|
||||
surface.clearCoatNormal = clearCoatNormal;
|
||||
// ______________________________________________________________________________________________
|
||||
// Lighting
|
||||
|
||||
// Make sure roughnessA is above 0 to avoid precision and divide by zero issues. 0.0005f is sufficient for directional lights since they tend to be quite bright.
|
||||
surface.roughnessA = max(roughness * roughness, 0.0005f);
|
||||
// Apply Decals
|
||||
ApplyDecals(lightingData.tileIterator, surface);
|
||||
|
||||
if (o_enableAnisotropy)
|
||||
// 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)
|
||||
{
|
||||
CalculateSurfaceDirectionalAnisotropicData(surface, anisotropy, vtxTangent, vtxBitangent);
|
||||
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
|
||||
}
|
||||
|
||||
float3 diffuseLighting = 0.0f; // accumulation of diffuse lighting
|
||||
float3 specularLighting = 0.0f; // accumulation of specular lighting
|
||||
float3 translucentBackLighting = 0.0f; // accumulation of transmitted light on the back face of object for back lighting
|
||||
|
||||
LightCullingTileIterator tileIterator;
|
||||
tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
|
||||
|
||||
ApplyDecals(tileIterator, surface);
|
||||
|
||||
if (o_enablePunctualLights)
|
||||
{
|
||||
ApplyPointLights(tileIterator, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplySpotLights(tileIterator, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
}
|
||||
|
||||
if (o_enableAreaLights)
|
||||
{
|
||||
ApplyDiskLights(tileIterator, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyCapsuleLights(tileIterator, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyQuadLights(tileIterator, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyPolygonLights(dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
}
|
||||
|
||||
if (opacityMode == OpacityMode::Blended || opacityMode == OpacityMode::TintedTransparent)
|
||||
{
|
||||
// transparencies currently require IBL in the forward pass
|
||||
float3 iblDiffuse = 0.0f;
|
||||
float3 iblSpecular = 0.0f;
|
||||
if (o_enableIBL)
|
||||
{
|
||||
ApplyIblDiffuse(surface, diffuseResponse, iblDiffuse);
|
||||
ApplyIblSpecular(surface, specularResponse, dirToCamera, brdf, iblSpecular);
|
||||
}
|
||||
|
||||
// Apply ambient occlusion to indirect diffuse
|
||||
iblDiffuse *= occlusion;
|
||||
|
||||
// Adjust IBL lighting by exposure.
|
||||
float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
|
||||
iblDiffuse *= iblExposureFactor;
|
||||
iblSpecular *= iblExposureFactor;
|
||||
diffuseLighting += iblDiffuse;
|
||||
specularLighting += iblSpecular;
|
||||
|
||||
alpha = FresnelSchlickWithRoughness(NdotV, alpha, roughness).x; // Increase opacity at grazing angles.
|
||||
}
|
||||
else if (o_meshUseForwardPassIBLSpecular || o_materialUseForwardPassIBLSpecular)
|
||||
{
|
||||
if (o_enableIBL)
|
||||
{
|
||||
float3 iblSpecular = 0.0f;
|
||||
ApplyIblSpecular(surface, specularResponse, dirToCamera, brdf, iblSpecular);
|
||||
|
||||
float iblExposureFactor = pow(2.0f, SceneSrg::m_iblExposure);
|
||||
specularLighting += (iblSpecular * iblExposureFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Emissive contribution
|
||||
// Emissive light is apply to specular now, as diffuse will be used for subsurface scattering later down the pipeline
|
||||
// We may change this if specular is also used for other processing
|
||||
specularLighting += emissive;
|
||||
|
||||
if (o_enableDirectionalLights)
|
||||
{
|
||||
ApplyDirectionalLights(dirToCamera, surface, IN.m_shadowCoords, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
}
|
||||
|
||||
// Transmitted light
|
||||
if(o_transmission_mode != TransmissionMode::None)
|
||||
{
|
||||
diffuseLighting += translucentBackLighting * transmissionTintThickness.xyz;
|
||||
}
|
||||
|
||||
PbrLightingOutput lightingOutput;
|
||||
|
||||
lightingOutput.m_diffuseColor = float4(diffuseLighting, alpha);
|
||||
lightingOutput.m_specularColor = float4(specularLighting, 1.0);
|
||||
|
||||
// albedo, specularF0, roughness, and normals for later passes (specular IBL, Diffuse GI, SSR, AO, etc)
|
||||
lightingOutput.m_specularF0 = float4(specularF0, roughness);
|
||||
lightingOutput.m_albedo.rgb = surface.albedo * diffuseResponse;
|
||||
lightingOutput.m_albedo.a = occlusion;
|
||||
lightingOutput.m_normal.rgb = EncodeNormalSignedOctahedron(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(clearCoatNormal), o_clearCoat_feature_enabled ? clearCoatFactor : 0.0, clearCoatRoughness);
|
||||
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
|
||||
|
||||
return lightingOutput;
|
||||
}
|
||||
@@ -278,6 +169,7 @@ PbrLightingOutput PbrLighting( in VSOutput IN,
|
||||
//! @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
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
option bool o_specularF0_enableMultiScatterCompensation;
|
||||
option bool o_enableShadows = true;
|
||||
option bool o_enableDirectionalLights = true;
|
||||
option bool o_enablePunctualLights = true;
|
||||
option bool o_enableAreaLights = true;
|
||||
option bool o_enableIBL = true;
|
||||
option bool o_enableSubsurfaceScattering;
|
||||
option bool o_clearCoat_feature_enabled;
|
||||
option enum class TransmissionMode {None, ThickObject, ThinObject} o_transmission_mode;
|
||||
option bool o_meshUseForwardPassIBLSpecular = false;
|
||||
option bool o_materialUseForwardPassIBLSpecular = false;
|
||||
|
||||
@@ -19,7 +19,7 @@ float3 GetCubemapCoords(float3 original)
|
||||
}
|
||||
|
||||
//! Compute multiscatter compensation multiplier
|
||||
float3 GetMultiScatterCompensation(float NdotV, float3 specularF0, float2 brdf, bool enabled)
|
||||
float3 GetMultiScatterCompensation(float3 specularF0, float2 brdf, bool enabled)
|
||||
{
|
||||
if (!enabled)
|
||||
{
|
||||
@@ -66,4 +66,4 @@ float3 ApplyParallaxCorrection(float3 aabbMin, float3 aabbMax, float3 aabbPos, f
|
||||
float distance = min(min(furthestIntersect.x, furthestIntersect.y), furthestIntersect.z);
|
||||
float3 intersectPos = reflectDir * distance + positionWS;
|
||||
return (intersectPos - aabbPos);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-18
@@ -57,7 +57,7 @@ void SampleCapsule(float2 randomPoint, ViewSrg::CapsuleLight light, float capToC
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyCapsuleLight(ViewSrg::CapsuleLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float lightLength = light.m_length;
|
||||
float3 startPoint = light.m_startPoint;
|
||||
@@ -125,10 +125,10 @@ void ApplyCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surface
|
||||
intensity *= INV_PI; // normalize for lambert reflectance.
|
||||
|
||||
float3 lightIntensity = (intensity * radiusAttenuation * ratioVisible) * light.m_rgbIntensityCandelas;
|
||||
diffuseLighting += max(0.0, surface.albedo * lightIntensity);
|
||||
lightingData.diffuseLighting += max(0.0, surface.albedo * lightIntensity);
|
||||
|
||||
// Calculate the reflection of the normal from the view direction
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
|
||||
// Find closest point on light to reflection vector.
|
||||
// See https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
|
||||
@@ -140,7 +140,7 @@ void ApplyCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surface
|
||||
float3 posToLight = closestIntersectionPoint - surface.position;
|
||||
|
||||
// Tranmission contribution
|
||||
translucentBackLighting += GetBackLighting(surface, lightIntensity, dirToCamera, normalize(posToLight), 0.0);
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0);
|
||||
|
||||
// Calculate the offset from the nearest point on the reflection vector to the nearest point on the capsule light
|
||||
float3 posToClosestPointAlongReflection = dot(posToLight, reflectionDir) * reflectionDir;
|
||||
@@ -169,11 +169,11 @@ void ApplyCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surface
|
||||
// Specular contribution
|
||||
lightIntensity = sphereToCapsuleAreaRatio * radiusAttenuation / d2;
|
||||
lightIntensity *= light.m_rgbIntensityCandelas;
|
||||
specularLighting += sphereIntensityNormalization * GetSpecularLighting(surface, lightIntensity, dirToCamera, normalize(posToLight));
|
||||
lightingData.specularLighting += sphereIntensityNormalization * GetSpecularLighting(surface, lightingData, lightIntensity, normalize(posToLight));
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ValidateCapsuleLight(ViewSrg::CapsuleLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
const uint sampleCount = 1024;
|
||||
|
||||
@@ -205,7 +205,7 @@ void ValidateCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surfa
|
||||
float3 direction;
|
||||
float2 randomPoint = GetHammersleyPoint(i, sampleCount);
|
||||
SampleCapsule(randomPoint, light, capToCylinderAreaRatio, localToWorld, position, direction);
|
||||
AddSampleContribution(surface, position, direction, dirToCamera, 0.0, diffuseAcc, specularAcc, translucentAcc);
|
||||
AddSampleContribution(surface, lightingData, position, direction, 0.0, diffuseAcc, specularAcc, translucentAcc);
|
||||
}
|
||||
|
||||
// Lighting value is in Candela, convert to Lumen for total light output of the light
|
||||
@@ -214,28 +214,28 @@ void ValidateCapsuleLight(ViewSrg::CapsuleLight light, float3 dirToCamera, Surfa
|
||||
// equal directions across the hemisphere, so we need to account for that
|
||||
float3 intensity = intensityLumens * INV_PI;
|
||||
|
||||
diffuseLighting += (diffuseAcc / float(sampleCount)) * intensity;
|
||||
translucentBackLighting += (translucentAcc / float(sampleCount)) * intensity;
|
||||
specularLighting += (specularAcc / float(sampleCount)) * intensity;
|
||||
lightingData.diffuseLighting += (diffuseAcc / float(sampleCount)) * intensity;
|
||||
lightingData.translucentBackLighting += (translucentAcc / float(sampleCount)) * intensity;
|
||||
lightingData.specularLighting += (specularAcc / float(sampleCount)) * intensity;
|
||||
}
|
||||
|
||||
void ApplyCapsuleLights(inout LightCullingTileIterator tileIterator, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyCapsuleLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
tileIterator.LoadAdvance();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
while(!tileIterator.IsDone())
|
||||
{
|
||||
uint currLightIndex = tileIterator.GetValue();
|
||||
tileIterator.LoadAdvance();
|
||||
while(!lightingData.tileIterator.IsDone())
|
||||
{
|
||||
uint currLightIndex = lightingData.tileIterator.GetValue();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
ViewSrg::CapsuleLight light = ViewSrg::m_capsuleLights[currLightIndex];
|
||||
if (o_area_light_validation)
|
||||
{
|
||||
ValidateCapsuleLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ValidateCapsuleLight(light, surface, lightingData);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyCapsuleLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyCapsuleLight(light, surface, lightingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-15
@@ -15,13 +15,7 @@
|
||||
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
|
||||
#include <Atom/Features/Shadow/DirectionalLightShadow.azsli>
|
||||
|
||||
void ApplyDirectionalLights(
|
||||
float3 dirToCamera,
|
||||
Surface surface,
|
||||
float3 shadowCoords[ViewSrg::MaxCascadeCount],
|
||||
inout float3 diffuseLighting,
|
||||
inout float3 specularLighting,
|
||||
inout float3 translucentBackLighting)
|
||||
void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
DirectionalLightShadow::DebugInfo debugInfo = {0, false};
|
||||
|
||||
@@ -33,13 +27,13 @@ void ApplyDirectionalLights(
|
||||
{
|
||||
litRatio = DirectionalLightShadow::GetVisibility(
|
||||
shadowIndex,
|
||||
shadowCoords,
|
||||
lightingData.shadowCoords,
|
||||
surface.normal,
|
||||
debugInfo);
|
||||
|
||||
if (o_transmission_mode == TransmissionMode::ThickObject)
|
||||
{
|
||||
backShadowRatio = DirectionalLightShadow::GetThickness(shadowIndex, shadowCoords);
|
||||
backShadowRatio = DirectionalLightShadow::GetThickness(shadowIndex, lightingData.shadowCoords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +44,7 @@ void ApplyDirectionalLights(
|
||||
float3 dirToLight = normalize(-light.m_direction);
|
||||
|
||||
// Adjust the direction of the light based on its angular diameter.
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
float3 lightDirToReflectionDir = reflectionDir - dirToLight;
|
||||
float lightDirToReflectionDirLen = length(lightDirToReflectionDir);
|
||||
lightDirToReflectionDir = lightDirToReflectionDir / lightDirToReflectionDirLen; // normalize the length
|
||||
@@ -72,16 +66,16 @@ void ApplyDirectionalLights(
|
||||
}
|
||||
}
|
||||
|
||||
diffuseLighting += GetDiffuseLighting(surface, light.m_rgbIntensityLux, dirToCamera, dirToLight) * currentLitRatio;
|
||||
specularLighting += GetSpecularLighting(surface, light.m_rgbIntensityLux, dirToCamera, dirToLight) * currentLitRatio;
|
||||
translucentBackLighting += GetBackLighting(surface, light.m_rgbIntensityLux, dirToCamera, dirToLight, currentBackShadowRatio);
|
||||
lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight) * currentLitRatio;
|
||||
lightingData.specularLighting += GetSpecularLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight) * currentLitRatio;
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, light.m_rgbIntensityLux, dirToLight, currentBackShadowRatio);
|
||||
}
|
||||
|
||||
// Add debug coloring for directional light shadow
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
specularLighting = DirectionalLightShadow::AddDebugColoring(
|
||||
specularLighting,
|
||||
lightingData.specularLighting = DirectionalLightShadow::AddDebugColoring(
|
||||
lightingData.specularLighting,
|
||||
ViewSrg::m_shadowIndexDirectionalLight,
|
||||
debugInfo);
|
||||
}
|
||||
|
||||
+17
-17
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
|
||||
|
||||
void ApplyDiskLight(ViewSrg::DiskLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyDiskLight(ViewSrg::DiskLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float3 posToLight = light.m_position - surface.position;
|
||||
float distanceToLight2 = dot(posToLight, posToLight); // light distance squared
|
||||
@@ -64,15 +64,15 @@ void ApplyDiskLight(ViewSrg::DiskLight light, float3 dirToCamera, Surface surfac
|
||||
lightIntensity /= ((light.m_diskRadius / distanceToPlane) + 1.0);
|
||||
|
||||
// Diffuse contribution
|
||||
diffuseLighting += GetDiffuseLighting(surface, lightIntensity, dirToCamera, posToLightDir);
|
||||
lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, posToLightDir);
|
||||
|
||||
// Tranmission contribution
|
||||
translucentBackLighting += GetBackLighting(surface, lightIntensity, dirToCamera, posToLightDir, 0.0);
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, posToLightDir, 0.0);
|
||||
|
||||
// Adjust the light direction for specular based on disk size
|
||||
|
||||
// Calculate the reflection off the normal from the view lightDirection
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
float reflectionDotLight = dot(reflectionDir, -lightDirection);
|
||||
|
||||
// Let 'Intersection' denote the point where the reflection ray intersects the diskLight plane
|
||||
@@ -104,7 +104,7 @@ void ApplyDiskLight(ViewSrg::DiskLight light, float3 dirToCamera, Surface surfac
|
||||
float diskIntensityNormalization = GetIntensityAdjustedByRadiusAndRoughness(surface.roughnessA, light.m_diskRadius, distanceToLight2);
|
||||
|
||||
// Specular contribution
|
||||
specularLighting += diskIntensityNormalization * GetSpecularLighting(surface, lightIntensity, dirToCamera, normalize(posToLight));
|
||||
lightingData.specularLighting += diskIntensityNormalization * GetSpecularLighting(surface, lightingData, lightIntensity, normalize(posToLight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ float3 SampleDisk(float2 randomPoint, ViewSrg::DiskLight light)
|
||||
return outPoint;
|
||||
}
|
||||
|
||||
void ValidateDiskLight(ViewSrg::DiskLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ValidateDiskLight(ViewSrg::DiskLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
const uint sampleCount = 512;
|
||||
|
||||
@@ -147,31 +147,31 @@ void ValidateDiskLight(ViewSrg::DiskLight light, float3 dirToCamera, Surface sur
|
||||
{
|
||||
float2 randomPoint = GetHammersleyPoint(i, sampleCount);
|
||||
float3 samplePoint = SampleDisk(randomPoint, light);
|
||||
AddSampleContribution(surface, samplePoint, light.m_direction, dirToCamera, light.m_bothDirectionsFactor, diffuseAcc, specularAcc, translucentAcc);
|
||||
AddSampleContribution(surface, lightingData, samplePoint, light.m_direction, light.m_bothDirectionsFactor, diffuseAcc, specularAcc, translucentAcc);
|
||||
}
|
||||
|
||||
diffuseLighting += (diffuseAcc / float(sampleCount)) * light.m_rgbIntensityCandelas;
|
||||
specularLighting += (specularAcc / float(sampleCount)) * light.m_rgbIntensityCandelas;
|
||||
lightingData.diffuseLighting += (diffuseAcc / float(sampleCount)) * light.m_rgbIntensityCandelas;
|
||||
lightingData.specularLighting += (specularAcc / float(sampleCount)) * light.m_rgbIntensityCandelas;
|
||||
}
|
||||
|
||||
void ApplyDiskLights(inout LightCullingTileIterator tileIterator, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyDiskLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
tileIterator.LoadAdvance();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
while( !tileIterator.IsDone() )
|
||||
{
|
||||
uint currLightIndex = tileIterator.GetValue();
|
||||
tileIterator.LoadAdvance();
|
||||
while( !lightingData.tileIterator.IsDone() )
|
||||
{
|
||||
uint currLightIndex = lightingData.tileIterator.GetValue();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
ViewSrg::DiskLight light = ViewSrg::m_diskLights[currLightIndex];
|
||||
|
||||
if (o_area_light_validation)
|
||||
{
|
||||
ValidateDiskLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ValidateDiskLight(light, surface, lightingData);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyDiskLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyDiskLight(light, surface, lightingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,25 +12,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
#include <Atom/RPI/Math.azsli>
|
||||
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
|
||||
#include <Atom/Features/PBR/LightingUtils.azsli>
|
||||
|
||||
void ApplyIblDiffuse(Surface surface, float3 diffuseResponse, out float3 outDiffuse)
|
||||
void ApplyIblDiffuse(float3 normal, float3 albedo, float3 diffuseResponse, out float3 outDiffuse)
|
||||
{
|
||||
float3 irradianceDir = MultiplyVectorQuaternion(surface.normal, SceneSrg::m_iblOrientation);
|
||||
float3 irradianceDir = MultiplyVectorQuaternion(normal, SceneSrg::m_iblOrientation);
|
||||
float3 diffuseSample = SceneSrg::m_diffuseEnvMap.Sample(SceneSrg::m_samplerEnv, GetCubemapCoords(irradianceDir)).rgb;
|
||||
|
||||
outDiffuse = diffuseResponse * surface.albedo * diffuseSample;
|
||||
outDiffuse = diffuseResponse * albedo * diffuseSample;
|
||||
}
|
||||
|
||||
void ApplyIblSpecular(Surface surface, float3 specularResponse, float3 dirToCamera, float2 brdf, out float3 outSpecular)
|
||||
void ApplyIblSpecular(float3 position, float3 normal, float3 specularF0, float roughnessLinear, float3 specularResponse, float3 dirToCamera, float2 brdf, out float3 outSpecular)
|
||||
{
|
||||
float3 reflectDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectDir = reflect(-dirToCamera, normal);
|
||||
|
||||
// global
|
||||
outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(surface.roughnessLinear)).rgb;
|
||||
outSpecular *= (surface.specularF0 * brdf.x + brdf.y);
|
||||
outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
|
||||
outSpecular *= (specularF0 * brdf.x + brdf.y);
|
||||
|
||||
// reflection probe
|
||||
if (ObjectSrg::m_reflectionProbeData.m_useReflectionProbe)
|
||||
@@ -38,24 +40,56 @@ void ApplyIblSpecular(Surface surface, float3 specularResponse, float3 dirToCame
|
||||
if (ObjectSrg::m_reflectionProbeData.m_useParallaxCorrection)
|
||||
{
|
||||
reflectDir = ApplyParallaxCorrection(
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMin,
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_aabbPos,
|
||||
surface.position,
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMin,
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_aabbPos,
|
||||
position,
|
||||
reflectDir);
|
||||
}
|
||||
|
||||
float3 probeSpecular = ObjectSrg::m_reflectionProbeCubeMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(surface.roughnessLinear)).rgb;
|
||||
probeSpecular *= (surface.specularF0 * brdf.x + brdf.y);
|
||||
float3 probeSpecular = ObjectSrg::m_reflectionProbeCubeMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
|
||||
probeSpecular *= (specularF0 * brdf.x + brdf.y);
|
||||
|
||||
// compute blend amount based on world position in the reflection probe volume
|
||||
float blendAmount = ComputeLerpBetweenInnerOuterAABBs(
|
||||
ObjectSrg::m_reflectionProbeData.m_innerAabbMin,
|
||||
ObjectSrg::m_reflectionProbeData.m_innerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_aabbPos,
|
||||
surface.position);
|
||||
ObjectSrg::m_reflectionProbeData.m_innerAabbMin,
|
||||
ObjectSrg::m_reflectionProbeData.m_innerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_outerAabbMax,
|
||||
ObjectSrg::m_reflectionProbeData.m_aabbPos,
|
||||
position);
|
||||
|
||||
outSpecular = lerp(outSpecular, probeSpecular, blendAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyIBL(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
|
||||
{
|
||||
// transparencies currently require IBL in the forward pass
|
||||
if (o_enableIBL)
|
||||
{
|
||||
float3 iblDiffuse = 0.0f;
|
||||
float3 iblSpecular = 0.0f;
|
||||
ApplyIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse, iblDiffuse);
|
||||
ApplyIblSpecular(surface.position, surface.normal, surface.specularF0, surface.roughnessLinear, lightingData.specularResponse, lightingData.dirToCamera, lightingData.brdf, iblSpecular);
|
||||
|
||||
// Adjust IBL lighting by exposure.
|
||||
float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
|
||||
lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.occlusion);
|
||||
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
|
||||
}
|
||||
}
|
||||
else if (o_meshUseForwardPassIBLSpecular || o_materialUseForwardPassIBLSpecular)
|
||||
{
|
||||
if (o_enableIBL)
|
||||
{
|
||||
float3 iblSpecular = 0.0f;
|
||||
ApplyIblSpecular(surface.position, surface.normal, surface.specularF0, surface.roughnessLinear, lightingData.specularResponse, lightingData.dirToCamera, lightingData.brdf, iblSpecular);
|
||||
|
||||
float iblExposureFactor = pow(2.0f, SceneSrg::m_iblExposure);
|
||||
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-16
@@ -22,13 +22,13 @@
|
||||
|
||||
option bool o_area_light_validation = false;
|
||||
|
||||
float3 GetDiffuseLighting(Surface surface, float3 lightIntensity, float3 dirToCamera, float3 dirToLight)
|
||||
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, dirToCamera, dirToLight, surface.roughnessLinear);
|
||||
diffuse = NormalizedDisneyDiffuse(surface.albedo, surface.normal, lightingData.dirToCamera, dirToLight, surface.roughnessLinear);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -38,29 +38,41 @@ float3 GetDiffuseLighting(Surface surface, float3 lightIntensity, float3 dirToCa
|
||||
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 + dirToCamera), dirToCamera));
|
||||
diffuse *= 1.0 - (FresnelSchlick(HdotV, 0.04) * surface.clearCoatFactor);
|
||||
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, const float3 lightIntensity, const float3 dirToCamera, const float3 dirToLight)
|
||||
float3 GetSpecularLighting(Surface surface, LightingData lightingData, const float3 lightIntensity, const float3 dirToLight)
|
||||
{
|
||||
float3 specular = SpecularGGX(surface, dirToCamera, 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 + dirToCamera);
|
||||
float NdotH = saturate(dot(surface.clearCoatNormal, halfVector));
|
||||
float NdotL = saturate(dot(surface.clearCoatNormal, dirToLight));
|
||||
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.clearCoatFactor;
|
||||
float clearCoatRoughness = max(surface.clearCoatRoughness * surface.clearCoatRoughness, 0.0005f);
|
||||
float3 clearCoatSpecular = ClearCoatGGX(NdotH, HdotL, NdotL, surface.clearCoatNormal, clearCoatRoughness, clearCoatF );
|
||||
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;
|
||||
}
|
||||
@@ -81,9 +93,9 @@ float GetIntensityAdjustedByRadiusAndRoughness(float roughnessA, float radius, f
|
||||
//! Adds diffuse and specular contribution for a single sample of a lambertian emitter
|
||||
void AddSampleContribution(
|
||||
in Surface surface,
|
||||
in LightingData lightingData,
|
||||
in float3 lightSamplePoint,
|
||||
in float3 lightSampleDirection,
|
||||
in float3 dirToCamera,
|
||||
in float bothDirectionsFactor,
|
||||
inout float3 diffuseAcc,
|
||||
inout float3 specularAcc,
|
||||
@@ -102,7 +114,7 @@ void AddSampleContribution(
|
||||
|
||||
float3 intensityRgb = float3(intensity, intensity, intensity);
|
||||
|
||||
diffuseAcc += GetDiffuseLighting(surface, intensityRgb, dirToCamera, posToLightSampleDir);
|
||||
translucentAcc += GetBackLighting(surface, intensityRgb, dirToCamera, posToLightSampleDir, 0.0);
|
||||
specularAcc += GetSpecularLighting(surface, intensityRgb, dirToCamera, posToLightSampleDir);
|
||||
diffuseAcc += GetDiffuseLighting(surface, lightingData, intensityRgb, posToLightSampleDir);
|
||||
translucentAcc += GetBackLighting(surface, lightingData, intensityRgb, posToLightSampleDir, 0.0);
|
||||
specularAcc += GetSpecularLighting(surface, lightingData, intensityRgb, posToLightSampleDir);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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/Lights/CapsuleLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/DirectionalLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/DiskLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/PointLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/PolygonLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/QuadLight.azsli>
|
||||
#include <Atom/Features/PBR/Lights/SpotLight.azsli>
|
||||
|
||||
void ApplyDirectLighting(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
if (o_enableDirectionalLights)
|
||||
{
|
||||
ApplyDirectionalLights(surface, lightingData);
|
||||
}
|
||||
if (o_enablePunctualLights)
|
||||
{
|
||||
ApplyPointLights(surface, lightingData);
|
||||
ApplySpotLights(surface, lightingData);
|
||||
}
|
||||
if (o_enableAreaLights)
|
||||
{
|
||||
ApplyDiskLights(surface, lightingData);
|
||||
ApplyCapsuleLights(surface, lightingData);
|
||||
ApplyQuadLights(surface, lightingData);
|
||||
ApplyPolygonLights(surface, lightingData);
|
||||
}
|
||||
}
|
||||
@@ -359,7 +359,7 @@ float LtcPolygonEvaluate(in float3 pos, in float3 normal, in float3 dirToView, i
|
||||
|
||||
// Find the previous clip point so it can be used when the polygon goes above the horizon by
|
||||
// searching backwards, updating the endIdx along the way to avoid reprocessing those points later
|
||||
for (endIdx; endIdx > startIdx + 1; --endIdx)
|
||||
for ( ; endIdx > startIdx + 1; --endIdx)
|
||||
{
|
||||
float3 prevPoint = mul(ltcMat, positions[endIdx - 1].xyz - pos);
|
||||
if (prevPoint.z > 0)
|
||||
@@ -392,4 +392,4 @@ float LtcPolygonEvaluate(in float3 pos, in float3 normal, in float3 dirToView, i
|
||||
|
||||
// Note: negated due to winding order
|
||||
return -sum;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-18
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
|
||||
|
||||
void ApplyPointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float3 posToLight = light.m_position - surface.position;
|
||||
float d2 = dot(posToLight, posToLight); // light distance squared
|
||||
@@ -32,15 +32,15 @@ void ApplyPointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface surf
|
||||
float3 lightIntensity = (light.m_rgbIntensityCandelas / d2) * radiusAttenuation;
|
||||
|
||||
// Diffuse contribution
|
||||
diffuseLighting += GetDiffuseLighting(surface, lightIntensity, dirToCamera, normalize(posToLight));
|
||||
lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, normalize(posToLight));
|
||||
|
||||
// Tranmission contribution
|
||||
translucentBackLighting += GetBackLighting(surface, lightIntensity, dirToCamera, normalize(posToLight), 0.0);
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, normalize(posToLight), 0.0);
|
||||
|
||||
// Adjust the light direcion for specular based on bulb size
|
||||
|
||||
// Calculate the reflection off the normal from the view direction
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
|
||||
// Calculate a vector from the reflection vector to the light
|
||||
float3 reflectionPosToLight = posToLight - dot(posToLight, reflectionDir) * reflectionDir;
|
||||
@@ -52,7 +52,7 @@ void ApplyPointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface surf
|
||||
float sphereIntensityNormalization = GetIntensityAdjustedByRadiusAndRoughness(surface.roughnessA, light.m_bulbRadius, d2);
|
||||
|
||||
// Specular contribution
|
||||
specularLighting += sphereIntensityNormalization * GetSpecularLighting(surface, lightIntensity, dirToCamera, normalize(posToLight));
|
||||
lightingData.specularLighting += sphereIntensityNormalization * GetSpecularLighting(surface, lightingData, lightIntensity, normalize(posToLight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ float3 SampleSphere(float2 randomPoint)
|
||||
return float3(sinTheta * cos(angle), sinTheta * sin(angle), cosTheta);
|
||||
}
|
||||
|
||||
void ValidatePointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ValidatePointLight(ViewSrg::PointLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
const uint sampleCount = 512;
|
||||
|
||||
@@ -78,7 +78,7 @@ void ValidatePointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface s
|
||||
float2 randomPoint = GetHammersleyPoint(i, sampleCount);
|
||||
float3 sampleDirection = SampleSphere(randomPoint);
|
||||
float3 samplePoint = light.m_position + sampleDirection * light.m_bulbRadius;
|
||||
AddSampleContribution(surface, samplePoint, sampleDirection, dirToCamera, 0.0, diffuseAcc, specularAcc, translucentAcc);
|
||||
AddSampleContribution(surface, lightingData, samplePoint, sampleDirection, 0.0, diffuseAcc, specularAcc, translucentAcc);
|
||||
}
|
||||
|
||||
// Lighting value is in Candela, convert to Lumen for total light output of the light
|
||||
@@ -87,29 +87,29 @@ void ValidatePointLight(ViewSrg::PointLight light, float3 dirToCamera, Surface s
|
||||
// equal directions across the hemisphere, so we need to account for that
|
||||
float3 intensity = intensityLumens * INV_PI;
|
||||
|
||||
diffuseLighting += (diffuseAcc / float(sampleCount)) * intensity;
|
||||
translucentBackLighting += (translucentAcc / float(sampleCount)) * intensity;
|
||||
specularLighting += (specularAcc / float(sampleCount)) * intensity;
|
||||
lightingData.diffuseLighting += (diffuseAcc / float(sampleCount)) * intensity;
|
||||
lightingData.translucentBackLighting += (translucentAcc / float(sampleCount)) * intensity;
|
||||
lightingData.specularLighting += (specularAcc / float(sampleCount)) * intensity;
|
||||
}
|
||||
|
||||
void ApplyPointLights(inout LightCullingTileIterator tileIterator, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyPointLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
tileIterator.LoadAdvance();
|
||||
|
||||
while( !tileIterator.IsDone() )
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
while( !lightingData.tileIterator.IsDone() )
|
||||
{
|
||||
uint currLightIndex = tileIterator.GetValue();
|
||||
tileIterator.LoadAdvance();
|
||||
uint currLightIndex = lightingData.tileIterator.GetValue();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
ViewSrg::PointLight light = ViewSrg::m_pointLights[currLightIndex];
|
||||
|
||||
if (o_area_light_validation)
|
||||
{
|
||||
ValidatePointLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ValidatePointLight(light, surface, lightingData);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyPointLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyPointLight(light, surface, lightingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -17,7 +17,7 @@
|
||||
#include <Atom/RPI/Math.azsli>
|
||||
|
||||
// Polygon lights using Linearly Transformed Cosines
|
||||
void ApplyPoylgonLight(ViewSrg::PolygonLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyPoylgonLight(ViewSrg::PolygonLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float3 posToLight = light.m_position - surface.position;
|
||||
float distanceToLight2 = dot(posToLight, posToLight); // light distance squared
|
||||
@@ -57,13 +57,13 @@ void ApplyPoylgonLight(ViewSrg::PolygonLight light, float3 dirToCamera, Surface
|
||||
|
||||
// Diffuse
|
||||
static const float3x3 identityMatrix = float3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
|
||||
float diffuse = LtcPolygonEvaluate(surface.position, surface.normal, dirToCamera, identityMatrix, ViewSrg::m_polygonLightPoints, startIndex, endIndex);
|
||||
float diffuse = LtcPolygonEvaluate(surface.position, surface.normal, lightingData.dirToCamera, identityMatrix, ViewSrg::m_polygonLightPoints, startIndex, endIndex);
|
||||
diffuse = doubleSided ? abs(diffuse) : max(0.0, diffuse);
|
||||
|
||||
// Specular
|
||||
float2 ltcCoords = LtcCoords(dot(surface.normal, dirToCamera), surface.roughnessLinear);
|
||||
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
|
||||
float3x3 ltcMat = LtcMatrix(SceneSrg::m_ltcMatrix, ltcCoords);
|
||||
float3 specular = LtcPolygonEvaluate(surface.position, surface.normal, dirToCamera, ltcMat, ViewSrg::m_polygonLightPoints, startIndex, endIndex);
|
||||
float3 specular = LtcPolygonEvaluate(surface.position, surface.normal, lightingData.dirToCamera, ltcMat, ViewSrg::m_polygonLightPoints, startIndex, endIndex);
|
||||
specular = doubleSided ? abs(specular) : max(0.0, specular);
|
||||
|
||||
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
|
||||
@@ -73,16 +73,16 @@ void ApplyPoylgonLight(ViewSrg::PolygonLight light, float3 dirToCamera, Surface
|
||||
// Scale by inverse surface area of hemisphere (1/2pi), attenuation, and light intensity
|
||||
float3 intensity = 0.5 * INV_PI * radiusAttenuation * abs(light.m_rgbIntensityNits);
|
||||
|
||||
diffuseLighting += surface.albedo * diffuse * intensity;
|
||||
specularLighting += surface.specularF0 * specular * intensity;
|
||||
lightingData.diffuseLighting += surface.albedo * diffuse * intensity;
|
||||
lightingData.specularLighting += surface.specularF0 * specular * intensity;
|
||||
}
|
||||
|
||||
void ApplyPolygonLights(float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyPolygonLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
for (uint currLightIndex = 0; currLightIndex < ViewSrg::m_polygonLightCount; ++currLightIndex)
|
||||
{
|
||||
ViewSrg::PolygonLight light = ViewSrg::m_polygonLights[currLightIndex];
|
||||
|
||||
ApplyPoylgonLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyPoylgonLight(light, surface, lightingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+32
-32
@@ -79,7 +79,7 @@ float3 GetSpecularDominantDirection(float3 normal, float3 reflection, float roug
|
||||
}
|
||||
|
||||
// Quad light approximation. Diffuse portion based on https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf Pages 49-50.
|
||||
void ApplyQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyQuadLight(ViewSrg::QuadLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float3 lightDirection = cross(light.m_leftDir, light.m_upDir); // left and up are already normalized.
|
||||
|
||||
@@ -118,12 +118,12 @@ void ApplyQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surfac
|
||||
|
||||
// Diffuse
|
||||
float3x3 identityMatrix = float3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
|
||||
float diffuse = LtcQuadEvaluate(surface.normal, dirToCamera, identityMatrix, p, doubleSided);
|
||||
float diffuse = LtcQuadEvaluate(surface.normal, lightingData.dirToCamera, identityMatrix, p, doubleSided);
|
||||
|
||||
// Specular
|
||||
float2 ltcCoords = LtcCoords(dot(surface.normal, dirToCamera), surface.roughnessLinear);
|
||||
float2 ltcCoords = LtcCoords(dot(surface.normal, lightingData.dirToCamera), surface.roughnessLinear);
|
||||
float3x3 ltcMat = LtcMatrix(SceneSrg::m_ltcMatrix, ltcCoords);
|
||||
float3 specular = LtcQuadEvaluate(surface.normal, dirToCamera, ltcMat, p, doubleSided);
|
||||
float3 specular = LtcQuadEvaluate(surface.normal, lightingData.dirToCamera, ltcMat, p, doubleSided);
|
||||
|
||||
// Apply BRDF scale terms (BRDF magnitude and Schlick Fresnel)
|
||||
float2 schlick = SceneSrg::m_ltcAmplification.Sample(PassSrg::LinearSampler, ltcCoords).xy;
|
||||
@@ -132,8 +132,8 @@ void ApplyQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surfac
|
||||
// Scale by inverse surface area of hemisphere (1/2pi), attenuation, and light intensity
|
||||
float3 intensity = 0.5 * INV_PI * radiusAttenuation * light.m_rgbIntensityNits;
|
||||
|
||||
diffuseLighting += surface.albedo * diffuse * intensity;
|
||||
specularLighting += surface.specularF0 * specular * intensity;
|
||||
lightingData.diffuseLighting += surface.albedo * diffuse * intensity;
|
||||
lightingData.specularLighting += surface.specularF0 * specular * intensity;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -152,29 +152,29 @@ void ApplyQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surfac
|
||||
// Each position contributes 1/5 of the light (4 corners + center)
|
||||
float3 intensity = solidAngle * 0.2 * radiusAttenuation * light.m_rgbIntensityNits;
|
||||
|
||||
diffuseLighting +=
|
||||
lightingData.diffuseLighting +=
|
||||
(
|
||||
GetDiffuseLighting(surface, intensity, dirToCamera, p0) +
|
||||
GetDiffuseLighting(surface, intensity, dirToCamera, p1) +
|
||||
GetDiffuseLighting(surface, intensity, dirToCamera, p2) +
|
||||
GetDiffuseLighting(surface, intensity, dirToCamera, p3) +
|
||||
GetDiffuseLighting(surface, intensity, dirToCamera, dirToLightCenter)
|
||||
GetDiffuseLighting(surface, lightingData, intensity, p0) +
|
||||
GetDiffuseLighting(surface, lightingData, intensity, p1) +
|
||||
GetDiffuseLighting(surface, lightingData, intensity, p2) +
|
||||
GetDiffuseLighting(surface, lightingData, intensity, p3) +
|
||||
GetDiffuseLighting(surface, lightingData, intensity, dirToLightCenter)
|
||||
);
|
||||
|
||||
translucentBackLighting +=
|
||||
lightingData.translucentBackLighting +=
|
||||
(
|
||||
GetBackLighting(surface, intensity, dirToCamera, p0, 0.0) +
|
||||
GetBackLighting(surface, intensity, dirToCamera, p1, 0.0) +
|
||||
GetBackLighting(surface, intensity, dirToCamera, p2, 0.0) +
|
||||
GetBackLighting(surface, intensity, dirToCamera, p3, 0.0) +
|
||||
GetBackLighting(surface, intensity, dirToCamera, dirToLightCenter, 0.0)
|
||||
GetBackLighting(surface, lightingData, intensity, p0, 0.0) +
|
||||
GetBackLighting(surface, lightingData, intensity, p1, 0.0) +
|
||||
GetBackLighting(surface, lightingData, intensity, p2, 0.0) +
|
||||
GetBackLighting(surface, lightingData, intensity, p3, 0.0) +
|
||||
GetBackLighting(surface, lightingData, intensity, dirToLightCenter, 0.0)
|
||||
);
|
||||
|
||||
// Calculate specular by choosing a single representative point on the light's surface based on the reflection ray
|
||||
// Then adjusting it's brightness based on different factors.
|
||||
|
||||
// Calculate the reflection ray from the view direction and surface normal
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
|
||||
// First find the reflection-plane intersection, then find the closest point on the rectangle to that intersection.
|
||||
float2 halfSize = float2(light.m_halfWidth, light.m_halfHeight);
|
||||
@@ -207,7 +207,7 @@ void ApplyQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surfac
|
||||
float distanceAdjustment = 1.0 + sqrt(lightPositionDist2) * (1.0 - rough * rough * solidAngleCoverage);
|
||||
|
||||
float3 specularintensity = light.m_rgbIntensityNits * roughnessAdjustment * distanceAdjustment;
|
||||
specularLighting += GetSpecularLighting(surface, specularintensity, dirToCamera, dirToLight) * radiusAttenuation;
|
||||
lightingData.specularLighting += GetSpecularLighting(surface, lightingData, specularintensity, dirToLight) * radiusAttenuation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,7 @@ float3 SampleRectangle(float2 randomPoint, ViewSrg::QuadLight light)
|
||||
return outPoint;
|
||||
}
|
||||
|
||||
void ValidateQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ValidateQuadLight(ViewSrg::QuadLight light, Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
float3 lightDirection = cross(light.m_leftDir, light.m_upDir); // left and up are already normalized.
|
||||
|
||||
@@ -239,35 +239,35 @@ void ValidateQuadLight(ViewSrg::QuadLight light, float3 dirToCamera, Surface sur
|
||||
{
|
||||
float2 randomPoint = GetHammersleyPoint(i, sampleCount);
|
||||
float3 samplePoint = SampleRectangle(randomPoint, light);
|
||||
AddSampleContribution(surface, samplePoint, lightDirection, dirToCamera, bothDirectionsFactor, diffuseAcc, specularAcc, translucentAcc);
|
||||
AddSampleContribution(surface, lightingData, samplePoint, lightDirection, bothDirectionsFactor, diffuseAcc, specularAcc, translucentAcc);
|
||||
}
|
||||
|
||||
float area = light.m_halfWidth * light.m_halfHeight * 4.0;
|
||||
float3 intensityCandelas = light.m_rgbIntensityNits * area;
|
||||
|
||||
diffuseLighting += (diffuseAcc / float(sampleCount)) * intensityCandelas;
|
||||
translucentBackLighting += (translucentAcc / float(sampleCount)) * intensityCandelas;
|
||||
specularLighting += (specularAcc / float(sampleCount)) * intensityCandelas;
|
||||
lightingData.diffuseLighting += (diffuseAcc / float(sampleCount)) * intensityCandelas;
|
||||
lightingData.translucentBackLighting += (translucentAcc / float(sampleCount)) * intensityCandelas;
|
||||
lightingData.specularLighting += (specularAcc / float(sampleCount)) * intensityCandelas;
|
||||
}
|
||||
|
||||
void ApplyQuadLights(inout LightCullingTileIterator tileIterator, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplyQuadLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
tileIterator.LoadAdvance();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
while( !tileIterator.IsDone() )
|
||||
while( !lightingData.tileIterator.IsDone() )
|
||||
{
|
||||
uint currLightIndex = tileIterator.GetValue();
|
||||
tileIterator.LoadAdvance();
|
||||
uint currLightIndex = lightingData.tileIterator.GetValue();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
ViewSrg::QuadLight light = ViewSrg::m_quadLights[currLightIndex];
|
||||
|
||||
if (o_area_light_validation)
|
||||
{
|
||||
ValidateQuadLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ValidateQuadLight(light, surface, lightingData);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyQuadLight(light, dirToCamera, surface, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplyQuadLight(light, surface, lightingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -15,7 +15,7 @@
|
||||
#include <Atom/Features/PBR/Lights/LightTypesCommon.azsli>
|
||||
#include <Atom/Features/Shadow/SpotLightShadow.azsli>
|
||||
|
||||
void ApplySpotLight(ViewSrg::SpotLight spotLight, float3 dirToCamera, Surface surface, uint lightIndex, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplySpotLight(ViewSrg::SpotLight spotLight, Surface surface, inout LightingData lightingData, uint lightIndex)
|
||||
{
|
||||
float3 posToLight = spotLight.m_position - surface.position;
|
||||
float distanceToLight2 = dot(posToLight, posToLight); // light distance squared
|
||||
@@ -98,11 +98,11 @@ void ApplySpotLight(ViewSrg::SpotLight spotLight, float3 dirToCamera, Surface su
|
||||
lightIntensity *= penumbraMask;
|
||||
}
|
||||
|
||||
diffuseLighting += GetDiffuseLighting(surface, lightIntensity, dirToCamera, dirToLight) * litRatio;
|
||||
translucentBackLighting += GetBackLighting(surface, lightIntensity, dirToCamera, dirToLight, backShadowRatio);
|
||||
lightingData.diffuseLighting += GetDiffuseLighting(surface, lightingData, lightIntensity, dirToLight) * litRatio;
|
||||
lightingData.translucentBackLighting += GetBackLighting(surface, lightingData, lightIntensity, dirToLight, backShadowRatio);
|
||||
|
||||
// Calculate the reflection off the normal from the view lightDirection
|
||||
float3 reflectionDir = reflect(-dirToCamera, surface.normal);
|
||||
float3 reflectionDir = reflect(-lightingData.dirToCamera, surface.normal);
|
||||
float reflectionDotLight = dot(reflectionDir, -spotLight.m_direction);
|
||||
|
||||
// Let 'Intersection' denote the point where the reflection ray intersects the diskLight plane
|
||||
@@ -133,20 +133,20 @@ void ApplySpotLight(ViewSrg::SpotLight spotLight, float3 dirToCamera, Surface su
|
||||
// Adjust the intensity of the light based on the bulb size to conserve energy
|
||||
float diskIntensityNormalization = GetIntensityAdjustedByRadiusAndRoughness(surface.roughnessA, spotLight.m_bulbRadius, distanceToLight2);
|
||||
|
||||
specularLighting += diskIntensityNormalization * GetSpecularLighting(surface, lightIntensity, dirToCamera, normalize(posToLight)) * litRatio;
|
||||
lightingData.specularLighting += diskIntensityNormalization * GetSpecularLighting(surface, lightingData, lightIntensity, normalize(posToLight)) * litRatio;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplySpotLights(inout LightCullingTileIterator tileIterator, float3 dirToCamera, Surface surface, inout float3 diffuseLighting, inout float3 specularLighting, inout float3 translucentBackLighting)
|
||||
void ApplySpotLights(Surface surface, inout LightingData lightingData)
|
||||
{
|
||||
tileIterator.LoadAdvance();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
while( !tileIterator.IsDone() )
|
||||
while( !lightingData.tileIterator.IsDone() )
|
||||
{
|
||||
uint currLightIndex = tileIterator.GetValue();
|
||||
tileIterator.LoadAdvance();
|
||||
uint currLightIndex = lightingData.tileIterator.GetValue();
|
||||
lightingData.tileIterator.LoadAdvance();
|
||||
|
||||
ViewSrg::SpotLight light = ViewSrg::m_spotLights[currLightIndex];
|
||||
ApplySpotLight(light, dirToCamera, surface, currLightIndex, diffuseLighting, specularLighting, translucentBackLighting);
|
||||
ApplySpotLight(light, surface, lightingData, currLightIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,15 @@
|
||||
#include "Ggx.azsli"
|
||||
#include "Fresnel.azsli"
|
||||
|
||||
option bool o_applySpecularAA;
|
||||
option bool o_enableAnisotropy = false;
|
||||
|
||||
// ------- Diffuse Lighting -------
|
||||
|
||||
//! Simple Lambertian BRDF.
|
||||
float3 DiffuseLambertian(float3 albedo, float3 normal, float3 dirToLight)
|
||||
{
|
||||
float NdotL = saturate(dot(normal, dirToLight));
|
||||
return albedo * NdotL * INV_PI;
|
||||
}
|
||||
|
||||
// Normalized Disney diffuse function taken from Frostbite's PBR course notes (page 10):
|
||||
// https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/course-notes-moving-frostbite-to-pbr-v32.pdf
|
||||
@@ -73,29 +80,11 @@ float3 DiffuseTitanfall(float roughnessA, float3 albedo, float3 normal, float3 d
|
||||
return albedo * (single + albedo * multi) * NdotL;
|
||||
}
|
||||
|
||||
//! Simple Lambertian BRDF.
|
||||
float3 DiffuseLambertian(float3 albedo, float3 normal, float3 dirToLight)
|
||||
{
|
||||
float NdotL = saturate(dot(normal, dirToLight));
|
||||
return albedo * NdotL * INV_PI;
|
||||
}
|
||||
|
||||
// Specular Anti-Aliasing technique from this paper:
|
||||
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
|
||||
float ApplySpecularAA(float roughnessA2, float3 normal)
|
||||
{
|
||||
// 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 );
|
||||
return filteredRoughnessA2;
|
||||
}
|
||||
|
||||
|
||||
// ------- Specular Lighting -------
|
||||
|
||||
//! Computes specular response from surfaces with microgeometry. The common form for microfacet
|
||||
//! implementations is D * G * F / (4.0 * NdotL * NdotV), with D G F being swappable terms.
|
||||
@@ -103,53 +92,55 @@ float ApplySpecularAA(float roughnessA2, float3 normal)
|
||||
//!
|
||||
//! @param roughnessA2 alpha roughness ^ 2 (alpha roughness is the unpacked form of artist authored linear roughness and is what is used for lighting calculations)
|
||||
//! @param specularF0 the fresnel f0 spectral value of the surface
|
||||
float3 SpecularGGX( Surface surface, float3 dirToCamera, float3 dirToLight)
|
||||
float3 SpecularGGX( float3 dirToCamera, float3 dirToLight, float3 normal, float3 specularF0, float NdotV, float roughnessA2, float3 multiScatterCompensation )
|
||||
{
|
||||
float3 halfVector = normalize(dirToLight + dirToCamera);
|
||||
float NdotH = saturate(dot(surface.normal, halfVector));
|
||||
float NdotV = saturate(dot(surface.normal, dirToCamera));
|
||||
float NdotL = saturate(dot(surface.normal, dirToLight));
|
||||
float NdotH = saturate(dot(normal, halfVector));
|
||||
float NdotL = saturate(dot(normal, dirToLight));
|
||||
float HdotV = saturate(dot(halfVector, dirToCamera)); // Note that HdotL = HdotV, so we don't need to calculate both
|
||||
|
||||
// Specular Anti-Aliasing correction
|
||||
float roughnessA2 = surface.roughnessA * surface.roughnessA;
|
||||
if(o_applySpecularAA)
|
||||
{
|
||||
roughnessA2 = ApplySpecularAA(roughnessA2, surface.normal);
|
||||
}
|
||||
|
||||
// D, G and F from the lighting equation
|
||||
// Note: the division by (4.0 * NdotL * NdotV) is already factored out in the G function as an optimization
|
||||
float D, G;
|
||||
if (o_enableAnisotropy)
|
||||
{
|
||||
D = NormalDistibution_AnisotropicGGX(
|
||||
NdotH, halfVector, surface.tangentAniso, surface.bitangentAniso, surface.anisotropyFactors );
|
||||
G = ShadowingMasking_AnisotropicSmithGGXCorrelated(
|
||||
surface.tangentAniso, surface.bitangentAniso, dirToCamera, dirToLight, NdotV, NdotL, surface.anisotropyFactors );
|
||||
}
|
||||
else
|
||||
{
|
||||
D = NormalDistributionGGX(NdotH, roughnessA2);
|
||||
G = GeometricShadowingMaskingGGXCorrelated(NdotV, NdotL, roughnessA2);
|
||||
}
|
||||
float3 F = FresnelSchlick(HdotV, surface.specularF0);
|
||||
float D = NormalDistributionGGX(NdotH, roughnessA2);
|
||||
float G = GeometricShadowingMaskingGGXCorrelated(NdotV, NdotL, roughnessA2);
|
||||
float3 F = FresnelSchlick(HdotV, specularF0);
|
||||
|
||||
D = max(0.0, D);
|
||||
G = max(0.0, G);
|
||||
|
||||
// Multiply with multiscattering compensation in order to take account for several specular light bounces.
|
||||
return surface.multiScatterCompensation * (D * G * F * NdotL);
|
||||
return multiScatterCompensation * (D * G * F * NdotL);
|
||||
}
|
||||
|
||||
float3 AnisotropicGGX( float3 dirToCamera, float3 dirToLight, float3 normal, float3 tangent, float3 bitangent, float2 anisotropyFactors,
|
||||
float3 specularF0, float NdotV, float3 multiScatterCompensation )
|
||||
{
|
||||
float3 halfVector = normalize(dirToLight + dirToCamera);
|
||||
float NdotH = saturate(dot(normal, halfVector));
|
||||
float NdotL = saturate(dot(normal, dirToLight));
|
||||
float HdotV = saturate(dot(halfVector, dirToCamera)); // Note that HdotL = HdotV, so we don't need to calculate both
|
||||
|
||||
// D, G and F from the lighting equation
|
||||
// Note: the division by (4.0 * NdotL * NdotV) is already factored out in the G function as an optimization
|
||||
float D = NormalDistibution_AnisotropicGGX( NdotH, halfVector, tangent, bitangent, anisotropyFactors );
|
||||
float G = ShadowingMasking_AnisotropicSmithGGXCorrelated(tangent, bitangent, dirToCamera, dirToLight, NdotV, NdotL, anisotropyFactors);
|
||||
float3 F = FresnelSchlick(HdotV, specularF0);
|
||||
|
||||
D = max(0.0, D);
|
||||
G = max(0.0, G);
|
||||
|
||||
// Multiply with multiscattering compensation in order to take account for several specular light bounces.
|
||||
return multiScatterCompensation * (D * G * F * NdotL);
|
||||
}
|
||||
|
||||
float3 ClearCoatGGX(float NdotH, float HdotL, float NdotL, float3 normal, float roughnessA, float3 F)
|
||||
{
|
||||
// Specular Anti-Aliasing correction
|
||||
float roughnessA2 = roughnessA * roughnessA;
|
||||
if(o_applySpecularAA)
|
||||
{
|
||||
roughnessA2 = ApplySpecularAA(roughnessA2, normal);
|
||||
}
|
||||
//if(o_applySpecularAA)
|
||||
//{
|
||||
// roughnessA2 = ApplySpecularAA(roughnessA2, normal);
|
||||
//}
|
||||
|
||||
float D = NormalDistributionGGX(NdotH, roughnessA2);
|
||||
// Kelemen geometry term : Kelemen. C. and Szirmay-Kalos. L. 2001
|
||||
|
||||
+10
-9
@@ -12,22 +12,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// ------- Fresnel Functions -------
|
||||
|
||||
//! Calculate fresnel reflectance using the Schlick method.
|
||||
//! Reference Naty Hoffman, "Background: Physics and Math of Shading": https://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf Page 16, (6)
|
||||
//!
|
||||
//! @param H half vector (which coincides with the normal vector at microlevel)
|
||||
//! @param V view vector (or light vector; the dot product is the same for both)
|
||||
//! @param F0 the characteristic specular reflectance of the material. Also referred to it as specular color.
|
||||
float3 FresnelSchlick(const float HdotV, const float3 F0)
|
||||
{
|
||||
// At angles where (View = Normal) the dot product HdotV is 1.0
|
||||
return F0 + (float3(1.0, 1.0, 1.0) - F0) * pow(1.0 - HdotV, 5.0);
|
||||
}
|
||||
|
||||
float3 FresnelSchlickF90(const float HdotV, const float3 F0, const float F90)
|
||||
{
|
||||
// At angles where (View = Normal) the dot product HdotV is 1.0
|
||||
return F0 + (F90 - F0) * pow(1.0 - HdotV, 5.0);
|
||||
return F0 + (F90 - F0) * pow(1.0f - HdotV, 5.0f);
|
||||
}
|
||||
|
||||
float3 FresnelSchlick(const float HdotV, const float3 F0)
|
||||
{
|
||||
return FresnelSchlickF90(HdotV, F0, 1.0f);
|
||||
}
|
||||
|
||||
//! Calculate fresnel reflectance using the Schlick method, taking roughness into account.
|
||||
@@ -42,9 +43,9 @@ float3 FresnelSchlickF90(const float HdotV, const float3 F0, const float F90)
|
||||
//! @param roughness roughness value used to further attenuate the fresnel response. This is a "fudge factor" and may or may not be perceptually linear.
|
||||
float3 FresnelSchlickWithRoughness(const float NdotV, const float3 specularF0, const float roughness)
|
||||
{
|
||||
float smoothness = 1.0 - roughness;
|
||||
float smoothness = 1.0f - roughness;
|
||||
float3 F0 = specularF0;
|
||||
|
||||
return F0 + (max(smoothness, F0) - F0) * pow(1.0 - saturate(NdotV), 5.0);
|
||||
return F0 + (max(smoothness, F0) - F0) * pow(1.0 - saturate(NdotV), 5.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,44 @@
|
||||
#include <Atom/RPI/Math.azsli>
|
||||
|
||||
|
||||
//! Distribution function (D) for the anisotropic GGX
|
||||
// ------- GGX -------
|
||||
|
||||
//! (D) Normal Distribution function for GGX
|
||||
//! Provides statistical distribution of microfacet normals M around the macrosurface normal N.
|
||||
//!
|
||||
//! @param H potential microfacet normal, usually the half-vector between the light and the camera
|
||||
//! @param N macrosurface normal
|
||||
//! @param roughnessA2 alpha roughness ^ 2 (alpha roughness is the unpacked form of artist authored linear roughness and is what is used for lighting calculations)
|
||||
//! @return factor for how much of the macrosurface has normals in the direction M. The value non-negative, but it's not normalized, so values are not restricted to [0, 1].
|
||||
float NormalDistributionGGX(const float NdotH, const float roughnessA2)
|
||||
{
|
||||
// Walter equation 33, simplified given that the positive characteristic function is handled elsewhere
|
||||
float b = (NdotH * roughnessA2 - NdotH) * NdotH + 1.0;
|
||||
return roughnessA2 / (PI * b * b);
|
||||
}
|
||||
|
||||
//! (G) Geometric Shadowing and Masking Distribution function for GGX
|
||||
//! Variant with height correlated Smith
|
||||
//!
|
||||
//! @param N macrosurface normal
|
||||
//! @param V direction to the camera
|
||||
//! @param L direction to the light
|
||||
//! @param roughnessA2 alpha roughness ^ 2 (alpha roughness is the unpacked form of artist authored linear roughness and is what is used for lighting calculations)
|
||||
//! @return probability that V and L are not masked.
|
||||
float GeometricShadowingMaskingGGXCorrelated(const float NdotV, const float NdotL, const float roughnessA2)
|
||||
{
|
||||
// See Frostbite PBR guide (page 12)
|
||||
// https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/course-notes-moving-frostbite-to-pbr-v32.pdf
|
||||
float ggxV = NdotL * sqrt((-NdotV * roughnessA2 + NdotV) * NdotV + roughnessA2);
|
||||
float ggxL = NdotV * sqrt((-NdotL * roughnessA2 + NdotL) * NdotL + roughnessA2);
|
||||
return 0.5f / max(ggxV + ggxL, GGX_EPSILON);
|
||||
}
|
||||
|
||||
|
||||
// ------- Anisotropic GGX -------
|
||||
|
||||
//! (D) Normal Distribution function for anisotropic GGX
|
||||
//!
|
||||
//! @param h - half vector viewer to the light, used to approximate the reflection probability for a microfacet normal at this angle
|
||||
//! @param t - rotated surface tangent for calculating anisotropic response
|
||||
//! @param b - rotated surface bitangent for calculating anisotropic response
|
||||
@@ -46,7 +83,7 @@ float NormalDistibution_AnisotropicGGX( float NdotH, const float3 h, const float
|
||||
return a2 * w2 * w2 * (1.0 / PI);
|
||||
}
|
||||
|
||||
//! Geometric shadowing and masking distribution function (G) for the anisotropic GGX
|
||||
//! (G) Geometric shadowing and masking distribution function for anisotropic GGX
|
||||
//! @param t - rotated surface tangent for calculating anisotropic response
|
||||
//! @param b - rotated surface bitangent for calculating anisotropic response
|
||||
//! @param anisotropyFactors - anisotropic tangent and bitangent factor
|
||||
@@ -66,35 +103,8 @@ float ShadowingMasking_AnisotropicSmithGGXCorrelated(
|
||||
return min(v, FLOAT_16_MAX);
|
||||
}
|
||||
|
||||
//! GGX normal distribution function.
|
||||
//! Provides statistical distribution of microfacet normals M around the macrosurface normal N.
|
||||
//!
|
||||
//! @param H potential microfacet normal, usually the half-vector between the light and the camera
|
||||
//! @param N macrosurface normal
|
||||
//! @param roughnessA2 alpha roughness ^ 2 (alpha roughness is the unpacked form of artist authored linear roughness and is what is used for lighting calculations)
|
||||
//! @return factor for how much of the macrosurface has normals in the direction M. The value non-negative, but it's not normalized, so values are not restricted to [0, 1].
|
||||
float NormalDistributionGGX(const float NdotH, const float roughnessA2)
|
||||
{
|
||||
// Walter equation 33, simplified given that the positive characteristic function is handled elsewhere
|
||||
float b = (NdotH * roughnessA2 - NdotH) * NdotH + 1.0;
|
||||
return roughnessA2 / (PI * b * b);
|
||||
}
|
||||
|
||||
//! GGX geometry shadowing/masking function, using the height correlated Smith
|
||||
//!
|
||||
//! @param N macrosurface normal
|
||||
//! @param V direction to the camera
|
||||
//! @param L direction to the light
|
||||
//! @param roughnessA2 alpha roughness ^ 2 (alpha roughness is the unpacked form of artist authored linear roughness and is what is used for lighting calculations)
|
||||
//! @return probability that V and L are not masked.
|
||||
float GeometricShadowingMaskingGGXCorrelated(const float NdotV, const float NdotL, const float roughnessA2)
|
||||
{
|
||||
// See Frostbite PBR guide (page 12)
|
||||
// https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/course-notes-moving-frostbite-to-pbr-v32.pdf
|
||||
float ggxV = NdotL * sqrt((-NdotV * roughnessA2 + NdotV) * NdotV + roughnessA2);
|
||||
float ggxL = NdotV * sqrt((-NdotL * roughnessA2 + NdotL) * NdotL + roughnessA2);
|
||||
return 0.5f / max(ggxV + ggxL, GGX_EPSILON);
|
||||
}
|
||||
// ------- Importance Sampling -------
|
||||
|
||||
//! Importance-sample a microgeometry normal using GGX distribution.
|
||||
//!
|
||||
|
||||
@@ -12,57 +12,57 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
// //! 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);
|
||||
// }
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
option bool o_enableAnisotropy = false;
|
||||
|
||||
// ------- Surface Data -------
|
||||
|
||||
class AnisotropicSurfaceData
|
||||
{
|
||||
float3 tangent; //!< surface space tangent for anisotropic use
|
||||
float3 bitangent; //!< surface space bitangent for anisotropic use
|
||||
float2 anisotropyFactors; //!< anisotory factors along the tangent and the bitangent directions
|
||||
|
||||
void Init(float3 normal, float3 vtxTangent, float3 vtxBitangent, float anisotropyAngle, float anisotropyFactor, float roughnessA);
|
||||
};
|
||||
|
||||
// ------- Functions -------
|
||||
|
||||
//! 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 unless rotated back.
|
||||
void AnisotropicSurfaceData::Init(float3 normal, float3 vtxTangent, float3 vtxBitangent, float anisotropyAngle, float anisotropyFactor, float roughnessA)
|
||||
{
|
||||
anisotropyFactors = max( 0.01,
|
||||
float2( roughnessA * (1.0 + anisotropyFactor),
|
||||
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
|
||||
bitangent = normalize(cross(normal, vtxTangent));
|
||||
tangent = cross(bitangent, normal);
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
option bool o_applySpecularAA;
|
||||
|
||||
// ------- Constants -------
|
||||
|
||||
// For artists workflows, specular F0 for dialectric (non-metal) materials is exposed as a 0-1 scale
|
||||
// However the specular F0 for dialectrics is much lower than metals, so we expose this scaling factor here
|
||||
static const float3 MaxDielectricSpecularF0 = 0.08f;
|
||||
|
||||
// Make sure roughnessA is above 0 to avoid precision and divide by zero issues.
|
||||
// 0.0005f is sufficient for directional lights since they tend to be quite bright.
|
||||
static const float MinRoughnessA = 0.0005f;
|
||||
|
||||
// ------- Surface Data -------
|
||||
|
||||
class 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 inSpecularF0, float metallic);
|
||||
};
|
||||
|
||||
// ------- Functions -------
|
||||
|
||||
// Specular Anti-Aliasing technique from this paper:
|
||||
// http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf
|
||||
void BasePbrSurfaceData::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 BasePbrSurfaceData::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 BasePbrSurfaceData::SetAlbedoAndSpecularF0(float3 baseColor, float inSpecularF0, float metallic)
|
||||
{
|
||||
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * inSpecularF0;
|
||||
|
||||
// Compute albedo and specularF0 based on metalness
|
||||
albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);
|
||||
specularF0 = lerp(dielectricSpecularF0, baseColor, metallic);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
BasePbrSurfaceData pbr;
|
||||
//AnisotropicSurfaceData anisotropy;
|
||||
TransmissionSurfaceData transmission;
|
||||
};
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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 //: BasePbrSurfaceData
|
||||
{
|
||||
//BasePbrSurfaceData pbr;
|
||||
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 inSpecularF0, 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 inSpecularF0, float metallic)
|
||||
{
|
||||
float3 dielectricSpecularF0 = MaxDielectricSpecularF0 * inSpecularF0;
|
||||
|
||||
// Compute albedo and specularF0 based on metalness
|
||||
albedo = lerp(baseColor, float3(0.0f, 0.0f, 0.0f), metallic);
|
||||
specularF0 = lerp(dielectricSpecularF0, baseColor, metallic);
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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)
|
||||
};
|
||||
+1
-1
@@ -152,4 +152,4 @@ float SampleShadowMapBicubic_16Tap(SampleShadowMapBicubicParameters param)
|
||||
|
||||
shadow /= 2704;
|
||||
return shadow * shadow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ ShaderResourceGroupSemantic SRG_RayTracingGlobal
|
||||
ShaderResourceGroupSemantic SRG_RayTracingScene
|
||||
{
|
||||
FrequencyId = 1;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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: VSInput, VSOutput, ObjectSrg must be defined before including this file.
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
// Options
|
||||
#include <Atom/Features/PBR/LightingOptions.azsli>
|
||||
|
||||
// Shader Resource Groups
|
||||
#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>
|
||||
#include <Atom/RPI/TangentSpace.azsli>
|
||||
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@
|
||||
"Depth" : { "Enable" : false }
|
||||
},
|
||||
|
||||
"CompilerVersion" : "1.0",
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
"Depth" : { "Enable" : false }
|
||||
},
|
||||
|
||||
"CompilerVersion" : "1.0",
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
|
||||
@@ -102,7 +102,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
|
||||
float NdotV = saturate(dot(normal, dirToCamera));
|
||||
NdotV = max(NdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
|
||||
float2 brdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(roughness, NdotV)).rg;
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(NdotV, specularF0, brdf, multiScatterCompensationEnabled);
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(specularF0, brdf, multiScatterCompensationEnabled);
|
||||
float3 specular = blendWeight * globalSpecular * multiScatterCompensation * (specularF0 * brdf.x + brdf.y);
|
||||
|
||||
float4 encodedClearCoatNormal = PassSrg::m_clearCoatNormal.Load(IN.m_position.xy, sampleIndex);
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ PSOutput MainPS(VSOutput IN)
|
||||
float NdotV = saturate(dot(normal, dirToCamera));
|
||||
NdotV = max(NdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
|
||||
float2 brdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(roughness, NdotV)).rg;
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(NdotV, specularF0, brdf, multiScatterCompensationEnabled);
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(specularF0, brdf, multiScatterCompensationEnabled);
|
||||
float3 specular = blendWeight * globalSpecular * multiScatterCompensation * (specularF0 * brdf.x + brdf.y);
|
||||
|
||||
float4 encodedClearCoatNormal = PassSrg::m_clearCoatNormal.Load(int3(IN.m_position.xy, 0));
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ bool ComputeProbeSpecular(float2 screenCoords, float3 positionWS, float3 aabbMin
|
||||
float3 probeSpecular = ObjectSrg::m_reflectionCubeMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(localReflectDir), GetRoughnessMip(roughness)).rgb;
|
||||
|
||||
// compute final specular amount
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(NdotV, specularF0, brdf, multiScatterCompensationEnabled);
|
||||
float3 multiScatterCompensation = GetMultiScatterCompensation(specularF0, brdf, multiScatterCompensationEnabled);
|
||||
specular = probeSpecular * multiScatterCompensation * (specularF0.xyz * brdf.x + brdf.y);
|
||||
|
||||
// compute clear coat specular amount
|
||||
|
||||
@@ -23,6 +23,11 @@ set(FILES
|
||||
Materials/Types/EnhancedPBR_ForwardPass_EDS.shader
|
||||
Materials/Types/EnhancedPBR_Shadowmap_WithPS.azsl
|
||||
Materials/Types/EnhancedPBR_Shadowmap_WithPS.shader
|
||||
Materials/Types/Skin.azsl
|
||||
Materials/Types/Skin.materialtype
|
||||
Materials/Types/Skin.shader
|
||||
Materials/Types/Skin_Common.azsli
|
||||
Materials/Types/Skin_WrinkleMaps.lua
|
||||
Materials/Types/StandardMultilayerPBR.materialtype
|
||||
Materials/Types/StandardMultilayerPBR_ClearCoatEnableFeature.lua
|
||||
Materials/Types/StandardMultilayerPBR_Common.azsli
|
||||
@@ -57,6 +62,7 @@ set(FILES
|
||||
Materials/Types/MaterialInputs/AlphaInput.azsli
|
||||
Materials/Types/MaterialInputs/BaseColorInput.azsli
|
||||
Materials/Types/MaterialInputs/ClearCoatInput.azsli
|
||||
Materials/Types/MaterialInputs/DetailMapsCommonFunctor.lua
|
||||
Materials/Types/MaterialInputs/DetailMapsInput.azsli
|
||||
Materials/Types/MaterialInputs/EmissiveInput.azsli
|
||||
Materials/Types/MaterialInputs/MetallicInput.azsli
|
||||
@@ -106,6 +112,7 @@ set(FILES
|
||||
Passes/DepthUpsample.pass
|
||||
Passes/DiffuseComposite.pass
|
||||
Passes/DiffuseGlobalFullscreen.pass
|
||||
Passes/DiffuseGlobalFullscreen_nomsaa.pass
|
||||
Passes/DiffuseGlobalIllumination.pass
|
||||
Passes/DiffuseProbeGridBlendDistance.pass
|
||||
Passes/DiffuseProbeGridBlendIrradiance.pass
|
||||
@@ -162,6 +169,7 @@ set(FILES
|
||||
Passes/ReflectionComposite.pass
|
||||
Passes/ReflectionCopyFrameBuffer.pass
|
||||
Passes/ReflectionGlobalFullscreen.pass
|
||||
Passes/ReflectionGlobalFullscreen_nomsaa.pass
|
||||
Passes/ReflectionProbeBlendWeight.pass
|
||||
Passes/ReflectionProbeRenderInner.pass
|
||||
Passes/ReflectionProbeRenderOuter.pass
|
||||
@@ -173,6 +181,7 @@ set(FILES
|
||||
Passes/ReflectionScreenSpaceBlurVertical.pass
|
||||
Passes/ReflectionScreenSpaceComposite.pass
|
||||
Passes/ReflectionScreenSpaceTrace.pass
|
||||
Passes/Reflections_nomsaa.pass
|
||||
Passes/ShadowParent.pass
|
||||
Passes/Skinning.pass
|
||||
Passes/SkyBox.pass
|
||||
@@ -191,6 +200,8 @@ set(FILES
|
||||
Passes/TransparentParent.pass
|
||||
Passes/UI.pass
|
||||
Passes/UIParent.pass
|
||||
Scripts/material_property_overrides_demo.lua
|
||||
ShaderLib/Atom/Features/BlendUtility.azsli
|
||||
ShaderLib/Atom/Features/IndirectRendering.azsli
|
||||
ShaderLib/Atom/Features/MatrixUtility.azsli
|
||||
ShaderLib/Atom/Features/ParallaxMapping.azsli
|
||||
@@ -212,6 +223,7 @@ set(FILES
|
||||
ShaderLib/Atom/Features/Math/Filter.azsli
|
||||
ShaderLib/Atom/Features/Math/FilterPassSrg.azsli
|
||||
ShaderLib/Atom/Features/Math/IntersectionTests.azsli
|
||||
ShaderLib/Atom/Features/MorphTargets/MorphTargetCompression.azsli
|
||||
ShaderLib/Atom/Features/PBR/AlphaUtils.azsli
|
||||
ShaderLib/Atom/Features/PBR/BackLighting.azsli
|
||||
ShaderLib/Atom/Features/PBR/Decals.azsli
|
||||
@@ -220,21 +232,33 @@ set(FILES
|
||||
ShaderLib/Atom/Features/PBR/ForwardPassSrg.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/LightingData.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lighting/StandardLighting.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/CapsuleLight.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/Lights.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/LightTypesCommon.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lights/Ltc.azsli
|
||||
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/SpotLight.azsli
|
||||
ShaderLib/Atom/Features/PBR/Microfacet/Brdf.azsli
|
||||
ShaderLib/Atom/Features/PBR/Microfacet/Fresnel.azsli
|
||||
ShaderLib/Atom/Features/PBR/Microfacet/Ggx.azsli
|
||||
ShaderLib/Atom/Features/PBR/Surfaces/AnisotropicSurfaceData.azsli
|
||||
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/StandardSurface.azsli
|
||||
ShaderLib/Atom/Features/PBR/Surfaces/TransmissionSurfaceData.azsli
|
||||
ShaderLib/Atom/Features/PostProcessing/Aces.azsli
|
||||
ShaderLib/Atom/Features/PostProcessing/AcesColorSpaceConversion.azsli
|
||||
ShaderLib/Atom/Features/PostProcessing/FullscreenPixelInfo.azsli
|
||||
@@ -245,6 +269,7 @@ set(FILES
|
||||
ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli
|
||||
ShaderLib/Atom/Features/PostProcessing/PostProcessUtil.azsli
|
||||
ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli
|
||||
ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli
|
||||
ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
|
||||
ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli
|
||||
ShaderLib/Atom/Features/Shadow/Shadow.azsli
|
||||
@@ -279,10 +304,16 @@ set(FILES
|
||||
Shaders/Depth/DepthPassTransparentMin.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseComposite.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseComposite_nomsaa.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen_nomsaa.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseGlobalFullscreen_nomsaa.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.shader
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.azsl
|
||||
Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample_nomsaa.shader
|
||||
Shaders/ImGui/ImGui.azsl
|
||||
Shaders/ImGui/ImGui.shader
|
||||
Shaders/LightCulling/LightCulling.azsl
|
||||
@@ -398,8 +429,12 @@ set(FILES
|
||||
Shaders/Reflections/ReflectionCommon.azsli
|
||||
Shaders/Reflections/ReflectionComposite.azsl
|
||||
Shaders/Reflections/ReflectionComposite.shader
|
||||
Shaders/Reflections/ReflectionComposite_nomsaa.azsl
|
||||
Shaders/Reflections/ReflectionComposite_nomsaa.shader
|
||||
Shaders/Reflections/ReflectionGlobalFullscreen.azsl
|
||||
Shaders/Reflections/ReflectionGlobalFullscreen.shader
|
||||
Shaders/Reflections/ReflectionGlobalFullscreen_nomsaa.azsl
|
||||
Shaders/Reflections/ReflectionGlobalFullscreen_nomsaa.shader
|
||||
Shaders/Reflections/ReflectionProbeBlendWeight.azsl
|
||||
Shaders/Reflections/ReflectionProbeBlendWeight.shader
|
||||
Shaders/Reflections/ReflectionProbeRenderCommon.azsli
|
||||
|
||||
@@ -106,7 +106,7 @@ PixelOutput MainPS(VertexOutput input)
|
||||
if (o_useNormalMap)
|
||||
{
|
||||
float4 sampledValue = MaterialSrg::m_normalMap.Sample(MaterialSrg::m_sampler, input.m_uv);
|
||||
normal = GetWorldSpaceNormal(sampledValue, input.m_normal, input.m_tangent, input.m_bitangent);
|
||||
normal = GetWorldSpaceNormal(sampledValue.xy, input.m_normal, input.m_tangent, input.m_bitangent);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -224,4 +224,4 @@ float NextRandomFloatUniform(inout uint seed)
|
||||
{
|
||||
seed = Xorshift(seed);
|
||||
return (float)seed / 4294967295.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,31 +138,14 @@ namespace AZ
|
||||
|
||||
AZStd::array_view<float> ModelKdTree::GetPositionsBuffer(const ModelLodAsset::Mesh& mesh)
|
||||
{
|
||||
const BufferAssetView* positionBufferAssetView = mesh.GetSemanticBufferAssetView(AZ::Name{"POSITION"});
|
||||
if (positionBufferAssetView)
|
||||
{
|
||||
const AZStd::array_view<uint8_t> positionRawBuffer = positionBufferAssetView->GetBufferAsset()->GetBuffer();
|
||||
const auto size = positionBufferAssetView->GetBufferViewDescriptor().m_elementSize;
|
||||
return {
|
||||
reinterpret_cast<const float*>(positionRawBuffer.data() + positionBufferAssetView->GetBufferViewDescriptor().m_elementOffset * size),
|
||||
positionBufferAssetView->GetBufferViewDescriptor().m_elementCount * size / sizeof(float)
|
||||
};
|
||||
}
|
||||
|
||||
AZ_Warning("ModelKdTree", false, "Could not find position buffers in a mesh");
|
||||
return {};
|
||||
AZStd::array_view<float> positionBuffer = mesh.GetSemanticBufferTyped<float>(AZ::Name{"POSITION"});
|
||||
AZ_Warning("ModelKdTree", !positionBuffer.empty(), "Could not find position buffers in a mesh");
|
||||
return positionBuffer;
|
||||
}
|
||||
|
||||
AZStd::array_view<ModelKdTree::TriangleIndices> ModelKdTree::GetIndexBuffer(const ModelLodAsset::Mesh& mesh)
|
||||
{
|
||||
const BufferAssetView& indexBufferAssetView = mesh.GetIndexBufferAssetView();
|
||||
const AZStd::array_view<uint8_t> indexRawBuffer = indexBufferAssetView.GetBufferAsset()->GetBuffer();
|
||||
const auto size = indexBufferAssetView.GetBufferViewDescriptor().m_elementSize;
|
||||
static_assert(sizeof(TriangleIndices) == 3 * sizeof(uint32_t));
|
||||
return {
|
||||
reinterpret_cast<const TriangleIndices*>(indexRawBuffer.data() + indexBufferAssetView.GetBufferViewDescriptor().m_elementOffset * size),
|
||||
indexBufferAssetView.GetBufferViewDescriptor().m_elementCount * size / sizeof(TriangleIndices)
|
||||
};
|
||||
return mesh.GetIndexBufferTyped<ModelKdTree::TriangleIndices>();
|
||||
}
|
||||
|
||||
void ModelKdTree::BuildRecursively(ModelKdTreeNode* pNode, const AZ::Aabb& boundbox, AZStd::vector<ObjectIdTriangleIndices>& indices)
|
||||
|
||||
@@ -39,6 +39,7 @@ struct VSOutput
|
||||
};
|
||||
|
||||
#include <Atom/Features/PBR/LightingModel.azsli>
|
||||
#include <Atom/Features/Vertex/VertexHelper.azsli>
|
||||
|
||||
VSOutput AutoBrick_ForwardPassVS(VSInput IN)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ VSOutput AutoBrick_ForwardPassVS(VSInput IN)
|
||||
|
||||
OUT.m_uv = IN.m_uv;
|
||||
|
||||
PbrVsHelper(IN, OUT, worldPosition);
|
||||
VertexHelper(IN, OUT, worldPosition);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ struct VSOutput
|
||||
};
|
||||
|
||||
#include <Atom/Features/PBR/LightingModel.azsli>
|
||||
#include <Atom/Features/Vertex/VertexHelper.azsli>
|
||||
|
||||
VSOutput MinimalPBR_MainPassVS(VSInput IN)
|
||||
{
|
||||
@@ -50,7 +51,7 @@ VSOutput MinimalPBR_MainPassVS(VSInput IN)
|
||||
|
||||
float3 worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz;
|
||||
|
||||
PbrVsHelper(IN, OUT, worldPosition);
|
||||
VertexHelper(IN, OUT, worldPosition);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
+3
-2
@@ -44,6 +44,7 @@ namespace AtomToolsFramework
|
||||
//! Requires the Atom RPI to be initialized in order
|
||||
//! to internally construct an RPI::ViewportContext.
|
||||
explicit RenderViewportWidget(AzFramework::ViewportId id = AzFramework::InvalidViewportId, QWidget* parent = nullptr);
|
||||
~RenderViewportWidget();
|
||||
|
||||
//! Gets the name associated with this viewport's ViewportContext.
|
||||
//! This context name can be used to adjust the current Camera
|
||||
@@ -93,8 +94,8 @@ namespace AtomToolsFramework
|
||||
// AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler ...
|
||||
void BeginCursorCapture() override;
|
||||
void EndCursorCapture() override;
|
||||
QPoint ViewportCursorScreenPosition() override;
|
||||
AZStd::optional<QPoint> PreviousViewportCursorScreenPosition() override;
|
||||
AzFramework::ScreenPoint ViewportCursorScreenPosition() override;
|
||||
AZStd::optional<AzFramework::ScreenPoint> PreviousViewportCursorScreenPosition() override;
|
||||
|
||||
// AzFramework::WindowRequestBus::Handler ...
|
||||
void SetWindowTitle(const AZStd::string& title) override;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ViewportControllerList.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/Bootstrap/BootstrapRequestBus.h>
|
||||
@@ -54,12 +55,22 @@ namespace AtomToolsFramework
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(GetId());
|
||||
AzFramework::InputChannelEventListener::Connect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
|
||||
|
||||
setUpdatesEnabled(false);
|
||||
setFocusPolicy(Qt::FocusPolicy::WheelFocus);
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
RenderViewportWidget::~RenderViewportWidget()
|
||||
{
|
||||
AzFramework::WindowRequestBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AzFramework::InputChannelEventListener::Disconnect();
|
||||
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void RenderViewportWidget::LockRenderTargetSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
setFixedSize(aznumeric_cast<int>(width), aznumeric_cast<int>(height));
|
||||
@@ -183,7 +194,8 @@ namespace AtomToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_controllerList->HandleInputChannelEvent({GetId(), inputChannel});
|
||||
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
|
||||
return m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
|
||||
}
|
||||
|
||||
void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time)
|
||||
@@ -234,14 +246,16 @@ namespace AtomToolsFramework
|
||||
|
||||
// Now that we've looked a viewport local mouse position,
|
||||
// we can go ahead and broadcast the system cursor input event to the controllers.
|
||||
// This allows any controllers not listening to pure mosue deltas to consistently
|
||||
// This allows any controllers not listening to pure mouse deltas to consistently
|
||||
// look up the mouse position in viewport screen coordinates.
|
||||
const AzFramework::InputDevice* mouseInputDevice = nullptr;
|
||||
if (AzFramework::InputDeviceRequestBus::EventResult(mouseInputDevice, AzFramework::InputDeviceMouse::Id, &AzFramework::InputDeviceRequests::GetInputDevice);
|
||||
if (AzFramework::InputDeviceRequestBus::EventResult(
|
||||
mouseInputDevice, AzFramework::InputDeviceMouse::Id, &AzFramework::InputDeviceRequests::GetInputDevice);
|
||||
mouseInputDevice != nullptr)
|
||||
{
|
||||
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
|
||||
AzFramework::InputChannel syntheticInput(AzFramework::InputDeviceMouse::SystemCursorPosition, *mouseInputDevice);
|
||||
m_controllerList->HandleInputChannelEvent({GetId(), syntheticInput});
|
||||
m_controllerList->HandleInputChannelEvent({GetId(), windowId, syntheticInput});
|
||||
}
|
||||
|
||||
if (m_capturingCursor && m_lastCursorPosition.has_value())
|
||||
@@ -262,7 +276,7 @@ namespace AtomToolsFramework
|
||||
const qreal deficePixelRatio = devicePixelRatioF();
|
||||
const QSize windowSize = uiWindowSize * deficePixelRatio;
|
||||
|
||||
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
|
||||
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
|
||||
AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
|
||||
m_windowResizedEvent = false;
|
||||
}
|
||||
@@ -391,7 +405,8 @@ namespace AtomToolsFramework
|
||||
return projectedPosition.GetAsVector3() / projectedPosition.GetW();
|
||||
}
|
||||
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> RenderViewportWidget::ViewportScreenToWorldRay(const QPoint& screenPosition)
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> RenderViewportWidget::ViewportScreenToWorldRay(
|
||||
const QPoint& screenPosition)
|
||||
{
|
||||
auto pos0 = ViewportScreenToWorld(screenPosition, 0.f);
|
||||
auto pos1 = ViewportScreenToWorld(screenPosition, 1.f);
|
||||
@@ -407,14 +422,16 @@ namespace AtomToolsFramework
|
||||
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
|
||||
}
|
||||
|
||||
QPoint RenderViewportWidget::ViewportCursorScreenPosition()
|
||||
AzFramework::ScreenPoint RenderViewportWidget::ViewportCursorScreenPosition()
|
||||
{
|
||||
return m_mousePosition.toPoint();
|
||||
return AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(m_mousePosition.toPoint());
|
||||
}
|
||||
|
||||
AZStd::optional<QPoint> RenderViewportWidget::PreviousViewportCursorScreenPosition()
|
||||
AZStd::optional<AzFramework::ScreenPoint> RenderViewportWidget::PreviousViewportCursorScreenPosition()
|
||||
{
|
||||
return m_lastCursorPosition.has_value() ? mapFromGlobal(m_lastCursorPosition.value()) : m_lastCursorPosition;
|
||||
using AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint;
|
||||
return m_lastCursorPosition.has_value() ? ScreenPointFromQPoint(mapFromGlobal(m_lastCursorPosition.value()))
|
||||
: AZStd::optional<AzFramework::ScreenPoint>{};
|
||||
}
|
||||
|
||||
void RenderViewportWidget::BeginCursorCapture()
|
||||
|
||||
@@ -23,7 +23,7 @@ ly_add_target(
|
||||
Source
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::FreeType2
|
||||
3rdParty::freetype
|
||||
AZ::AzCore
|
||||
AZ::AtomCore
|
||||
Legacy::CryCommon
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace AZ
|
||||
|
||||
void MeshComponentController::UnregisterModel()
|
||||
{
|
||||
if (m_meshFeatureProcessor)
|
||||
if (m_meshFeatureProcessor && m_meshHandle.IsValid())
|
||||
{
|
||||
MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy);
|
||||
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
|
||||
|
||||
@@ -307,9 +307,9 @@ namespace EMotionFX
|
||||
const float updatedPositionY = m_actorInstance->GetWorldSpaceTransform().mPosition.GetY();
|
||||
const float actualDeltaX = AZ::GetAbs(updatedPositionX - originalPositionX);
|
||||
const float actualDeltaY = AZ::GetAbs(updatedPositionY - originalPositionY);
|
||||
EXPECT_TRUE(AZ::GetAbs(actualDeltaX - expectedDeltaX) < 0.001f)
|
||||
EXPECT_NEAR(actualDeltaX, expectedDeltaX, 0.001f)
|
||||
<< "Diagonal Rotation: The absolute difference between actual delta and expected delta of X-axis should be less than 0.001f.";
|
||||
EXPECT_TRUE(AZ::GetAbs(actualDeltaY - expectedDeltaY) < 0.001f)
|
||||
EXPECT_NEAR(actualDeltaY, expectedDeltaY, 0.001f)
|
||||
<< "Diagonal Rotation: The absolute difference between actual delta and expected delta of Y-axis should be less than 0.001f.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ ly_add_target(
|
||||
3rdParty::etc2comp
|
||||
3rdParty::PVRTexTool
|
||||
3rdParty::squish-ccr
|
||||
3rdParty::zlib
|
||||
3rdParty::tiff
|
||||
Legacy::CryCommon
|
||||
AZ::AzCore
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace ImageProcessing
|
||||
{
|
||||
}
|
||||
|
||||
explicit ColorRGBA16(uint64 a_u)
|
||||
explicit ColorRGBA16(AZ::u64 a_u)
|
||||
: u(a_u)
|
||||
{
|
||||
}
|
||||
@@ -152,7 +152,7 @@ namespace ImageProcessing
|
||||
uint16 b;
|
||||
uint16 a;
|
||||
};
|
||||
uint64 u;
|
||||
AZ::u64 u;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace ImageProcessing
|
||||
srcImage->GetImagePointer(mip, srcMem, srcPitch);
|
||||
|
||||
const pvrtexture::CPVRTextureHeader srcHeader(
|
||||
srcPixelType.PixelTypeID, // uint64 u64PixelFormat,
|
||||
srcPixelType.PixelTypeID, // AZ::u64 u64PixelFormat,
|
||||
width, // uint32 u32Height=1,
|
||||
height, // uint32 u32Width=1,
|
||||
1, // uint32 u32Depth=1,
|
||||
@@ -310,7 +310,7 @@ namespace ImageProcessing
|
||||
|
||||
// Preparing source compressed data
|
||||
const pvrtexture::CPVRTextureHeader compressedHeader(
|
||||
FindPvrPixelFormat(fmtSrc), // uint64 u64PixelFormat,
|
||||
FindPvrPixelFormat(fmtSrc), // AZ::u64 u64PixelFormat,
|
||||
width, // uint32 u32Height=1,
|
||||
height, // uint32 u32Width=1,
|
||||
1, // uint32 u32Depth=1,
|
||||
|
||||
@@ -25,9 +25,5 @@ typedef AZ::s32 int32;
|
||||
typedef AZ::s32 sint32;
|
||||
typedef AZ::u32 uint32;
|
||||
|
||||
typedef AZ::s64 int64;
|
||||
typedef AZ::s64 sint64;
|
||||
typedef AZ::u64 uint64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <libtiff/tiffio.h> // TIFF library
|
||||
#include <tiffio.h> // TIFF library
|
||||
|
||||
namespace ImageProcessing
|
||||
{
|
||||
|
||||
@@ -87,6 +87,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
Legacy::CryCommon
|
||||
Gem::LmbrCentral
|
||||
Gem::TextureAtlas
|
||||
Gem::AtomToolsFramework.Static
|
||||
Gem::AtomToolsFramework.Editor
|
||||
${additional_dependencies}
|
||||
PUBLIC
|
||||
Gem::Atom_RPI.Public
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include <LyShine/Bus/UiEditorCanvasBus.h>
|
||||
|
||||
#include "LyShine.h"
|
||||
#include "UiRenderer.h"
|
||||
#include "ViewportNudge.h"
|
||||
#include "ViewportPivot.h"
|
||||
#include "ViewportSnap.h"
|
||||
@@ -34,6 +36,9 @@
|
||||
|
||||
#include <QGridLayout>
|
||||
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
|
||||
#define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_KEY "ViewportWidget::m_drawElementBordersFlags"
|
||||
#define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_DEFAULT ( ViewportWidget::DrawElementBorders_Unselected )
|
||||
|
||||
@@ -198,7 +203,7 @@ namespace
|
||||
} // anonymous namespace.
|
||||
|
||||
ViewportWidget::ViewportWidget(EditorWindow* parent)
|
||||
: QViewport(parent)
|
||||
: AtomToolsFramework::RenderViewportWidget(AzFramework::InvalidViewportId, parent)
|
||||
, m_editorWindow(parent)
|
||||
, m_viewportInteraction(new ViewportInteraction(m_editorWindow))
|
||||
, m_viewportAnchor(new ViewportAnchor())
|
||||
@@ -213,30 +218,12 @@ ViewportWidget::ViewportWidget(EditorWindow* parent)
|
||||
, m_rulersVisible(GetPersistentRulerVisibility())
|
||||
, m_guidesVisible(GetPersistentGuideVisibility())
|
||||
{
|
||||
QObject::connect(this,
|
||||
SIGNAL(SignalRender(const SRenderContext&)),
|
||||
SLOT(HandleSignalRender(const SRenderContext&)));
|
||||
|
||||
// Turn off all fancy visuals in the viewport.
|
||||
{
|
||||
SViewportSettings tweakedSettings = GetSettings();
|
||||
|
||||
tweakedSettings.grid.showGrid = false;
|
||||
tweakedSettings.grid.origin = false;
|
||||
tweakedSettings.rendering.fps = false;
|
||||
tweakedSettings.rendering.wireframe = false;
|
||||
tweakedSettings.lighting.m_brightness = 0.0f;
|
||||
tweakedSettings.camera.showViewportOrientation = false;
|
||||
|
||||
SetSettings(tweakedSettings);
|
||||
}
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
SetUseArrowsForNavigation(false);
|
||||
|
||||
UpdateViewportBackground();
|
||||
|
||||
InitUiRenderer();
|
||||
|
||||
SetupShortcuts();
|
||||
|
||||
// Setup a timer for the maximum refresh rate we want.
|
||||
@@ -264,12 +251,32 @@ ViewportWidget::ViewportWidget(EditorWindow* parent)
|
||||
});
|
||||
|
||||
FontNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ViewportWidget::~ViewportWidget()
|
||||
{
|
||||
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
|
||||
FontNotificationBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
|
||||
m_uiRenderer.reset();
|
||||
|
||||
// Notify LyShine that this is no longer a valid UiRenderer.
|
||||
// Only one viewport/renderer is currently supported in the UI Editor
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
lyShine->SetUiRendererForEditor(nullptr);
|
||||
}
|
||||
|
||||
void ViewportWidget::InitUiRenderer()
|
||||
{
|
||||
m_uiRenderer = AZStd::make_shared<UiRenderer>(GetViewportContext());
|
||||
|
||||
// Notify LyShine that this is the UiRenderer to be used for rendering
|
||||
// UI canvases that are loaded in the UI Editor.
|
||||
// Only one viewport/renderer is currently supported in the UI Editor
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
lyShine->SetUiRendererForEditor(m_uiRenderer);
|
||||
}
|
||||
|
||||
ViewportInteraction* ViewportWidget::GetViewportInteraction()
|
||||
@@ -292,17 +299,15 @@ void ViewportWidget::ToggleDrawElementBorders(uint32 flags)
|
||||
|
||||
void ViewportWidget::UpdateViewportBackground()
|
||||
{
|
||||
SViewportSettings tweakedSettings = GetSettings();
|
||||
ColorB backgroundColor(ViewportHelpers::backgroundColorDark.GetR8(),
|
||||
const QColor backgroundColor(ViewportHelpers::backgroundColorDark.GetR8(),
|
||||
ViewportHelpers::backgroundColorDark.GetG8(),
|
||||
ViewportHelpers::backgroundColorDark.GetB8(),
|
||||
ViewportHelpers::backgroundColorDark.GetA8());
|
||||
tweakedSettings.background.useGradient = false;
|
||||
tweakedSettings.background.topColor = backgroundColor;
|
||||
tweakedSettings.background.bottomColor = backgroundColor;
|
||||
tweakedSettings.lighting.m_ambientColor = backgroundColor;
|
||||
|
||||
SetSettings(tweakedSettings);
|
||||
QPalette pal(palette());
|
||||
pal.setColor(QPalette::Window, backgroundColor);
|
||||
setPalette(pal);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
void ViewportWidget::ActiveCanvasChanged()
|
||||
@@ -344,8 +349,10 @@ void ViewportWidget::ClearUntilSafeToRedraw()
|
||||
// set flag so that Update will just clear the screen rather than rendering canvas
|
||||
m_canvasRenderIsEnabled = false;
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // check if still needed
|
||||
// Force an update
|
||||
Update();
|
||||
#endif
|
||||
|
||||
// Schedule a timer to set the m_canvasRenderIsEnabled flag
|
||||
// using a time of zero just waits until there is nothing on the event queue
|
||||
@@ -454,9 +461,10 @@ void ViewportWidget::contextMenuEvent(QContextMenuEvent* e)
|
||||
}
|
||||
}
|
||||
|
||||
QViewport::contextMenuEvent(e);
|
||||
RenderViewportWidget::contextMenuEvent(e);
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO // check if still needed
|
||||
void ViewportWidget::HandleSignalRender([[maybe_unused]] const SRenderContext& context)
|
||||
{
|
||||
// Called from QViewport when redrawing the viewport.
|
||||
@@ -477,6 +485,7 @@ void ViewportWidget::HandleSignalRender([[maybe_unused]] const SRenderContext& c
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ViewportWidget::UserSelectionChanged(HierarchyItemRawPtrList* items)
|
||||
{
|
||||
@@ -497,8 +506,34 @@ void ViewportWidget::EnableCanvasRender()
|
||||
RefreshTick();
|
||||
}
|
||||
|
||||
void ViewportWidget::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
if (!m_uiRenderer->IsReady() || !m_canvasRenderIsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
gEnv->pRenderer->SetSrgbWrite(true);
|
||||
#endif
|
||||
|
||||
// Set up to render a frame to this viewport's window
|
||||
GetViewportContext()->RenderTick();
|
||||
|
||||
UiEditorMode editorMode = m_editorWindow->GetEditorMode();
|
||||
if (editorMode == UiEditorMode::Edit)
|
||||
{
|
||||
RenderEditMode(deltaTime);
|
||||
}
|
||||
else // if (editorMode == UiEditorMode::Preview)
|
||||
{
|
||||
RenderPreviewMode(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportWidget::RefreshTick()
|
||||
{
|
||||
#ifdef LYSHINE_EDITOR_TODO // still need this?
|
||||
if (m_refreshRequested)
|
||||
{
|
||||
if (m_canvasRenderIsEnabled)
|
||||
@@ -511,6 +546,7 @@ void ViewportWidget::RefreshTick()
|
||||
// in case we were called manually, reset the timer
|
||||
m_updateTimer.start();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ViewportWidget::mousePressEvent(QMouseEvent* ev)
|
||||
@@ -636,7 +672,7 @@ void ViewportWidget::wheelEvent(QWheelEvent* ev)
|
||||
m_viewportInteraction->MouseWheelEvent(&scaledEvent);
|
||||
}
|
||||
|
||||
QViewport::wheelEvent(ev);
|
||||
RenderViewportWidget::wheelEvent(ev);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
@@ -698,7 +734,7 @@ void ViewportWidget::keyPressEvent(QKeyEvent* event)
|
||||
bool handled = m_viewportInteraction->KeyPressEvent(event);
|
||||
if (!handled)
|
||||
{
|
||||
QViewport::keyPressEvent(event);
|
||||
RenderViewportWidget::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
else // if (editorMode == UiEditorMode::Preview)
|
||||
@@ -739,7 +775,7 @@ void ViewportWidget::keyReleaseEvent(QKeyEvent* event)
|
||||
bool handled = m_viewportInteraction->KeyReleaseEvent(event);
|
||||
if (!handled)
|
||||
{
|
||||
QViewport::keyReleaseEvent(event);
|
||||
RenderViewportWidget::keyReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
else if (editorMode == UiEditorMode::Preview)
|
||||
@@ -790,7 +826,7 @@ void ViewportWidget::resizeEvent(QResizeEvent* ev)
|
||||
}
|
||||
}
|
||||
|
||||
QViewport::resizeEvent(ev);
|
||||
RenderViewportWidget::resizeEvent(ev);
|
||||
}
|
||||
|
||||
bool ViewportWidget::AcceptsMimeData(const QMimeData* mimeData)
|
||||
@@ -863,7 +899,7 @@ QPointF ViewportWidget::WidgetToViewport(const QPointF & point) const
|
||||
return point * WidgetToViewportFactor();
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderEditMode()
|
||||
void ViewportWidget::RenderEditMode(float deltaTime)
|
||||
{
|
||||
if (m_fontTextureHasChanged)
|
||||
{
|
||||
@@ -893,16 +929,18 @@ void ViewportWidget::RenderEditMode()
|
||||
AZ::Vector2 viewportSize(aznumeric_cast<float>(size().width()), aznumeric_cast<float>(size().height()));
|
||||
viewportSize *= QHighDpiScaling::factor(windowHandle()->screen());
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
// clear the stencil buffer before rendering each canvas - required for masking
|
||||
// NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target
|
||||
ColorF viewportBackgroundColor(0, 0, 0, 0); // if clearing color we want to set alpha to zero also
|
||||
gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR_STENCIL, viewportBackgroundColor);
|
||||
#endif
|
||||
|
||||
// Set the target size of the canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, GetLastFrameTime(), false);
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false);
|
||||
|
||||
// Render this canvas
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, RenderCanvasInEditorViewport, false, viewportSize);
|
||||
@@ -999,7 +1037,7 @@ void ViewportWidget::RenderEditMode()
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportWidget::RenderPreviewMode()
|
||||
void ViewportWidget::RenderPreviewMode(float deltaTime)
|
||||
{
|
||||
AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
|
||||
|
||||
@@ -1059,7 +1097,7 @@ void ViewportWidget::RenderPreviewMode()
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, true, canvasSize);
|
||||
|
||||
// Update this canvas (must be done after SetTargetCanvasSize)
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, GetLastFrameTime(), true);
|
||||
EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true);
|
||||
|
||||
// Execute events that have been queued during the canvas update
|
||||
gEnv->pLyShine->ExecuteQueuedEvents();
|
||||
@@ -1090,12 +1128,15 @@ void ViewportWidget::RenderPreviewMode()
|
||||
canvasToViewportMatrix.SetTranslation(translation);
|
||||
EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetCanvasToViewportMatrix, canvasToViewportMatrix);
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
// clear the stencil buffer before rendering each canvas - required for masking
|
||||
// NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target
|
||||
// We also clear the color to a mid grey so that we can see the bounds of the canvas
|
||||
ColorF viewportBackgroundColor(0.5f, 0.5f, 0.5f, 0); // if clearing color we want to set alpha to zero also
|
||||
gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor);
|
||||
#endif
|
||||
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
// Render a black rectangle covering the canvas area. This allows the canvas bounds to be visible when the canvas size is
|
||||
// not exactly the same as the viewport size
|
||||
AZ::Vector2 topLeftInViewportSpace = CanvasHelpers::GetViewportPoint(canvasEntityId, AZ::Vector2(0.0f, 0.0f));
|
||||
@@ -1104,6 +1145,7 @@ void ViewportWidget::RenderPreviewMode()
|
||||
Draw2dHelper draw2d;
|
||||
int texId = gEnv->pRenderer->GetBlackTextureId();
|
||||
draw2d.DrawImage(texId, topLeftInViewportSpace, sizeInViewportSpace);
|
||||
#endif
|
||||
|
||||
// Render this canvas
|
||||
// NOTE: the displayBounds param is always false. If we wanted a debug option to display the bounds
|
||||
|
||||
@@ -15,18 +15,19 @@
|
||||
#include "EditorCommon.h"
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
|
||||
|
||||
#include <IFont.h>
|
||||
#include <QViewport.h>
|
||||
|
||||
#include <QTimer>
|
||||
#endif
|
||||
|
||||
class RulerWidget;
|
||||
class QMimeData;
|
||||
class UiRenderer;
|
||||
|
||||
class ViewportWidget
|
||||
: public QViewport
|
||||
: public AtomToolsFramework::RenderViewportWidget
|
||||
, private AzToolsFramework::EditorPickModeNotificationBus::Handler
|
||||
, private FontNotificationBus::Handler
|
||||
{
|
||||
@@ -84,13 +85,14 @@ public: // member functions
|
||||
void ShowGuides(bool show);
|
||||
bool AreGuidesShown() { return m_guidesVisible; }
|
||||
|
||||
void InitUiRenderer();
|
||||
|
||||
protected:
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent* e) override;
|
||||
|
||||
private slots:
|
||||
|
||||
void HandleSignalRender(const SRenderContext& context);
|
||||
void UserSelectionChanged(HierarchyItemRawPtrList* items);
|
||||
|
||||
void EnableCanvasRender();
|
||||
@@ -141,11 +143,15 @@ private: // member functions
|
||||
void OnFontTextureUpdated(IFFont* font) override;
|
||||
// ~FontNotifications
|
||||
|
||||
// AZ::TickBus::Handler
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
// ~AZ::TickBus::Handler
|
||||
|
||||
//! Render the viewport when in edit mode
|
||||
void RenderEditMode();
|
||||
void RenderEditMode(float deltaTime);
|
||||
|
||||
//! Render the viewport when in preview mode
|
||||
void RenderPreviewMode();
|
||||
void RenderPreviewMode(float deltaTime);
|
||||
|
||||
//! Create shortcuts for manipulating the viewport
|
||||
void SetupShortcuts();
|
||||
@@ -193,4 +199,6 @@ private: // data
|
||||
bool m_rulersVisible;
|
||||
bool m_guidesVisible;
|
||||
bool m_fontTextureHasChanged = false;
|
||||
|
||||
AZStd::shared_ptr<UiRenderer> m_uiRenderer;
|
||||
};
|
||||
|
||||
@@ -288,6 +288,18 @@ UiRenderer* CLyShine::GetUiRenderer()
|
||||
return m_uiRenderer.get();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
UiRenderer* CLyShine::GetUiRendererForEditor()
|
||||
{
|
||||
return m_uiRendererForEditor.get();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void CLyShine::SetUiRendererForEditor(AZStd::shared_ptr<UiRenderer> uiRenderer)
|
||||
{
|
||||
m_uiRendererForEditor = uiRenderer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZ::EntityId CLyShine::CreateCanvas()
|
||||
{
|
||||
@@ -414,7 +426,7 @@ void CLyShine::Render()
|
||||
{
|
||||
FRAME_PROFILER(__FUNCTION__, gEnv->pSystem, PROFILE_UI);
|
||||
|
||||
// LYSHINE_ATOM_TODO - verify that this is no longer needed and remove
|
||||
// LYSHINE_ATOM_TODO - convert to use Atom interface to check for null renderer
|
||||
if (!gEnv || !gEnv->pRenderer || gEnv->pRenderer->GetRenderType() == ERenderType::eRT_Null)
|
||||
{
|
||||
// if the renderer is not initialized or it is the null renderer (e.g. running as a server)
|
||||
|
||||
@@ -111,9 +111,13 @@ public:
|
||||
int GetTickOrder() override;
|
||||
// ~TickEvents
|
||||
|
||||
// Get the UIRenderer (which is owned by CLyShine). This is not exposed outside the gem.
|
||||
// Get the UIRenderer for the game (which is owned by CLyShine). This is not exposed outside the gem.
|
||||
UiRenderer* GetUiRenderer();
|
||||
|
||||
// Get/set the UIRenderer for the Editor (which is owned by CLyShine). This is not exposed outside the gem.
|
||||
UiRenderer* GetUiRendererForEditor();
|
||||
void SetUiRendererForEditor(AZStd::shared_ptr<UiRenderer> uiRenderer);
|
||||
|
||||
public: // static member functions
|
||||
|
||||
#if defined(LYSHINE_INTERNAL_UNIT_TEST)
|
||||
@@ -138,6 +142,7 @@ private: // data
|
||||
|
||||
std::unique_ptr<CDraw2d> m_draw2d; // using a pointer rather than an instance to avoid including Draw2d.h
|
||||
std::unique_ptr<UiRenderer> m_uiRenderer; // using a pointer rather than an instance to avoid including UiRenderer.h
|
||||
AZStd::shared_ptr<UiRenderer> m_uiRendererForEditor;
|
||||
|
||||
std::unique_ptr<UiCanvasManager> m_uiCanvasManager;
|
||||
|
||||
|
||||
@@ -253,12 +253,18 @@ namespace
|
||||
}, context);
|
||||
}
|
||||
|
||||
UiRenderer* GetUiRenderer()
|
||||
UiRenderer* GetUiRendererForGame()
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine->GetUiRenderer();
|
||||
}
|
||||
|
||||
UiRenderer* GetUiRendererForEditor()
|
||||
{
|
||||
CLyShine* lyShine = static_cast<CLyShine*>(gEnv->pLyShine);
|
||||
return lyShine->GetUiRendererForEditor();
|
||||
}
|
||||
|
||||
bool IsValidInteractable(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (!entityId.IsValid())
|
||||
@@ -1974,9 +1980,12 @@ void UiCanvasComponent::UpdateCanvasInEditorViewport(float deltaTime, bool isInG
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::RenderCanvasInEditorViewport(bool isInGame, AZ::Vector2 viewportSize)
|
||||
{
|
||||
GetUiRenderer()->BeginUiFrameRender();
|
||||
RenderCanvas(isInGame, viewportSize);
|
||||
GetUiRenderer()->EndUiFrameRender();
|
||||
// When isInGame is true we're rendering the canvas in UI Editor's Preview Mode
|
||||
UiRenderer* uiRenderer = GetUiRendererForEditor();
|
||||
AZ_Assert(uiRenderer, "Trying to render a canvas in the UI Editor before its UIRenderer has been initialized");
|
||||
uiRenderer->BeginUiFrameRender();
|
||||
RenderCanvas(isInGame, viewportSize, uiRenderer);
|
||||
uiRenderer->EndUiFrameRender();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2019,7 +2028,7 @@ void UiCanvasComponent::UpdateCanvas(float deltaTime, bool isInGame)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize)
|
||||
void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, UiRenderer* uiRenderer)
|
||||
{
|
||||
// Ignore render ops if we're not enabled
|
||||
if (!m_enabled)
|
||||
@@ -2027,6 +2036,11 @@ void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uiRenderer)
|
||||
{
|
||||
uiRenderer = GetUiRendererForGame();
|
||||
}
|
||||
|
||||
// It is possible, due to the LoadScreenComponent, for this canvas to have Render called while it is rendering.
|
||||
// This is rare but can happen because rendering of text can call FontCreateTexture which results in CreateTextureObject
|
||||
// being called, which has a load scren update in it. Rendering the canvas to the render graph while already in the
|
||||
@@ -2051,9 +2065,9 @@ void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize)
|
||||
|
||||
if (!m_renderGraph.IsEmpty())
|
||||
{
|
||||
GetUiRenderer()->BeginCanvasRender();
|
||||
m_renderGraph.Render(GetUiRenderer(), viewportSize);
|
||||
GetUiRenderer()->EndCanvasRender();
|
||||
uiRenderer->BeginCanvasRender();
|
||||
m_renderGraph.Render(uiRenderer, viewportSize);
|
||||
uiRenderer->EndCanvasRender();
|
||||
}
|
||||
|
||||
m_isRendering = false;
|
||||
@@ -3724,6 +3738,7 @@ void UiCanvasComponent::DestroyRenderTarget()
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void UiCanvasComponent::RenderCanvasToTexture()
|
||||
{
|
||||
#ifdef LYSHINE_ATOM_TODO
|
||||
if (m_renderTargetHandle <= 0)
|
||||
{
|
||||
return;
|
||||
@@ -3752,6 +3767,7 @@ void UiCanvasComponent::RenderCanvasToTexture()
|
||||
|
||||
GetUiRenderer()->EndUiFrameRender();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user