+#include
namespace O3DE::ProjectManager
{
+ inline constexpr static int s_contentMargins = 80;
+ inline constexpr static int s_buttonSpacing = 30;
+ inline constexpr static int s_iconSize = 24;
+ inline constexpr static int s_spacerSize = 20;
+ inline constexpr static int s_boxButtonWidth = 210;
+ inline constexpr static int s_boxButtonHeight = 280;
+
FirstTimeUseScreen::FirstTimeUseScreen(QWidget* parent)
: ScreenWidget(parent)
- , m_ui(new Ui::FirstTimeUseClass())
{
- m_ui->setupUi(this);
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ setLayout(vLayout);
+ vLayout->setContentsMargins(s_contentMargins, s_contentMargins, s_contentMargins, s_contentMargins);
- connect(m_ui->createProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleNewProjectButton);
- connect(m_ui->openProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleOpenProjectButton);
+ QLabel* titleLabel = new QLabel(this);
+ titleLabel->setText(tr("Ready. Set. Create!"));
+ titleLabel->setStyleSheet("font-size: 60px");
+ vLayout->addWidget(titleLabel);
+
+ QLabel* introLabel = new QLabel(this);
+ introLabel->setTextFormat(Qt::AutoText);
+ introLabel->setText(tr("Welcome to O3DE! Start something new by creating a project. Not sure what to create?
Explore what\342\200\231s available by downloading our sample project.
"));
+ introLabel->setStyleSheet("font-size: 14px");
+ vLayout->addWidget(introLabel);
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout();
+ buttonLayout->setSpacing(s_buttonSpacing);
+
+ m_createProjectButton = CreateLargeBoxButton(QIcon(":/Resources/Add.svg"), tr("Create Project"), this);
+ m_createProjectButton->setIconSize(QSize(s_iconSize, s_iconSize));
+ buttonLayout->addWidget(m_createProjectButton);
+
+ m_addProjectButton = CreateLargeBoxButton(QIcon(":/Resources/Select_Folder.svg"), tr("Add a Project"), this);
+ m_addProjectButton->setIconSize(QSize(s_iconSize, s_iconSize));
+ buttonLayout->addWidget(m_addProjectButton);
+
+ QSpacerItem* buttonSpacer = new QSpacerItem(s_spacerSize, s_spacerSize, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ buttonLayout->addItem(buttonSpacer);
+
+ vLayout->addItem(buttonLayout);
+
+ QSpacerItem* verticalSpacer = new QSpacerItem(s_spacerSize, s_spacerSize, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ vLayout->addItem(verticalSpacer);
+
+ // Using border-image allows for scaling options background-image does not support
+ setStyleSheet("O3DE--ProjectManager--ScreenWidget { border-image: url(:/Resources/Backgrounds/FirstTimeBackgroundImage.jpg) repeat repeat; }");
+
+ connect(m_createProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleNewProjectButton);
+ connect(m_addProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleAddProjectButton);
}
ProjectManagerScreen FirstTimeUseScreen::GetScreenEnum()
@@ -36,9 +82,21 @@ namespace O3DE::ProjectManager
emit ResetScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
emit ChangeScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
}
- void FirstTimeUseScreen::HandleOpenProjectButton()
+ void FirstTimeUseScreen::HandleAddProjectButton()
{
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
}
+ QPushButton* FirstTimeUseScreen::CreateLargeBoxButton(const QIcon& icon, const QString& text, QWidget* parent)
+ {
+ QPushButton* largeBoxButton = new QPushButton(icon, text, parent);
+
+ largeBoxButton->setFixedSize(s_boxButtonWidth, s_boxButtonHeight);
+ largeBoxButton->setFlat(true);
+ largeBoxButton->setFocusPolicy(Qt::FocusPolicy::NoFocus);
+ largeBoxButton->setStyleSheet("QPushButton { font-size: 14px; background-color: rgba(0, 0, 0, 191); }");
+
+ return largeBoxButton;
+ }
+
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h
index 4b4a99f16a..b6b57dc16b 100644
--- a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h
+++ b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h
@@ -15,10 +15,8 @@
#include
#endif
-namespace Ui
-{
- class FirstTimeUseClass;
-}
+QT_FORWARD_DECLARE_CLASS(QIcon)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
namespace O3DE::ProjectManager
{
@@ -32,10 +30,13 @@ namespace O3DE::ProjectManager
protected slots:
void HandleNewProjectButton();
- void HandleOpenProjectButton();
+ void HandleAddProjectButton();
private:
- QScopedPointer m_ui;
+ QPushButton* CreateLargeBoxButton(const QIcon& icon, const QString& text, QWidget* parent = nullptr);
+
+ QPushButton* m_createProjectButton;
+ QPushButton* m_addProjectButton;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.ui b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.ui
deleted file mode 100644
index fdc195731f..0000000000
--- a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.ui
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
- FirstTimeUseClass
-
-
-
- 0
- 0
- 881
- 555
-
-
-
- Form
-
-
- -
-
-
-
-
-
-
- 30
-
-
-
- READY. SET. CREATE!
-
-
-
- -
-
-
- <html><head/><body><p>Welcome to O3DE! Start something new by creating a project. Not sure what to create? </p><p>Explore what’s available by downloading our sample project.</p></body></html>
-
-
- Qt::AutoText
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Create Project
-
-
-
- :/Resources/Add.svg:/Resources/Add.svg
-
-
-
- 16
- 16
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Open a Project
-
-
-
- :/Resources/Select_Folder.svg:/Resources/Select_Folder.svg
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
index 977667071f..6b9d268564 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
@@ -27,6 +27,12 @@ namespace O3DE::ProjectManager
, m_ui(new Ui::ProjectManagerWindowClass())
{
m_ui->setupUi(this);
+ QLayout* layout = m_ui->centralWidget->layout();
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ setFixedSize(this->geometry().width(), this->geometry().height());
m_pythonBindings = AZStd::make_unique(engineRootPath);
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui
index 789dd1b656..a71ed3aabf 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui
@@ -6,10 +6,16 @@
0
0
- 800
- 600
+ 1200
+ 800
+
+
+ 0
+ 0
+
+
O3DE Project Manager
@@ -21,7 +27,7 @@
0
0
- 800
+ 1200
36
diff --git a/Code/Tools/ProjectManager/Source/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h
index ae235daf2b..483066e031 100644
--- a/Code/Tools/ProjectManager/Source/ScreenWidget.h
+++ b/Code/Tools/ProjectManager/Source/ScreenWidget.h
@@ -15,18 +15,20 @@
#include
#include
+#include
+#include
#endif
namespace O3DE::ProjectManager
{
class ScreenWidget
- : public QWidget
+ : public QFrame
{
Q_OBJECT
public:
explicit ScreenWidget(QWidget* parent = nullptr)
- : QWidget(parent)
+ : QFrame(parent)
{
}
~ScreenWidget() = default;
diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
index 69af09f496..b8a38ed155 100644
--- a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
@@ -22,6 +22,9 @@ namespace O3DE::ProjectManager
: QWidget(parent)
{
QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setMargin(0);
+ vLayout->setSpacing(0);
+ vLayout->setContentsMargins(0, 0, 0, 0);
setLayout(vLayout);
m_screenStack = new QStackedWidget();
diff --git a/Code/Tools/ProjectManager/project_manager.qrc b/Code/Tools/ProjectManager/project_manager.qrc
index 6509a9f940..3c23bc24ff 100644
--- a/Code/Tools/ProjectManager/project_manager.qrc
+++ b/Code/Tools/ProjectManager/project_manager.qrc
@@ -9,5 +9,6 @@
Resources/iOS.svg
Resources/Linux.svg
Resources/macOS.svg
+ Resources/Backgrounds/FirstTimeBackgroundImage.jpg
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index 9ffdb6029d..3594d1e079 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -22,7 +22,6 @@ set(FILES
Source/EngineInfo.cpp
Source/FirstTimeUseScreen.h
Source/FirstTimeUseScreen.cpp
- Source/FirstTimeUseScreen.ui
Source/ProjectManagerWindow.h
Source/ProjectManagerWindow.cpp
Source/ProjectTemplateInfo.h
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
index 0ee25195bc..38f7de89c6 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
@@ -260,7 +260,7 @@ namespace AZ
{
AZ_TraceContext("Importer", "Animation");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
// Add check for animation layers at the scene level.
@@ -387,11 +387,10 @@ namespace AZ
}
Events::ProcessingResultCombiner combinedAnimationResult;
- for (AZ::u32 meshIndex = 0; meshIndex < currentNode->mNumMeshes; ++meshIndex)
+ if (context.m_sourceNode.ContainsMesh())
{
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[meshIndex]];
-
- if (NodeToChannelToMorphAnim::iterator channelsForMeshName = meshMorphAnimations.find(mesh->mName.C_Str());
+ const aiMesh* firstMesh = scene->mMeshes[currentNode->mMeshes[0]];
+ if (NodeToChannelToMorphAnim::iterator channelsForMeshName = meshMorphAnimations.find(firstMesh->mName.C_Str());
channelsForMeshName != meshMorphAnimations.end())
{
const auto [nodeIterName, channels] = *channelsForMeshName;
@@ -399,7 +398,7 @@ namespace AZ
{
const auto& [animation, morphAnimation] = animAndMorphAnim;
combinedAnimationResult += ImportBlendShapeAnimation(
- context, animation, morphAnimation, mesh);
+ context, animation, morphAnimation, firstMesh);
}
}
}
@@ -413,32 +412,39 @@ namespace AZ
if (boneAnimations.empty() && !meshMorphAnimations.empty())
{
const aiAnimation* animation = scene->mAnimations[0];
-
- // Morph animations need a regular animation on the node, as well.
- // If there is no bone animation on the current node, then generate one here.
- AZStd::shared_ptr createdAnimationData =
- AZStd::make_shared();
-
- const size_t numKeyframes = animation->mDuration + 1; // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1
- createdAnimationData->ReserveKeyFrames(numKeyframes);
-
- const double timeStepBetweenFrames = 1.0 / animation->mTicksPerSecond;
- createdAnimationData->SetTimeStepBetweenFrames(timeStepBetweenFrames);
-
- // Set every frame of the animation to the start location of the node.
- aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
- DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
- context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
- context.m_sourceSceneSystem.ConvertUnit(localTransform);
- for (AZ::u32 time = 0; time <= animation->mDuration; ++time)
+ for (AZ::u32 channelIndex = 0; channelIndex < animation->mNumMorphMeshChannels; ++channelIndex)
{
- createdAnimationData->AddKeyFrame(localTransform);
+ const aiMeshMorphAnim* nodeAnim = animation->mMorphMeshChannels[channelIndex];
+ // Morph animations need a regular animation on the node, as well.
+ // If there is no bone animation on the current node, then generate one here.
+ AZStd::shared_ptr createdAnimationData =
+ AZStd::make_shared();
+
+ const size_t numKeyframes = GetNumKeyFrames(
+ nodeAnim->mNumKeys,
+ animation->mDuration,
+ animation->mTicksPerSecond);
+ createdAnimationData->ReserveKeyFrames(numKeyframes);
+
+ const double timeStepBetweenFrames = 1.0 / animation->mTicksPerSecond;
+ createdAnimationData->SetTimeStepBetweenFrames(timeStepBetweenFrames);
+
+ // Set every frame of the animation to the start location of the node.
+ aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
+ DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
+ context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
+ context.m_sourceSceneSystem.ConvertUnit(localTransform);
+ for (AZ::u32 time = 0; time <= numKeyframes; ++time)
+ {
+ createdAnimationData->AddKeyFrame(localTransform);
+ }
+
+ const AZStd::string stubBoneAnimForMorphName(AZStd::string::format("%s%s", nodeName.c_str(), nodeAnim->mName.C_Str()));
+ Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
+ context.m_currentGraphPosition, stubBoneAnimForMorphName.c_str(), AZStd::move(createdAnimationData));
+ context.m_scene.GetGraph().MakeEndPoint(addNode);
}
-
- Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
- context.m_currentGraphPosition, nodeName.c_str(), AZStd::move(createdAnimationData));
- context.m_scene.GetGraph().MakeEndPoint(addNode);
-
+
return combinedAnimationResult.GetResult();
}
decltype(boneAnimations) parentFillerAnimations;
@@ -446,8 +452,8 @@ namespace AZ
// Go through all the animations and make sure we create animations for bones who's parents don't have an animation
for (auto&& anim : boneAnimations)
{
- aiNode* node = scene->mRootNode->FindNode(anim.first.c_str());
- aiNode* parent = node->mParent;
+ const aiNode* node = scene->mRootNode->FindNode(anim.first.c_str());
+ const aiNode* parent = node->mParent;
while (parent && parent != scene->mRootNode)
{
@@ -598,7 +604,8 @@ namespace AZ
// Keyframes generated for every single frame of the animation.
typedef AZStd::map> ValueToKeyDataMap;
ValueToKeyDataMap valueToKeyDataMap;
-
+ // Key time can be less than zero, normalize to have zero be the lowest time.
+ double keyOffset = 0;
for (int keyIdx = 0; keyIdx < meshMorphAnim->mNumKeys; keyIdx++)
{
aiMeshMorphKey& key = meshMorphAnim->mKeys[keyIdx];
@@ -609,6 +616,10 @@ namespace AZ
valueToKeyDataMap[currentValue].insert(
AZStd::upper_bound(valueToKeyDataMap[currentValue].begin(), valueToKeyDataMap[currentValue].end(),thisKey),
thisKey);
+ if (key.mTime < keyOffset)
+ {
+ keyOffset = key.mTime;
+ }
}
}
@@ -631,7 +642,7 @@ namespace AZ
const double time = GetTimeForFrame(frame, animation->mTicksPerSecond);
float weight = 0;
- if (!SampleKeyFrame(weight, keys, keys.size(), time, keyIdx))
+ if (!SampleKeyFrame(weight, keys, keys.size(), time + keyOffset, keyIdx))
{
return Events::ProcessingResult::Failure;
}
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.cpp
index c2b1f20035..2ce9bc14f4 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.cpp
@@ -25,7 +25,6 @@
#include
#include
-
namespace AZ
{
namespace SceneAPI
@@ -44,7 +43,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast(context);
if (serializeContext)
{
- serializeContext->Class()->Version(2); // LYN-2576
+ serializeContext->Class()->Version(3); // LYN-3250
}
}
@@ -55,62 +54,79 @@ namespace AZ
{
return Events::ProcessingResult::Ignored;
}
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
- GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
- if (!meshDataResult.IsSuccess())
+ const auto meshHasTangentsAndBitangents = [&scene](const unsigned int meshIndex)
{
- return meshDataResult.GetError();
- }
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
+ return scene->mMeshes[meshIndex]->HasTangentsAndBitangents();
+ };
- size_t vertexCount = parentMeshData->GetVertexCount();
-
- int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
- if (sdkMeshIndex < 0 || sdkMeshIndex >= currentNode->mNumMeshes)
- {
- AZ_Error(Utilities::ErrorWindow, false,
- "Tried to construct bitangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
- return Events::ProcessingResult::Failure;
- }
-
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
-
- if (!mesh->HasTangentsAndBitangents())
+ // If there are no bitangents on any meshes, there's nothing to import in this function.
+ const bool anyMeshHasTangentsAndBitangents = AZStd::any_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
+ if (!anyMeshHasTangentsAndBitangents)
{
return Events::ProcessingResult::Ignored;
}
+ // AssImp nodes with multiple meshes on them occur when AssImp split a mesh on material.
+ // This logic recombines those meshes to minimize the changes needed to replace FBX SDK with AssImp, FBX SDK did not separate meshes,
+ // and the engine has code to do this later.
+ const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
+ if (!allMeshesHaveTangentsAndBitangents)
+ {
+ const char* mixedBitangentsError =
+ "Node with name %s has meshes with and without bitangents. "
+ "Placeholder incorrect bitangents will be generated to allow the data to process, "
+ "but the source art needs to be fixed to correct this. Either apply bitangents to all meshes on this node, "
+ "or remove all bitangents from all meshes on this node.";
+ AZ_Error(
+ Utilities::ErrorWindow, false, mixedBitangentsError, currentNode->mName.C_Str());
+ }
+
+ const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
+
AZStd::shared_ptr bitangentStream =
AZStd::make_shared();
-
// AssImp only has one bitangentStream per mesh.
bitangentStream->SetBitangentSetIndex(0);
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
bitangentStream->ReserveContainerSpace(vertexCount);
-
- for (int v = 0; v < mesh->mNumVertices; ++v)
+ for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
{
- const Vector3 bitangent(
- AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
- bitangentStream->AppendBitangent(bitangent);
+ const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+
+ for (int v = 0; v < mesh->mNumVertices; ++v)
+ {
+ if (!mesh->HasTangentsAndBitangents())
+ {
+ // This node has mixed meshes with and without bitangents.
+ // An error was already thrown above. Output stub bitangents so
+ // the mesh can still be output in some form, even if the data isn't correct.
+ // The bitangent count needs to match the vertex count on the associated mesh node.
+ bitangentStream->AppendBitangent(Vector3::CreateAxisY());
+ }
+ else
+ {
+ const Vector3 bitangent(
+ AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
+ bitangentStream->AppendBitangent(bitangent);
+ }
+ }
}
- AZStd::string nodeName(AZStd::string::format("%s",m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
- context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
+ context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
Events::ProcessingResult bitangentResults;
- AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, nodeName.c_str());
+ AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, m_defaultNodeName);
bitangentResults = Events::Process(dataPopulated);
if (bitangentResults != Events::ProcessingResult::Failure)
{
bitangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
-
return bitangentResults;
}
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.cpp
index c0399329d3..34266a3e29 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.cpp
@@ -74,37 +74,51 @@ namespace AZ
{
return meshDataResult.GetError();
}
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
- int parentMeshIndex = parentMeshData->GetSdkMeshIndex();
Events::ProcessingResultCombiner combinedBlendShapeResult;
+ // 1. Loop through meshes & anims
+ // Create storage: Anim to meshes
+ // 2. Loop through anims & meshes
+ // Create an anim mesh for each anim, with meshes re-combined.
+ // AssImp separates meshes that have multiple materials.
+ // This code re-combines them to match previous FBX SDK behavior,
+ // so they can be separated by engine code instead.
+ AZStd::map>> animToMeshToAnimMeshIndices;
for (int nodeMeshIdx = 0; nodeMeshIdx < numMesh; nodeMeshIdx++)
{
int sceneMeshIdx = context.m_sourceNode.GetAssImpNode()->mMeshes[nodeMeshIdx];
const aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[sceneMeshIdx];
-
- // Each mesh gets its own node in the scene graph, so only generate
- // morph targets for the current mesh.
- if (parentMeshIndex != nodeMeshIdx || !aiMesh->mNumAnimMeshes)
- {
- continue;
- }
-
for (int animIdx = 0; animIdx < aiMesh->mNumAnimMeshes; animIdx++)
{
- AZStd::shared_ptr blendShapeData =
- AZStd::make_shared();
-
aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[animIdx];
- AZStd::string nodeName(aiAnimMesh->mName.C_Str());
- size_t dotIndex = nodeName.rfind('.');
- if (dotIndex != AZStd::string::npos)
- {
- nodeName.erase(0, dotIndex + 1);
- }
- RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "BlendShape");
- AZ_TraceContext("Blend shape name", nodeName);
+ animToMeshToAnimMeshIndices[aiAnimMesh->mName.C_Str()].emplace_back(nodeMeshIdx, animIdx);
+ }
+ }
+
+ for (const auto& animToMeshIndex : animToMeshToAnimMeshIndices)
+ {
+ AZStd::shared_ptr blendShapeData =
+ AZStd::make_shared();
+
+ // Some DCC tools, like Maya, include a full path separated by '.' in the node names.
+ // For example, "cone_skin_blendShapeNode.cone_squash"
+ // Downstream processing doesn't want anything but the last part of that node name,
+ // so find the last '.' and remove anything before it.
+ AZStd::string nodeName(animToMeshIndex.first);
+ size_t dotIndex = nodeName.rfind('.');
+ if (dotIndex != AZStd::string::npos)
+ {
+ nodeName.erase(0, dotIndex + 1);
+ }
+ int vertexOffset = 0;
+ RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "BlendShape");
+ AZ_TraceContext("Blend shape name", nodeName);
+ for (const auto& meshIndex : animToMeshIndex.second)
+ {
+ int sceneMeshIdx = context.m_sourceNode.GetAssImpNode()->mMeshes[meshIndex.first];
+ const aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[sceneMeshIdx];
+ const aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[meshIndex.second];
AZStd::bitset uvSetUsedFlags;
for (AZ::u8 uvSetIndex = 0; uvSetIndex < SceneData::GraphData::BlendShapeData::MaxNumUVSets; ++uvSetIndex)
@@ -128,7 +142,7 @@ namespace AZ
context.m_sourceSceneSystem.ConvertUnit(vertex);
blendShapeData->AddPosition(vertex);
- blendShapeData->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
+ blendShapeData->SetVertexIndexToControlPointIndexMap(vertIdx + vertexOffset, vertIdx + vertexOffset);
// Add normals
if (aiAnimMesh->HasNormals())
@@ -191,33 +205,36 @@ namespace AZ
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
- blendFace.vertexIndex[idx] = face.mIndices[idx];
+ blendFace.vertexIndex[idx] = face.mIndices[idx] + vertexOffset;
}
blendShapeData->AddFace(blendFace);
}
+ vertexOffset += aiMesh->mNumVertices;
- // Report problem if no vertex or face converted to MeshData
- if (blendShapeData->GetVertexCount() <= 0 || blendShapeData->GetFaceCount() <= 0)
- {
- AZ_Error(Utilities::ErrorWindow, false, "Missing geometry data in blendshape node %s.", nodeName.c_str());
- return Events::ProcessingResult::Failure;
- }
- Containers::SceneGraph::NodeIndex newIndex =
- context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
-
- Events::ProcessingResult blendShapeResult;
- AssImpSceneAttributeDataPopulatedContext dataPopulated(context, blendShapeData, newIndex, nodeName);
- blendShapeResult = Events::Process(dataPopulated);
-
- if (blendShapeResult != Events::ProcessingResult::Failure)
- {
- blendShapeResult = AddAttributeDataNodeWithContexts(dataPopulated);
- }
- combinedBlendShapeResult += blendShapeResult;
}
+
+ // Report problem if no vertex or face converted to MeshData
+ if (blendShapeData->GetVertexCount() <= 0 || blendShapeData->GetFaceCount() <= 0)
+ {
+ AZ_Error(Utilities::ErrorWindow, false, "Missing geometry data in blendshape node %s.", nodeName.c_str());
+ return Events::ProcessingResult::Failure;
+ }
+
+ Containers::SceneGraph::NodeIndex newIndex =
+ context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
+
+ Events::ProcessingResult blendShapeResult;
+ AssImpSceneAttributeDataPopulatedContext dataPopulated(context, blendShapeData, newIndex, nodeName);
+ blendShapeResult = Events::Process(dataPopulated);
+
+ if (blendShapeResult != Events::ProcessingResult::Failure)
+ {
+ blendShapeResult = AddAttributeDataNodeWithContexts(dataPopulated);
+ }
+ combinedBlendShapeResult += blendShapeResult;
}
return combinedBlendShapeResult.GetResult();
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
index 4467d6933b..5b43941715 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.cpp
@@ -46,8 +46,8 @@ namespace AZ
}
void EnumBonesInNode(
- const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList,
- AZStd::unordered_map& boneLookup)
+ const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList,
+ AZStd::unordered_map& boneLookup)
{
/* From AssImp Documentation
a) Create a map or a similar container to store which nodes are necessary for the skeleton. Pre-initialise it for all nodes with a "no".
@@ -62,14 +62,14 @@ namespace AZ
for (unsigned meshIndex = 0; meshIndex < node->mNumMeshes; ++meshIndex)
{
- aiMesh* mesh = scene->mMeshes[node->mMeshes[meshIndex]];
+ const aiMesh* mesh = scene->mMeshes[node->mMeshes[meshIndex]];
for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
{
- aiBone* bone = mesh->mBones[boneIndex];
+ const aiBone* bone = mesh->mBones[boneIndex];
- aiNode* boneNode = scene->mRootNode->FindNode(bone->mName);
- aiNode* boneParent = boneNode->mParent;
+ const aiNode* boneNode = scene->mRootNode->FindNode(bone->mName);
+ const aiNode* boneParent = boneNode->mParent;
mainBoneList[bone->mName.C_Str()] = boneNode;
boneLookup[bone->mName.C_Str()] = bone;
@@ -85,8 +85,8 @@ namespace AZ
}
void EnumChildren(
- const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList,
- AZStd::unordered_map& boneLookup)
+ const aiScene* scene, const aiNode* node, AZStd::unordered_map& mainBoneList,
+ AZStd::unordered_map& boneLookup)
{
EnumBonesInNode(scene, node, mainBoneList, boneLookup);
@@ -102,7 +102,7 @@ namespace AZ
{
AZ_TraceContext("Importer", "Bone");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (IsPivotNode(currentNode->mName))
@@ -118,8 +118,8 @@ namespace AZ
}
else
{
- AZStd::unordered_map mainBoneList;
- AZStd::unordered_map boneLookup;
+ AZStd::unordered_map mainBoneList;
+ AZStd::unordered_map boneLookup;
EnumChildren(scene, scene->mRootNode, mainBoneList, boneLookup);
if (mainBoneList.find(currentNode->mName.C_Str()) != mainBoneList.end())
@@ -172,7 +172,7 @@ namespace AZ
}
aiMatrix4x4 transform = currentNode->mTransformation;
- aiNode* parent = currentNode->mParent;
+ const aiNode* parent = currentNode->mParent;
while (parent)
{
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.cpp
index 7ebdb55363..75fa39105f 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
#include
@@ -44,7 +45,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast(context);
if (serializeContext)
{
- serializeContext->Class()->Version(2); // LYN-2576
+ serializeContext->Class()->Version(3); // LYN-3250
}
}
@@ -55,43 +56,64 @@ namespace AZ
{
return Events::ProcessingResult::Ignored;
}
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
- GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
- if (!meshDataResult.IsSuccess())
- {
- return meshDataResult.GetError();
- }
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
+ // This node has at least one mesh, verify that the color channel counts are the same for all meshes.
+ const int expectedColorChannels = scene->mMeshes[currentNode->mMeshes[0]]->GetNumColorChannels();
+ const bool allMeshesHaveSameNumberOfColorChannels =
+ AZStd::all_of(currentNode->mMeshes + 1, currentNode->mMeshes + currentNode->mNumMeshes, [scene, expectedColorChannels](const unsigned int meshIndex)
+ {
+ return scene->mMeshes[meshIndex]->GetNumColorChannels() == expectedColorChannels;
+ });
- size_t vertexCount = parentMeshData->GetVertexCount();
+ AZ_Error(
+ Utilities::ErrorWindow,
+ allMeshesHaveSameNumberOfColorChannels,
+ "Color channel counts for node %s has meshes with different color channel counts. "
+ "The color channel count for the first mesh will be used, and placeholder incorrect color values "
+ "will be generated to allow the data to process, but the source art needs to be fixed to correct this. "
+ "All meshes on this node should have the same number of color channels.",
+ currentNode->mName.C_Str());
- int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
- if (sdkMeshIndex < 0)
+ if (expectedColorChannels == 0)
{
- AZ_Error(Utilities::ErrorWindow, false,
- "Tried to construct color stream attribute for invalid or non-mesh parent data, mesh index is missing");
- return Events::ProcessingResult::Failure;
+ return Events::ProcessingResult::Ignored;
}
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+ const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
Events::ProcessingResultCombiner combinedVertexColorResults;
- for (int colorSetIndex = 0; colorSetIndex < mesh->GetNumColorChannels(); ++colorSetIndex)
+ for (int colorSetIndex = 0; colorSetIndex < expectedColorChannels; ++colorSetIndex)
{
+
AZStd::shared_ptr vertexColors =
AZStd::make_shared();
vertexColors->ReserveContainerSpace(vertexCount);
- for (int v = 0; v < mesh->mNumVertices; ++v)
+ for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
{
- AZ::SceneAPI::DataTypes::Color vertexColor(
- AssImpSDKWrapper::AssImpTypeConverter::ToColor(mesh->mColors[colorSetIndex][v]));
- vertexColors->AppendColor(vertexColor);
+ const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+ for (int v = 0; v < mesh->mNumVertices; ++v)
+ {
+ if (colorSetIndex < mesh->GetNumColorChannels())
+ {
+ AZ::SceneAPI::DataTypes::Color vertexColor(
+ AssImpSDKWrapper::AssImpTypeConverter::ToColor(mesh->mColors[colorSetIndex][v]));
+ vertexColors->AppendColor(vertexColor);
+ }
+ else
+ {
+ // An error was already emitted if this mesh has less color channels
+ // than other meshes on the parent node. Append an arbitrary color value, fully opaque black,
+ // so the mesh can still be processed.
+ // It's better to let the engine load a partially valid mesh than to completely fail.
+ vertexColors->AppendColor(AZ::SceneAPI::DataTypes::Color(0.0f,0.0f,0.0f,1.0f));
+ }
+ }
}
- AZStd::string nodeName(AZStd::string::format("%s%d",m_defaultNodeName,colorSetIndex));
+ AZStd::string nodeName(AZStd::string::format("%s%d", m_defaultNodeName, colorSetIndex));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
@@ -106,9 +128,7 @@ namespace AZ
combinedVertexColorResults += colorMapResults;
}
-
return combinedVertexColorResults.GetResult();
-
}
} // namespace FbxSceneBuilder
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.cpp
index 80ac01ebdf..e79eaa09aa 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.cpp
@@ -69,7 +69,7 @@ namespace AZ
aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode)
{
- aiNode* parent = currentNode->mParent;
+ const aiNode* parent = currentNode->mParent;
aiMatrix4x4 combinedTransform = currentNode->mTransformation;
while (parent)
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.cpp
index e314804ea1..a912b90e34 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.cpp
@@ -62,7 +62,7 @@ namespace AZ
for (int idx = 0; idx < context.m_sourceNode.m_assImpNode->mNumMeshes; ++idx)
{
int meshIndex = context.m_sourceNode.m_assImpNode->mMeshes[idx];
- aiMesh* assImpMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshIndex];
+ const aiMesh* assImpMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshIndex];
AZ_Assert(assImpMesh, "Asset Importer Mesh should not be null.");
int materialIndex = assImpMesh->mMaterialIndex;
AZ_TraceContext("Material Index", materialIndex);
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.cpp
index cafb96934d..193a1f9fd5 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.cpp
@@ -45,7 +45,7 @@ namespace AZ
{
AZ_TraceContext("Importer", "Mesh");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (!context.m_sourceNode.ContainsMesh() || IsSkinnedMesh(*currentNode, *scene))
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.cpp
index 145dc9a457..f4a5fd0f93 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.cpp
@@ -45,7 +45,7 @@ namespace AZ
{
AZ_TraceContext("Importer", "Skin");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (!context.m_sourceNode.ContainsMesh() || !IsSkinnedMesh(*currentNode, *scene))
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp
index abcbf10b4a..d8503857cc 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.cpp
@@ -51,7 +51,7 @@ namespace AZ
{
AZ_TraceContext("Importer", "Skin Weights");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if(currentNode->mNumMeshes <= 0)
@@ -59,35 +59,21 @@ namespace AZ
return Events::ProcessingResult::Ignored;
}
- GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
- if (!meshDataResult.IsSuccess())
- {
- return meshDataResult.GetError();
- }
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
-
- int parentMeshIndex = parentMeshData->GetSdkMeshIndex();
-
Events::ProcessingResultCombiner combinedSkinWeightsResult;
+ // Don't create this until a bone with weights is encountered
+ Containers::SceneGraph::NodeIndex weightsIndexForMesh;
+ AZStd::string skinWeightName;
+ AZStd::shared_ptr skinWeightData;
+
+ const uint64_t totalVertices = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
+
+ int vertexCount = 0;
for(unsigned nodeMeshIndex = 0; nodeMeshIndex < currentNode->mNumMeshes; ++nodeMeshIndex)
{
- if (nodeMeshIndex != parentMeshIndex)
- {
- // Only generate skinning data for the parent mesh.
- // Each AssImp mesh is assigned to a unique node,
- // so the skinning data should be generated as a child node
- // for the associated parent mesh.
- continue;
- }
int sceneMeshIndex = currentNode->mMeshes[nodeMeshIndex];
const aiMesh* mesh = scene->mMeshes[sceneMeshIndex];
- // Don't create this until a bone with weights is encountered
- Containers::SceneGraph::NodeIndex weightsIndexForMesh;
- AZStd::string skinWeightName;
- AZStd::shared_ptr skinWeightData;
-
for(unsigned b = 0; b < mesh->mNumBones; ++b)
{
const aiBone* bone = mesh->mBones[b];
@@ -100,7 +86,6 @@ namespace AZ
if (!weightsIndexForMesh.IsValid())
{
skinWeightName = s_skinWeightName;
- skinWeightName += AZStd::to_string(nodeMeshIndex);
RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
weightsIndexForMesh =
@@ -116,23 +101,25 @@ namespace AZ
}
Pending pending;
pending.m_bone = bone;
- pending.m_numVertices = mesh->mNumVertices;
+ pending.m_numVertices = totalVertices;
pending.m_skinWeightData = skinWeightData;
+ pending.m_vertOffset = vertexCount;
m_pendingSkinWeights.push_back(pending);
}
-
- Events::ProcessingResult skinWeightsResult;
- AssImpSceneAttributeDataPopulatedContext dataPopulated(context, skinWeightData, weightsIndexForMesh, skinWeightName);
- skinWeightsResult = Events::Process(dataPopulated);
-
- if (skinWeightsResult != Events::ProcessingResult::Failure)
- {
- skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated);
- }
-
- combinedSkinWeightsResult += skinWeightsResult;
+ vertexCount += mesh->mNumVertices;
}
+ Events::ProcessingResult skinWeightsResult;
+ AssImpSceneAttributeDataPopulatedContext dataPopulated(context, skinWeightData, weightsIndexForMesh, skinWeightName);
+ skinWeightsResult = Events::Process(dataPopulated);
+
+ if (skinWeightsResult != Events::ProcessingResult::Failure)
+ {
+ skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated);
+ }
+
+ combinedSkinWeightsResult += skinWeightsResult;
+
return combinedSkinWeightsResult.GetResult();
}
@@ -153,7 +140,7 @@ namespace AZ
link.boneId = boneId;
link.weight = it.m_bone->mWeights[weight].mWeight;
- it.m_skinWeightData->AddAndSortLink(it.m_bone->mWeights[weight].mVertexId, link);
+ it.m_skinWeightData->AddAndSortLink(it.m_bone->mWeights[weight].mVertexId + it.m_vertOffset, link);
}
}
const auto result = m_pendingSkinWeights.empty() ? Events::ProcessingResult::Ignored : Events::ProcessingResult::Success;
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h
index f048fe0af2..655c838701 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h
@@ -61,6 +61,7 @@ namespace AZ
{
const aiBone* m_bone = nullptr;
unsigned m_numVertices = 0;
+ unsigned m_vertOffset = 0;
AZStd::shared_ptr m_skinWeightData;
};
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.cpp
index 992a6a6ab1..47b7e410b4 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
#include
@@ -44,7 +45,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast(context);
if (serializeContext)
{
- serializeContext->Class()->Version(2); // LYN-2576
+ serializeContext->Class()->Version(3); // LYN-3250
}
}
@@ -55,62 +56,79 @@ namespace AZ
{
return Events::ProcessingResult::Ignored;
}
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
-
- GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
- if (!meshDataResult.IsSuccess())
+
+ const auto meshHasTangentsAndBitangents = [&scene](const unsigned int meshIndex)
{
- return meshDataResult.GetError();
- }
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
+ return scene->mMeshes[meshIndex]->HasTangentsAndBitangents();
+ };
- size_t vertexCount = parentMeshData->GetVertexCount();
-
- int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
- if (sdkMeshIndex < 0 || sdkMeshIndex >= currentNode->mNumMeshes)
- {
- AZ_Error(Utilities::ErrorWindow, false,
- "Tried to construct tangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
- return Events::ProcessingResult::Failure;
- }
-
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
-
- if (!mesh->HasTangentsAndBitangents())
+ // If there are no tangents on any meshes, there's nothing to import in this function.
+ const bool anyMeshHasTangentsAndBitangents = AZStd::any_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
+ if (!anyMeshHasTangentsAndBitangents)
{
return Events::ProcessingResult::Ignored;
}
+ // AssImp nodes with multiple meshes on them occur when AssImp split a mesh on material.
+ // This logic recombines those meshes to minimize the changes needed to replace FBX SDK with AssImp, FBX SDK did not separate meshes,
+ // and the engine has code to do this later.
+ const bool allMeshesHaveTangentsAndBitangents = AZStd::all_of(currentNode->mMeshes, currentNode->mMeshes + currentNode->mNumMeshes, meshHasTangentsAndBitangents);
+ if (!allMeshesHaveTangentsAndBitangents)
+ {
+ const char* mixedTangentsError =
+ "Node with name %s has meshes with and without tangents. "
+ "Placeholder incorrect tangents will be generated to allow the data to process, "
+ "but the source art needs to be fixed to correct this. Either apply tangents to all meshes on this node, "
+ "or remove all tangents from all meshes on this node.";
+ AZ_Error(
+ Utilities::ErrorWindow, false, mixedTangentsError, currentNode->mName.C_Str());
+ }
+
+ const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
+
AZStd::shared_ptr tangentStream =
AZStd::make_shared();
-
// AssImp only has one tangentStream per mesh.
tangentStream->SetTangentSetIndex(0);
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
tangentStream->ReserveContainerSpace(vertexCount);
-
- for (int v = 0; v < mesh->mNumVertices; ++v)
+ for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
{
- // Vector4's constructor that takes in a vector3 sets w to 1.0f automatically.
- const Vector4 tangent(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mTangents[v]));
- tangentStream->AppendTangent(tangent);
+ const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+
+ for (int v = 0; v < mesh->mNumVertices; ++v)
+ {
+ if (!mesh->HasTangentsAndBitangents())
+ {
+ // This node has mixed meshes with and without tangents.
+ // An error was already thrown above. Output stub tangents so
+ // the mesh can still be output in some form, even if the data isn't correct.
+ // The tangent count needs to match the vertex count on the associated mesh node.
+ tangentStream->AppendTangent(Vector4(0.f, 1.f, 0.f, 1.f));
+ }
+ else
+ {
+ const Vector4 tangent(
+ AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mTangents[v]));
+ tangentStream->AppendTangent(tangent);
+ }
+ }
}
- AZStd::string nodeName(AZStd::string::format("%s", m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
- context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
+ context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
Events::ProcessingResult tangentResults;
- AssImpSceneAttributeDataPopulatedContext dataPopulated(context, tangentStream, newIndex, nodeName.c_str());
+ AssImpSceneAttributeDataPopulatedContext dataPopulated(context, tangentStream, newIndex, m_defaultNodeName);
tangentResults = Events::Process(dataPopulated);
if (tangentResults != Events::ProcessingResult::Failure)
{
tangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
-
return tangentResults;
}
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
index 84c0e3e18c..5357c32fa9 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp
@@ -50,7 +50,7 @@ namespace AZ
Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "transform");
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (currentNode == scene->mRootNode || IsPivotNode(currentNode->mName))
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.cpp
index f5f47b233d..e37a4f4285 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.cpp
@@ -12,17 +12,19 @@
#include
#include
+#include
+#include
#include
#include
#include
#include
#include
#include
-#include
-#include
+#include
#include
#include
-#include
+#include
+#include
#include
#include
@@ -45,7 +47,7 @@ namespace AZ
SerializeContext* serializeContext = azrtti_cast(context);
if (serializeContext)
{
- serializeContext->Class()->Version(3); // LYN-2506
+ serializeContext->Class()->Version(4); // LYN-3250
}
}
@@ -56,28 +58,53 @@ namespace AZ
{
return Events::ProcessingResult::Ignored;
}
- aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
+ const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
- GetMeshDataFromParentResult meshDataResult(GetMeshDataFromParent(context));
- if (!meshDataResult.IsSuccess())
+ // AssImp separates meshes that have multiple materials.
+ // This code re-combines them to match previous FBX SDK behavior,
+ // so they can be separated by engine code instead.
+ bool foundTextureCoordinates = false;
+ AZStd::array meshesPerTextureCoordinateIndex = {};
+ for (int localMeshIndex = 0; localMeshIndex < currentNode->mNumMeshes; ++localMeshIndex)
{
- return meshDataResult.GetError();
+ aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[localMeshIndex]];
+ for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
+ {
+ if (!mesh->mTextureCoords[texCoordIndex])
+ {
+ continue;
+ }
+ ++meshesPerTextureCoordinateIndex[texCoordIndex];
+ foundTextureCoordinates = true;
+ }
}
- const SceneData::GraphData::MeshData* const parentMeshData(meshDataResult.GetValue());
- size_t vertexCount = parentMeshData->GetVertexCount();
+ if (!foundTextureCoordinates)
+ {
+ return Events::ProcessingResult::Ignored;
+ }
- int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
- AZ_Assert(sdkMeshIndex >= 0,
- "Tried to construct uv stream attribute for invalid or non-mesh parent data, mesh index is missing");
+ const uint64_t vertexCount = GetVertexCountForAllMeshesOnNode(*currentNode, *scene);
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+ for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
+ {
+ int meshesWithIndex = meshesPerTextureCoordinateIndex[texCoordIndex];
+ AZ_Error(
+ Utilities::ErrorWindow,
+ meshesWithIndex == 0 || meshesWithIndex == currentNode->mNumMeshes,
+ "Texture coordinate index %d for node %s is not on all meshes on this node. "
+ "Placeholder arbitrary texture values will be generated to allow the data to process, but the source art "
+ "needs to be fixed to correct this. All meshes on this node should have the same number of texture coordinate channels.",
+ texCoordIndex,
+ currentNode->mName.C_Str());
+ }
Events::ProcessingResultCombiner combinedUvMapResults;
- for (int texCoordIndex = 0; texCoordIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++texCoordIndex)
+ for (int texCoordIndex = 0; texCoordIndex < meshesPerTextureCoordinateIndex.size(); ++texCoordIndex)
{
- if (!mesh->mTextureCoords[texCoordIndex])
+ // No meshes have this texture coordinate index, skip it.
+ if (meshesPerTextureCoordinateIndex[texCoordIndex] == 0)
{
continue;
}
@@ -85,24 +112,55 @@ namespace AZ
AZStd::shared_ptr uvMap =
AZStd::make_shared();
uvMap->ReserveContainerSpace(vertexCount);
-
+ bool customNameFound = false;
AZStd::string name(AZStd::string::format("%s%d", m_defaultNodeName, texCoordIndex));
- if (mesh->mTextureCoordsNames[texCoordIndex].length)
+ for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
{
- name = mesh->mTextureCoordsNames[texCoordIndex].C_Str();
+ const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
+ if(mesh->mTextureCoords[texCoordIndex])
+ {
+ if (mesh->mTextureCoordsNames[texCoordIndex].length > 0)
+ {
+ if (!customNameFound)
+ {
+ name = mesh->mTextureCoordsNames[texCoordIndex].C_Str();
+ customNameFound = true;
+ }
+ else
+ {
+ AZ_Warning(Utilities::WarningWindow,
+ strcmp(name.c_str(), mesh->mTextureCoordsNames[texCoordIndex].C_Str()) == 0,
+ "Node %s has conflicting mesh coordinate names at index %d, %s and %s. Using %s.",
+ currentNode->mName.C_Str(),
+ texCoordIndex,
+ name.c_str(),
+ mesh->mTextureCoordsNames[texCoordIndex].C_Str(),
+ name.c_str());
+ }
+ }
+ }
+
+ for (int v = 0; v < mesh->mNumVertices; ++v)
+ {
+ if (mesh->mTextureCoords[texCoordIndex])
+ {
+ AZ::Vector2 vertexUV(
+ mesh->mTextureCoords[texCoordIndex][v].x,
+ // The engine's V coordinate is reverse of how it's stored in the FBX file.
+ 1.0f - mesh->mTextureCoords[texCoordIndex][v].y);
+ uvMap->AppendUV(vertexUV);
+ }
+ else
+ {
+ // An error was already emitted if the UV channels for all meshes on this node do not match.
+ // Append an arbitrary UV value so that the mesh can still be processed.
+ // It's better to let the engine load a partially valid mesh than to completely fail.
+ uvMap->AppendUV(AZ::Vector2::CreateZero());
+ }
+ }
}
uvMap->SetCustomName(name.c_str());
-
- for (int v = 0; v < mesh->mNumVertices; ++v)
- {
- AZ::Vector2 vertexUV(
- mesh->mTextureCoords[texCoordIndex][v].x,
- // The engine's V coordinate is reverse of how it's stored in the FBX file.
- 1.0f - mesh->mTextureCoords[texCoordIndex][v].y);
- uvMap->AppendUV(vertexUV);
- }
-
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, name.c_str());
@@ -116,6 +174,7 @@ namespace AZ
}
combinedUvMapResults += uvMapResults;
+
}
return combinedUvMapResults.GetResult();
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp
index 59821336e0..c90fe7d1f3 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -24,7 +25,7 @@
namespace AZ::SceneAPI::FbxSceneBuilder
{
- bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector>& meshes,
+ bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector>& meshes,
const AZStd::function()>& makeMeshFunc)
{
AZStd::unordered_map assImpMatIndexToLYIndex;
@@ -34,17 +35,18 @@ namespace AZ::SceneAPI::FbxSceneBuilder
{
return false;
}
+ auto newMesh = makeMeshFunc();
+ newMesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
+ newMesh->SetOriginalUnitSizeInMeters(sceneSystem.GetOriginalUnitSizeInMeters());
+
+ // AssImp separates meshes that have multiple materials.
+ // This code re-combines them to match previous FBX SDK behavior,
+ // so they can be separated by engine code instead.
+ int vertOffset = 0;
for (int m = 0; m < currentNode->mNumMeshes; ++m)
{
- auto newMesh = makeMeshFunc();
-
- newMesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
- newMesh->SetOriginalUnitSizeInMeters(sceneSystem.GetOriginalUnitSizeInMeters());
-
- newMesh->SetSdkMeshIndex(m);
-
- aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
+ const aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
// Lumberyard materials are created in order based on mesh references in the scene
if (assImpMatIndexToLYIndex.find(mesh->mMaterialIndex) == assImpMatIndexToLYIndex.end())
@@ -59,7 +61,7 @@ namespace AZ::SceneAPI::FbxSceneBuilder
sceneSystem.SwapVec3ForUpAxis(vertex);
sceneSystem.ConvertUnit(vertex);
newMesh->AddPosition(vertex);
- newMesh->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
+ newMesh->SetVertexIndexToControlPointIndexMap(vertIdx + vertOffset, vertIdx + vertOffset);
if (mesh->HasNormals())
{
@@ -86,14 +88,15 @@ namespace AZ::SceneAPI::FbxSceneBuilder
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
- meshFace.vertexIndex[idx] = face.mIndices[idx];
+ meshFace.vertexIndex[idx] = face.mIndices[idx] + vertOffset;
}
newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
}
+ vertOffset += mesh->mNumVertices;
- meshes.push_back(newMesh);
}
+ meshes.push_back(newMesh);
return true;
}
@@ -127,4 +130,13 @@ namespace AZ::SceneAPI::FbxSceneBuilder
azrtti_cast(parentData);
return AZ::Success(parentMeshData);
}
+
+ uint64_t GetVertexCountForAllMeshesOnNode(const aiNode& node, const aiScene& scene)
+ {
+ return AZStd::accumulate(node.mMeshes, node.mMeshes + node.mNumMeshes, uint64_t{ 0u },
+ [&scene](auto runningTotal, unsigned int meshIndex)
+ {
+ return runningTotal + scene.mMeshes[meshIndex]->mNumVertices;
+ });
+ }
}
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h
index c0b5c044cb..3c7d3d2102 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h
@@ -44,11 +44,16 @@ namespace AZ
namespace FbxSceneBuilder
{
- bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector>& meshes,
+ bool BuildSceneMeshFromAssImpMesh(const aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector>& meshes,
const AZStd::function()>& makeMeshFunc);
typedef AZ::Outcome GetMeshDataFromParentResult;
GetMeshDataFromParentResult GetMeshDataFromParent(AssImpSceneNodeAppendedContext& context);
+
+ // If a node in the original scene file has a mesh with multiple materials on it, the associated AssImp
+ // node will have multiple meshes on it, broken apart per material. This returns the total number
+ // of vertices on all meshes on the given node.
+ uint64_t GetVertexCountForAllMeshesOnNode(const aiNode& node, const aiScene& scene);
}
}
}
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.cpp
index abc095d583..b67696e3cc 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.cpp
@@ -27,6 +27,7 @@ namespace AZ
Containers::SceneGraph::NodeIndex parentNode, const char* defaultName)
{
AZ_TraceContext("Node name", name);
+ const AZStd::string originalNodeName(name);
bool isNameUpdated = false;
// Nodes can't have an empty name, except of the root, otherwise nodes can't be referenced.
@@ -56,7 +57,7 @@ namespace AZ
// can't reference the same parent in that case. This is to make sure the node can be quickly found as
// the full path will be unique. To fix any issues, an index is appended.
size_t index = 1;
- size_t offset = name.length();
+ const size_t offset = name.length();
while (graph.Find(parentNode, name).IsValid())
{
// Remove the previously tried extension.
@@ -71,7 +72,8 @@ namespace AZ
if (isNameUpdated)
{
AZ_TraceContext("New node name", name);
- AZ_TracePrintf(Utilities::WarningWindow, "The name of the node was invalid or conflicting and was updated.");
+ AZ_TracePrintf(Utilities::WarningWindow, "The name of the node '%s' was invalid or conflicting and was updated to '%s'.",
+ originalNodeName.c_str(), name.c_str());
}
return isNameUpdated;
diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp
index eccbe729c6..2cda1e68ae 100644
--- a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp
+++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp
@@ -38,12 +38,14 @@ namespace AZ
{
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName);
AZ_TraceContext("Filename", fileName);
+ // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this,
+ // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release.
+ // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph.
m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, false);
m_sceneFileName = fileName;
m_assImpScene = m_importer.ReadFile(fileName,
aiProcess_Triangulate //Triangulates all faces of all meshes
- | aiProcess_JoinIdenticalVertices //Identifies and joins identical vertex data sets for the imported meshes
| aiProcess_LimitBoneWeights //Limits the number of bones that can affect a vertex to a maximum value
//dropping the least important and re-normalizing
| aiProcess_GenNormals); //Generate normals for meshes
diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp
index e99788d570..f3c01df2e3 100644
--- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp
+++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp
@@ -19,6 +19,16 @@ namespace AZ::SceneAPI::Utilities
m_output += AZStd::string::format("\t%s: %s\n", name, data);
}
+ void DebugOutput::WriteArray(const char* name, const unsigned int* data, int size)
+ {
+ m_output += AZStd::string::format("\t%s: ", name);
+ for (int index = 0; index < size; ++index)
+ {
+ m_output += AZStd::string::format("%d, ", data[index]);
+ }
+ m_output += AZStd::string::format("\n");
+ }
+
void DebugOutput::Write(const char* name, const AZStd::string& data)
{
Write(name, data.c_str());
diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h
index a598c996c9..83dc9dd6ab 100644
--- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h
+++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h
@@ -29,6 +29,7 @@ namespace AZ::SceneAPI::Utilities
void Write(const char* name, const AZStd::vector>& data);
SCENE_CORE_API void Write(const char* name, const char* data);
+ SCENE_CORE_API void WriteArray(const char* name, const unsigned int* data, int size);
SCENE_CORE_API void Write(const char* name, const AZStd::string& data);
SCENE_CORE_API void Write(const char* name, double data);
SCENE_CORE_API void Write(const char* name, uint64_t data);
diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp
index 902928d404..7d81166829 100644
--- a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp
+++ b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp
@@ -285,8 +285,26 @@ namespace AZ
void BlendShapeData::GetDebugOutput(SceneAPI::Utilities::DebugOutput& output) const
{
output.Write("Positions", m_positions);
+ int index = 0;
+ for (const auto& position : m_positions)
+ {
+ output.Write(AZStd::string::format("\t%d", index).c_str(), position);
+ ++index;
+ }
+ index = 0;
output.Write("Normals", m_normals);
+ for (const auto& normal : m_normals)
+ {
+ output.Write(AZStd::string::format("\t%d", index).c_str(), normal);
+ ++index;
+ }
+ index = 0;
output.Write("Faces", m_faces);
+ for (const auto& face : m_faces)
+ {
+ output.WriteArray(AZStd::string::format("\t%d", index).c_str(), face.vertexIndex, 3);
+ ++index;
+ }
}
} // GraphData
} // SceneData
diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp
index 8bf49b2898..8f464240c9 100644
--- a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp
+++ b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp
@@ -45,7 +45,6 @@ namespace AZ
behaviorContext->Class()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
- ->Method("GetSdkMeshIndex", &MeshData::GetSdkMeshIndex)
->Method("GetControlPointIndex", &MeshData::GetControlPointIndex)
->Method("GetUsedControlPointCount", &MeshData::GetUsedControlPointCount)
->Method("GetUsedPointIndexForControlPoint", &MeshData::GetUsedPointIndexForControlPoint)
@@ -77,10 +76,6 @@ namespace AZ
void MeshData::CloneAttributesFrom(const IGraphObject* sourceObject)
{
IMeshData::CloneAttributesFrom(sourceObject);
- if (const auto* typedSource = azrtti_cast(sourceObject))
- {
- SetSdkMeshIndex(typedSource->GetSdkMeshIndex());
- }
}
void MeshData::AddPosition(const AZ::Vector3& position)
@@ -111,15 +106,6 @@ namespace AZ
m_faceMaterialIds.push_back(faceMaterialId);
}
- void MeshData::SetSdkMeshIndex(int sdkMeshIndex)
- {
- m_sdkMeshIndex = sdkMeshIndex;
- }
- int MeshData::GetSdkMeshIndex() const
- {
- return m_sdkMeshIndex;
- }
-
void MeshData::SetVertexIndexToControlPointIndexMap(int vertexIndex, int controlPointIndex)
{
m_vertexIndexToControlPointIndexMap[vertexIndex] = controlPointIndex;
@@ -206,8 +192,26 @@ namespace AZ
void MeshData::GetDebugOutput(SceneAPI::Utilities::DebugOutput& output) const
{
output.Write("Positions", m_positions);
+ int index = 0;
+ for (const auto& position : m_positions)
+ {
+ output.Write(AZStd::string::format("\t%d", index).c_str(), position);
+ ++index;
+ }
+ index = 0;
output.Write("Normals", m_normals);
+ for (const auto& normal : m_normals)
+ {
+ output.Write(AZStd::string::format("\t%d", index).c_str(), normal);
+ ++index;
+ }
+ index = 0;
output.Write("FaceList", m_faceList);
+ for (const auto& face : m_faceList)
+ {
+ output.WriteArray(AZStd::string::format("\t%d", index).c_str(), face.vertexIndex, 3);
+ ++index;
+ }
output.Write("FaceMaterialIds", m_faceMaterialIds);
}
}
diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.h b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.h
index c5197d6cb4..4321096857 100644
--- a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.h
+++ b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.h
@@ -49,9 +49,6 @@ namespace AZ
SCENE_DATA_API void AddFace(const AZ::SceneAPI::DataTypes::IMeshData::Face& face,
unsigned int faceMaterialId = AZ::SceneAPI::DataTypes::IMeshData::s_invalidMaterialId);
- SCENE_DATA_API void SetSdkMeshIndex(int sdkMeshIndex);
- SCENE_DATA_API int GetSdkMeshIndex() const;
-
SCENE_DATA_API void SetVertexIndexToControlPointIndexMap(int vertexIndex, int controlPointIndex);
SCENE_DATA_API size_t GetUsedControlPointCount() const override;
SCENE_DATA_API int GetControlPointIndex(int vertexIndex) const override;
@@ -80,8 +77,6 @@ namespace AZ
AZStd::unordered_map m_vertexIndexToControlPointIndexMap;
AZStd::unordered_map m_controlPointToUsedVertexIndexMap;
-
- int m_sdkMeshIndex = -1;
};
}
}
diff --git a/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
index 79c6cfea7e..84018bbc9a 100644
--- a/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
+++ b/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
@@ -57,7 +57,6 @@ namespace AZ
meshData->AddNormal(Vector3{0.1f, 0.2f, 0.3f});
meshData->AddNormal(Vector3{0.4f, 0.5f, 0.6f});
meshData->SetOriginalUnitSizeInMeters(10.0f);
- meshData->SetSdkMeshIndex(1337);
meshData->SetUnitSizeInMeters(0.5f);
meshData->SetVertexIndexToControlPointIndexMap(0, 10);
meshData->SetVertexIndexToControlPointIndexMap(1, 11);
@@ -252,7 +251,6 @@ namespace AZ
ExpectExecute("TestExpectFloatEquals(meshData:GetNormal(1).z, 0.6)");
ExpectExecute("TestExpectFloatEquals(meshData:GetOriginalUnitSizeInMeters(), 10.0)");
ExpectExecute("TestExpectFloatEquals(meshData:GetUnitSizeInMeters(), 0.5)");
- ExpectExecute("TestExpectIntegerEquals(meshData:GetSdkMeshIndex(), 1337)");
ExpectExecute("TestExpectIntegerEquals(meshData:GetUsedControlPointCount(), 4)");
ExpectExecute("TestExpectIntegerEquals(meshData:GetControlPointIndex(0), 10)");
ExpectExecute("TestExpectIntegerEquals(meshData:GetControlPointIndex(1), 11)");
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
index 84095ac163..456d7cbabe 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
@@ -101,7 +101,7 @@ struct VSOutput
float2 m_uv[UvSetCount] : UV1;
float2 m_detailUv : UV3;
- float4 m_blendMask : UV8;
+ float4 m_wrinkleBlendFactors : UV8;
};
#include
@@ -132,11 +132,11 @@ VSOutput SkinVS(VSInput IN)
if(o_blendMask_isBound)
{
- OUT.m_blendMask = IN.m_optional_blendMask;
+ OUT.m_wrinkleBlendFactors = IN.m_optional_blendMask;
}
else
{
- OUT.m_blendMask = float4(0,1,0,0);
+ OUT.m_wrinkleBlendFactors = float4(0,0,0,0);
}
VertexHelper(IN, OUT, worldPosition, false);
@@ -214,7 +214,22 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
-
+
+ // ------- Wrinkle Map Setup -------
+
+ // Combine the optional per-morph target wrinkle masks
+ float4 wrinkleBlendFactors = float4(0.0, 0.0, 0.0, 0.0);
+ for(uint wrinkleMaskIndex = 0; wrinkleMaskIndex < ObjectSrg::m_wrinkle_mask_count; ++wrinkleMaskIndex)
+ {
+ wrinkleBlendFactors += ObjectSrg::m_wrinkle_masks[wrinkleMaskIndex].Sample(MaterialSrg::m_sampler, normalUv) * ObjectSrg::GetWrinkleMaskWeight(wrinkleMaskIndex);
+ }
+
+ // If texture based morph target driven masks are being used, use those values instead of the per-vertex colors
+ if(ObjectSrg::m_wrinkle_mask_count)
+ {
+ IN.m_wrinkleBlendFactors = saturate(wrinkleBlendFactors);
+ }
+
// Since the wrinkle normal maps should all be in the same tangent space as the main normal map, we should be able to blend the raw normal map
// texture values before doing all the tangent space transforms, so we only have to do the transforms once, for better performance.
@@ -223,12 +238,12 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
{
normalMapSample = SampleNormalXY(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY);
}
- if(o_wrinkleLayers_enabled && o_blendMask_isBound && o_wrinkleLayers_normal_enabled)
+ if(o_wrinkleLayers_enabled && o_wrinkleLayers_normal_enabled)
{
- normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture1, normalMapSample, MaterialSrg::m_wrinkle_normal_texture1, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.r);
- normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture2, normalMapSample, MaterialSrg::m_wrinkle_normal_texture2, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.g);
- normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture3, normalMapSample, MaterialSrg::m_wrinkle_normal_texture3, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.b);
- normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_blendMask.a);
+ normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture1, normalMapSample, MaterialSrg::m_wrinkle_normal_texture1, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.r);
+ normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture2, normalMapSample, MaterialSrg::m_wrinkle_normal_texture2, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.g);
+ normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture3, normalMapSample, MaterialSrg::m_wrinkle_normal_texture3, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.b);
+ normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.a);
}
if(o_detail_normal_useTexture)
@@ -255,7 +270,7 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float3 baseColor = GetBaseColorInput(MaterialSrg::m_baseColorMap, MaterialSrg::m_sampler, baseColorUv, MaterialSrg::m_baseColor, o_baseColor_useTexture);
bool useSampledBaseColor = o_baseColor_useTexture;
- if(o_wrinkleLayers_enabled && o_blendMask_isBound && o_wrinkleLayers_baseColor_enabled)
+ if(o_wrinkleLayers_enabled && o_wrinkleLayers_baseColor_enabled)
{
// If any of the wrinkle maps are applied, we will use the Base Color blend settings to apply the MaterialSrg::m_baseColor tint to the wrinkle maps,
// even if the main base color map is not used.
@@ -272,10 +287,10 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
baseColor = float3(1,1,1);
}
- baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture1, baseColor, MaterialSrg::m_wrinkle_baseColor_texture1, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.r);
- baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture2, baseColor, MaterialSrg::m_wrinkle_baseColor_texture2, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.g);
- baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture3, baseColor, MaterialSrg::m_wrinkle_baseColor_texture3, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.b);
- baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture4, baseColor, MaterialSrg::m_wrinkle_baseColor_texture4, MaterialSrg::m_sampler, baseColorUv, IN.m_blendMask.a);
+ baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture1, baseColor, MaterialSrg::m_wrinkle_baseColor_texture1, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.r);
+ baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture2, baseColor, MaterialSrg::m_wrinkle_baseColor_texture2, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.g);
+ baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture3, baseColor, MaterialSrg::m_wrinkle_baseColor_texture3, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.b);
+ baseColor = ApplyBaseColorWrinkleMap(o_wrinkleLayers_baseColor_useTexture4, baseColor, MaterialSrg::m_wrinkle_baseColor_texture4, MaterialSrg::m_sampler, baseColorUv, IN.m_wrinkleBlendFactors.a);
}
@@ -283,13 +298,13 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
baseColor = ApplyTextureOverlay(o_detail_baseColor_useTexture, baseColor, MaterialSrg::m_detail_baseColor_texture, MaterialSrg::m_sampler, IN.m_detailUv, detailLayerBaseColorFactor);
- if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues && o_blendMask_isBound)
+ if(o_wrinkleLayers_enabled && o_wrinkleLayers_showBlendMaskValues)
{
// Overlay debug colors to highlight the different blend weights coming from the vertex color stream.
- if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_blendMask.r); }
- if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_blendMask.g); }
- if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_blendMask.b); }
- if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_blendMask.a); }
+ if(o_wrinkleLayers_count > 0) { baseColor = lerp(baseColor, float3(1,0,0), IN.m_wrinkleBlendFactors.r); }
+ if(o_wrinkleLayers_count > 1) { baseColor = lerp(baseColor, float3(0,1,0), IN.m_wrinkleBlendFactors.g); }
+ if(o_wrinkleLayers_count > 2) { baseColor = lerp(baseColor, float3(0,0,1), IN.m_wrinkleBlendFactors.b); }
+ if(o_wrinkleLayers_count > 3) { baseColor = lerp(baseColor, float3(1,1,1), IN.m_wrinkleBlendFactors.a); }
}
// ------- Specular -------
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
index b8951d69c7..101a03b907 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
@@ -987,15 +987,6 @@
{
"file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
"tag": "SkinnedMeshMotionVector"
- },
- // Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency
- {
- "file": "Shaders/Depth/DepthPassTransparentMin.shader",
- "tag": "DepthPassTransparentMin"
- },
- {
- "file": "Shaders/Depth/DepthPassTransparentMax.shader",
- "tag": "DepthPassTransparentMax"
}
],
"functors": [
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
index a74ceb1783..2b0d09bc5c 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
@@ -1199,6 +1199,14 @@
"file": "./StandardPBR_ForwardPass_EDS.shader",
"tag": "ForwardPass_EDS"
},
+ {
+ "file": "./StandardPBR_LowEndForward.shader",
+ "tag": "LowEndForward"
+ },
+ {
+ "file": "./StandardPBR_LowEndForward_EDS.shader",
+ "tag": "LowEndForward_EDS"
+ },
{
"file": "Shaders/Shadow/Shadowmap.shader",
"tag": "Shadowmap"
@@ -1289,10 +1297,6 @@
"textureProperty": "baseColor.textureMap",
"useTextureProperty": "baseColor.useTexture",
"dependentProperties": ["baseColor.textureMapUv", "baseColor.textureBlendMode"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
"shaderOption": "o_baseColor_useTexture"
}
},
@@ -1302,10 +1306,6 @@
"textureProperty": "metallic.textureMap",
"useTextureProperty": "metallic.useTexture",
"dependentProperties": ["metallic.textureMapUv"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
"shaderOption": "o_metallic_useTexture"
}
},
@@ -1315,10 +1315,6 @@
"textureProperty": "specularF0.textureMap",
"useTextureProperty": "specularF0.useTexture",
"dependentProperties": ["specularF0.textureMapUv"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
"shaderOption": "o_specularF0_useTexture"
}
},
@@ -1328,10 +1324,6 @@
"textureProperty": "normal.textureMap",
"useTextureProperty": "normal.useTexture",
"dependentProperties": ["normal.textureMapUv", "normal.factor", "normal.flipX", "normal.flipY"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
"shaderOption": "o_normal_useTexture"
}
},
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
index f362349a7b..bf1ec96b79 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
@@ -10,6 +10,8 @@
*
*/
+#include "Atom/Features/ShaderQualityOptions.azsli"
+
#include "StandardPBR_Common.azsli"
// SRGs
@@ -317,13 +319,18 @@ ForwardPassOutputWithDepth StandardPbr_ForwardPassPS(VSOutput IN, bool isFrontFa
PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth);
+#ifdef UNIFIED_FORWARD_OUTPUT
+ OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb;
+ OUT.m_color.a = lightingOutput.m_diffuseColor.a;
+ OUT.m_depth = depth;
+#else
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_specularColor = lightingOutput.m_specularColor;
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
OUT.m_depth = depth;
-
+#endif
return OUT;
}
@@ -335,12 +342,16 @@ ForwardPassOutput StandardPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace :
PbrLightingOutput lightingOutput = ForwardPassPS_Common(IN, isFrontFace, depth);
+#ifdef UNIFIED_FORWARD_OUTPUT
+ OUT.m_color.rgb = lightingOutput.m_diffuseColor.rgb + lightingOutput.m_specularColor.rgb;
+ OUT.m_color.a = lightingOutput.m_diffuseColor.a;
+#else
OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
OUT.m_specularColor = lightingOutput.m_specularColor;
OUT.m_specularF0 = lightingOutput.m_specularF0;
OUT.m_albedo = lightingOutput.m_albedo;
OUT.m_normal = lightingOutput.m_normal;
-
+#endif
return OUT;
}
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.azsl
new file mode 100644
index 0000000000..c87faffcbe
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.azsl
@@ -0,0 +1,17 @@
+/*
+* 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.
+*
+*/
+
+// NOTE: This file is a temporary workaround until .shader files can #define macros for their .azsl files
+
+#define QUALITY_LOW_END 1
+
+#include "StandardPBR_ForwardPass.azsl"
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.shader
new file mode 100644
index 0000000000..44139608ca
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward.shader
@@ -0,0 +1,59 @@
+{
+ // Note: "LowEnd" shaders are for supporting the low end pipeline
+ // These shaders can be safely added to materials without incurring additional runtime draw
+ // items as draw items for shaders are only created if the scene has a pass with a matching
+ // DrawListTag. If your pipeline doesn't have a "lowEndForward" DrawListTag, no draw items
+ // for this shader will be created.
+
+ "Source" : "./StandardPBR_LowEndForward.azsl",
+
+ "DepthStencilState" :
+ {
+ "Depth" :
+ {
+ "Enable" : true,
+ "CompareFunc" : "GreaterEqual"
+ },
+ "Stencil" :
+ {
+ "Enable" : true,
+ "ReadMask" : "0x00",
+ "WriteMask" : "0xFF",
+ "FrontFace" :
+ {
+ "Func" : "Always",
+ "DepthFailOp" : "Keep",
+ "FailOp" : "Keep",
+ "PassOp" : "Replace"
+ },
+ "BackFace" :
+ {
+ "Func" : "Always",
+ "DepthFailOp" : "Keep",
+ "FailOp" : "Keep",
+ "PassOp" : "Replace"
+ }
+ }
+ },
+
+ "CompilerHints" : {
+ "DisableOptimizations" : false
+ },
+
+ "ProgramSettings":
+ {
+ "EntryPoints":
+ [
+ {
+ "name": "StandardPbr_ForwardPassVS",
+ "type": "Vertex"
+ },
+ {
+ "name": "StandardPbr_ForwardPassPS",
+ "type": "Fragment"
+ }
+ ]
+ },
+
+ "DrawList" : "lowEndForward"
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward_EDS.shader b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward_EDS.shader
new file mode 100644
index 0000000000..9faa1d3698
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_LowEndForward_EDS.shader
@@ -0,0 +1,59 @@
+{
+ // Note: "LowEnd" shaders are for supporting the low end pipeline
+ // These shaders can be safely added to materials without incurring additional runtime draw
+ // items as draw items for shaders are only created if the scene has a pass with a matching
+ // DrawListTag. If your pipeline doesn't have a "lowEndForward" DrawListTag, no draw items
+ // for this shader will be created.
+
+ "Source" : "./StandardPBR_LowEndForward.azsl",
+
+ "DepthStencilState" :
+ {
+ "Depth" :
+ {
+ "Enable" : true,
+ "CompareFunc" : "GreaterEqual"
+ },
+ "Stencil" :
+ {
+ "Enable" : true,
+ "ReadMask" : "0x00",
+ "WriteMask" : "0xFF",
+ "FrontFace" :
+ {
+ "Func" : "Always",
+ "DepthFailOp" : "Keep",
+ "FailOp" : "Keep",
+ "PassOp" : "Replace"
+ },
+ "BackFace" :
+ {
+ "Func" : "Always",
+ "DepthFailOp" : "Keep",
+ "FailOp" : "Keep",
+ "PassOp" : "Replace"
+ }
+ }
+ },
+
+ "CompilerHints" : {
+ "DisableOptimizations" : false
+ },
+
+ "ProgramSettings":
+ {
+ "EntryPoints":
+ [
+ {
+ "name": "StandardPbr_ForwardPassVS",
+ "type": "Vertex"
+ },
+ {
+ "name": "StandardPbr_ForwardPassPS_EDS",
+ "type": "Fragment"
+ }
+ ]
+ },
+
+ "DrawList" : "lowEndForward"
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua
index 7c3d989c35..2733713122 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua
@@ -29,26 +29,33 @@ function Process(context)
local depthPass = context:GetShaderByTag("DepthPass")
local shadowMap = context:GetShaderByTag("Shadowmap")
local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS")
+ local lowEndForwardEDS = context:GetShaderByTag("LowEndForward_EDS")
+
local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS")
local shadowMapWitPS = context:GetShaderByTag("Shadowmap_WithPS")
local forwardPass = context:GetShaderByTag("ForwardPass")
+ local lowEndForward = context:GetShaderByTag("LowEndForward")
if parallaxEnabled and parallaxPdoEnabled then
depthPass:SetEnabled(false)
shadowMap:SetEnabled(false)
forwardPassEDS:SetEnabled(false)
+ lowEndForwardEDS:SetEnabled(false)
depthPassWithPS:SetEnabled(true)
shadowMapWitPS:SetEnabled(true)
forwardPass:SetEnabled(true)
+ lowEndForward:SetEnabled(true)
else
depthPass:SetEnabled(opacityMode == OpacityMode_Opaque)
shadowMap:SetEnabled(opacityMode == OpacityMode_Opaque)
forwardPassEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
+ lowEndForwardEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
depthPassWithPS:SetEnabled(opacityMode == OpacityMode_Cutout)
shadowMapWitPS:SetEnabled(opacityMode == OpacityMode_Cutout)
forwardPass:SetEnabled(opacityMode == OpacityMode_Cutout)
+ lowEndForward:SetEnabled(opacityMode == OpacityMode_Cutout)
end
context:GetShaderByTag("DepthPassTransparentMin"):SetEnabled((opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/Forward.pass b/Gems/Atom/Feature/Common/Assets/Passes/Forward.pass
index 31a8ed1879..b66e3bb4e1 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/Forward.pass
+++ b/Gems/Atom/Feature/Common/Assets/Passes/Forward.pass
@@ -148,22 +148,6 @@
},
"LoadAction": "Clear"
}
- },
- {
- "Name": "ScatterDistanceOutput",
- "SlotType": "Output",
- "ScopeAttachmentUsage": "RenderTarget",
- "LoadStoreAction": {
- "ClearValue": {
- "Value": [
- 0.0,
- 0.0,
- 0.0,
- 0.0
- ]
- },
- "LoadAction": "Clear"
- }
}
],
"ImageAttachments": [
@@ -238,19 +222,6 @@
"AssetRef": {
"FilePath": "Textures/BRDFTexture.attimage"
}
- },
- {
- "Name": "ScatterDistanceImage",
- "SizeSource": {
- "Source": {
- "Pass": "Parent",
- "Attachment": "SwapChainOutput"
- }
- },
- "ImageDescriptor": {
- "Format": "R11G11B10_FLOAT",
- "SharedQueueMask": "Graphics"
- }
}
],
"Connections": [
@@ -295,13 +266,6 @@
"Pass": "This",
"Attachment": "BRDFTexture"
}
- },
- {
- "LocalSlot": "ScatterDistanceOutput",
- "AttachmentRef": {
- "Pass": "This",
- "Attachment": "ScatterDistanceImage"
- }
}
]
}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass
new file mode 100644
index 0000000000..3e804d23e2
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Passes/LightAdaptationParent.pass
@@ -0,0 +1,146 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "PassAsset",
+ "ClassData": {
+ "PassTemplate": {
+ "Name": "LightAdaptationParentTemplate",
+ "PassClass": "ParentPass",
+ "Slots": [
+ // Inputs...
+ {
+ "Name": "LightingInput",
+ "SlotType": "Input"
+ },
+ // SwapChain here is only used to reference the frame height and format
+ {
+ "Name": "SwapChainOutput",
+ "SlotType": "InputOutput"
+ },
+ // Outputs...
+ {
+ "Name": "Output",
+ "SlotType": "Output"
+ },
+ // Debug Outputs...
+ {
+ "Name": "LuminanceMipChainOutput",
+ "SlotType": "Output"
+ }
+ ],
+ "Connections": [
+ {
+ "LocalSlot": "Output",
+ "AttachmentRef": {
+ "Pass": "DisplayMapperPass",
+ "Attachment": "Output"
+ }
+ },
+ {
+ "LocalSlot": "LuminanceMipChainOutput",
+ "AttachmentRef": {
+ "Pass": "DownsampleLuminanceMipChain",
+ "Attachment": "MipChainInputOutput"
+ }
+ }
+ ],
+ "PassRequests": [
+ {
+ "Name": "DownsampleLuminanceMinAvgMax",
+ "TemplateName": "DownsampleLuminanceMinAvgMaxCS",
+ "Connections": [
+ {
+ "LocalSlot": "Input",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "LightingInput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "DownsampleLuminanceMipChain",
+ "TemplateName": "DownsampleMipChainTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "MipChainInputOutput",
+ "AttachmentRef": {
+ "Pass": "DownsampleLuminanceMinAvgMax",
+ "Attachment": "Output"
+ }
+ }
+ ],
+ "PassData": {
+ "$type": "DownsampleMipChainPassData",
+ "ShaderAsset": {
+ "FilePath": "Shaders/PostProcessing/DownsampleMinAvgMaxCS.shader"
+ }
+ }
+ },
+ {
+ "Name": "EyeAdaptationPass",
+ "TemplateName": "EyeAdaptationTemplate",
+ "Enabled": false,
+ "Connections": [
+ {
+ "LocalSlot": "SceneLuminanceInput",
+ "AttachmentRef": {
+ "Pass": "DownsampleLuminanceMipChain",
+ "Attachment": "MipChainInputOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "LookModificationTransformPass",
+ "TemplateName": "LookModificationTransformTemplate",
+ "Enabled": true,
+ "Connections": [
+ {
+ "LocalSlot": "Input",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "LightingInput"
+ }
+ },
+ {
+ "LocalSlot": "EyeAdaptationDataInput",
+ "AttachmentRef": {
+ "Pass": "EyeAdaptationPass",
+ "Attachment": "EyeAdaptationDataInputOutput"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "DisplayMapperPass",
+ "TemplateName": "DisplayMapperTemplate",
+ "Enabled": true,
+ "Connections": [
+ {
+ "LocalSlot": "Input",
+ "AttachmentRef": {
+ "Pass": "LookModificationTransformPass",
+ "Attachment": "Output"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndForward.pass b/Gems/Atom/Feature/Common/Assets/Passes/LowEndForward.pass
new file mode 100644
index 0000000000..4b865fcb6d
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndForward.pass
@@ -0,0 +1,133 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "PassAsset",
+ "ClassData": {
+ "PassTemplate": {
+ "Name": "LowEndForwardPassTemplate",
+ "PassClass": "RasterPass",
+ "Slots": [
+ // Inputs...
+ {
+ "Name": "BRDFTextureInput",
+ "ShaderInputName": "m_brdfMap",
+ "SlotType": "Input",
+ "ScopeAttachmentUsage": "Shader"
+ },
+ {
+ "Name": "DirectionalLightShadowmap",
+ "ShaderInputName": "m_directionalLightShadowmap",
+ "SlotType": "Input",
+ "ScopeAttachmentUsage": "Shader",
+ "ImageViewDesc": {
+ "IsArray": 1
+ }
+ },
+ {
+ "Name": "ExponentialShadowmapDirectional",
+ "ShaderInputName": "m_directionalLightExponentialShadowmap",
+ "SlotType": "Input",
+ "ScopeAttachmentUsage": "Shader",
+ "ImageViewDesc": {
+ "IsArray": 1
+ }
+ },
+ {
+ "Name": "ProjectedShadowmap",
+ "ShaderInputName": "m_projectedShadowmaps",
+ "SlotType": "Input",
+ "ScopeAttachmentUsage": "Shader",
+ "ImageViewDesc": {
+ "IsArray": 1
+ }
+ },
+ {
+ "Name": "ExponentialShadowmapProjected",
+ "ShaderInputName": "m_projectedExponentialShadowmap",
+ "SlotType": "Input",
+ "ScopeAttachmentUsage": "Shader",
+ "ImageViewDesc": {
+ "IsArray": 1
+ }
+ },
+ {
+ "Name": "TileLightData",
+ "SlotType": "Input",
+ "ShaderInputName": "m_tileLightData",
+ "ScopeAttachmentUsage": "Shader"
+ },
+ {
+ "Name": "LightListRemapped",
+ "SlotType": "Input",
+ "ShaderInputName": "m_lightListRemapped",
+ "ScopeAttachmentUsage": "Shader"
+ },
+ // Input/Outputs...
+ {
+ "Name": "DepthStencilInputOutput",
+ "SlotType": "InputOutput",
+ "ScopeAttachmentUsage": "DepthStencil"
+ },
+ // Outputs...
+ {
+ "Name": "LightingOutput",
+ "SlotType": "Output",
+ "ScopeAttachmentUsage": "RenderTarget",
+ "LoadStoreAction": {
+ "ClearValue": {
+ "Value": [
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0
+ ]
+ },
+ "LoadAction": "Clear"
+ }
+ }
+ ],
+ "ImageAttachments": [
+ {
+ "Name": "LightingAttachment",
+ "SizeSource": {
+ "Source": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ },
+ "MultisampleSource": {
+ "Pass": "This",
+ "Attachment": "DepthStencilInputOutput"
+ },
+ "ImageDescriptor": {
+ "Format": "R16G16B16A16_FLOAT",
+ "SharedQueueMask": "Graphics"
+ }
+ },
+ {
+ "Name": "BRDFTexture",
+ "Lifetime": "Imported",
+ "AssetRef": {
+ "FilePath": "Textures/BRDFTexture.attimage"
+ }
+ }
+ ],
+ "Connections": [
+ {
+ "LocalSlot": "LightingOutput",
+ "AttachmentRef": {
+ "Pass": "This",
+ "Attachment": "LightingAttachment"
+ }
+ },
+ {
+ "LocalSlot": "BRDFTextureInput",
+ "AttachmentRef": {
+ "Pass": "This",
+ "Attachment": "BRDFTexture"
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass
new file mode 100644
index 0000000000..b19569fb9d
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass
@@ -0,0 +1,344 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "PassAsset",
+ "ClassData": {
+ "PassTemplate": {
+ "Name": "LowEndPipelineTemplate",
+ "PassClass": "ParentPass",
+ "Slots": [
+ {
+ "Name": "SwapChainOutput",
+ "SlotType": "InputOutput",
+ "ScopeAttachmentUsage": "RenderTarget"
+ }
+ ],
+ "PassRequests": [
+ {
+ "Name": "MorphTargetPass",
+ "TemplateName": "MorphTargetPassTemplate"
+ },
+ {
+ "Name": "SkinningPass",
+ "TemplateName": "SkinningPassTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "SkinnedMeshOutputStream",
+ "AttachmentRef": {
+ "Pass": "MorphTargetPass",
+ "Attachment": "MorphTargetDeltaOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "DepthPrePass",
+ "TemplateName": "DepthMSAAParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "SkinnedMeshes",
+ "AttachmentRef": {
+ "Pass": "SkinningPass",
+ "Attachment": "SkinnedMeshOutputStream"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "LightCullingPass",
+ "TemplateName": "LightCullingParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "SkinnedMeshes",
+ "AttachmentRef": {
+ "Pass": "SkinningPass",
+ "Attachment": "SkinnedMeshOutputStream"
+ }
+ },
+ {
+ "LocalSlot": "DepthMSAA",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "DepthMSAA"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ShadowPass",
+ "TemplateName": "ShadowParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "SkinnedMeshes",
+ "AttachmentRef": {
+ "Pass": "SkinningPass",
+ "Attachment": "SkinnedMeshOutputStream"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "ForwardPass",
+ "TemplateName": "LowEndForwardPassTemplate",
+ "Connections": [
+ // Inputs...
+ {
+ "LocalSlot": "DirectionalLightShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "ExponentialShadowmapDirectional",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalESM"
+ }
+ },
+ {
+ "LocalSlot": "ProjectedShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "ExponentialShadowmapProjected",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedESM"
+ }
+ },
+ {
+ "LocalSlot": "TileLightData",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "TileLightData"
+ }
+ },
+ {
+ "LocalSlot": "LightListRemapped",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "LightListRemapped"
+ }
+ },
+ // Input/Outputs...
+ {
+ "LocalSlot": "DepthStencilInputOutput",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "DepthMSAA"
+ }
+ }
+ ],
+ "PassData": {
+ "$type": "RasterPassData",
+ "DrawListTag": "lowEndForward",
+ "PipelineViewTag": "MainCamera",
+ "PassSrgAsset": {
+ "FilePath": "shaderlib/atom/features/pbr/forwardpasssrg.azsli:PassSrg"
+ }
+ }
+ },
+ {
+ "Name": "SkyBoxPass",
+ "TemplateName": "SkyBoxTemplate",
+ "Enabled": true,
+ "Connections": [
+ {
+ "LocalSlot": "SpecularInputOutput",
+ "AttachmentRef": {
+ "Pass": "ForwardPass",
+ "Attachment": "LightingOutput"
+ }
+ },
+ {
+ "LocalSlot": "SkyBoxDepth",
+ "AttachmentRef": {
+ "Pass": "ForwardPass",
+ "Attachment": "DepthStencilInputOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "MSAAResolvePass",
+ "TemplateName": "MSAAResolveColorTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "Input",
+ "AttachmentRef": {
+ "Pass": "SkyBoxPass",
+ "Attachment": "SpecularInputOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "TransparentPass",
+ "TemplateName": "TransparentParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "DirectionalShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "DirectionalESM",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalESM"
+ }
+ },
+ {
+ "LocalSlot": "ProjectedShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "ProjectedESM",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedESM"
+ }
+ },
+ {
+ "LocalSlot": "TileLightData",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "TileLightData"
+ }
+ },
+ {
+ "LocalSlot": "LightListRemapped",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "LightListRemapped"
+ }
+ },
+ {
+ "LocalSlot": "DepthStencil",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "Depth"
+ }
+ },
+ {
+ "LocalSlot": "InputOutput",
+ "AttachmentRef": {
+ "Pass": "MSAAResolvePass",
+ "Attachment": "Output"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "LightAdaptation",
+ "TemplateName": "LightAdaptationParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "LightingInput",
+ "AttachmentRef": {
+ "Pass": "TransparentPass",
+ "Attachment": "InputOutput"
+ }
+ },
+ {
+ "LocalSlot": "SwapChainOutput",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "AuxGeomPass",
+ "TemplateName": "AuxGeomPassTemplate",
+ "Enabled": true,
+ "Connections": [
+ {
+ "LocalSlot": "ColorInputOutput",
+ "AttachmentRef": {
+ "Pass": "LightAdaptation",
+ "Attachment": "Output"
+ }
+ },
+ {
+ "LocalSlot": "DepthInputOutput",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "Depth"
+ }
+ }
+ ],
+ "PassData": {
+ "$type": "RasterPassData",
+ "DrawListTag": "auxgeom",
+ "PipelineViewTag": "MainCamera"
+ }
+ },
+ {
+ "Name": "UIPass",
+ "TemplateName": "UIParentTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "InputOutput",
+ "AttachmentRef": {
+ "Pass": "AuxGeomPass",
+ "Attachment": "ColorInputOutput"
+ }
+ }
+ ]
+ },
+ {
+ "Name": "CopyToSwapChain",
+ "TemplateName": "FullscreenCopyTemplate",
+ "Connections": [
+ {
+ "LocalSlot": "Input",
+ "AttachmentRef": {
+ "Pass": "UIPass",
+ "Attachment": "InputOutput"
+ }
+ },
+ {
+ "LocalSlot": "Output",
+ "AttachmentRef": {
+ "Pass": "Parent",
+ "Attachment": "SwapChainOutput"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass
index dda120e164..a691fe2534 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass
+++ b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass
@@ -305,7 +305,7 @@
},
{
"Name": "SkyBoxPass",
- "TemplateName": "SkyBoxTemplate",
+ "TemplateName": "SkyBoxTwoOutputsTemplate",
"Enabled": true,
"Connections": [
{
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
index b83ab65ff2..c56e8932b1 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
+++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset
@@ -92,6 +92,10 @@
"Name": "SkyBoxTemplate",
"Path": "Passes/SkyBox.pass"
},
+ {
+ "Name": "SkyBoxTwoOutputsTemplate",
+ "Path": "Passes/SkyBox_TwoOutputs.pass"
+ },
{
"Name": "UIPassTemplate",
"Path": "Passes/UI.pass"
@@ -483,6 +487,18 @@
{
"Name": "UIParentTemplate",
"Path": "Passes/UIParent.pass"
+ },
+ {
+ "Name": "LightAdaptationParentTemplate",
+ "Path": "Passes/LightAdaptationParent.pass"
+ },
+ {
+ "Name": "LowEndForwardPassTemplate",
+ "Path": "Passes/LowEndForward.pass"
+ },
+ {
+ "Name": "LowEndPipelineTemplate",
+ "Path": "Passes/LowEndPipeline.pass"
}
]
}
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass
index 37b1ee5c5a..36f7f1e985 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass
+++ b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass
@@ -40,7 +40,7 @@
{
"LocalSlot": "Output",
"AttachmentRef": {
- "Pass": "DisplayMapperPass",
+ "Pass": "LightAdaptation",
"Attachment": "Output"
}
},
@@ -54,8 +54,8 @@
{
"LocalSlot": "LuminanceMipChainOutput",
"AttachmentRef": {
- "Pass": "DownsampleLuminanceMipChain",
- "Attachment": "MipChainInputOutput"
+ "Pass": "LightAdaptation",
+ "Attachment": "LuminanceMipChainOutput"
}
}
],
@@ -115,94 +115,16 @@
}
]
},
- // Everything before this point deals in raw lighting values
- // ---------------------------------------------------------
- // Everything after starts to map to values we see on screen
{
- "Name": "DownsampleLuminanceMinAvgMax",
- "TemplateName": "DownsampleLuminanceMinAvgMaxCS",
+ "Name": "LightAdaptation",
+ "TemplateName": "LightAdaptationParentTemplate",
"Connections": [
{
- "LocalSlot": "Input",
+ "LocalSlot": "LightingInput",
"AttachmentRef": {
"Pass": "BloomPass",
"Attachment": "InputOutput"
}
- }
- ]
- },
- {
- "Name": "DownsampleLuminanceMipChain",
- "TemplateName": "DownsampleMipChainTemplate",
- "Connections": [
- {
- "LocalSlot": "MipChainInputOutput",
- "AttachmentRef": {
- "Pass": "DownsampleLuminanceMinAvgMax",
- "Attachment": "Output"
- }
- }
- ],
- "PassData": {
- "$type": "DownsampleMipChainPassData",
- "ShaderAsset": {
- "FilePath": "Shaders/PostProcessing/DownsampleMinAvgMaxCS.shader"
- }
- }
- },
- {
- "Name": "EyeAdaptationPass",
- "TemplateName": "EyeAdaptationTemplate",
- "Enabled": false,
- "Connections": [
- {
- "LocalSlot": "SceneLuminanceInput",
- "AttachmentRef": {
- "Pass": "DownsampleLuminanceMipChain",
- "Attachment": "MipChainInputOutput"
- }
- }
- ]
- },
- {
- "Name": "LookModificationTransformPass",
- "TemplateName": "LookModificationTransformTemplate",
- "Enabled": true,
- "Connections": [
- {
- "LocalSlot": "Input",
- "AttachmentRef": {
- "Pass": "BloomPass",
- "Attachment": "InputOutput"
- }
- },
- {
- "LocalSlot": "EyeAdaptationDataInput",
- "AttachmentRef": {
- "Pass": "EyeAdaptationPass",
- "Attachment": "EyeAdaptationDataInputOutput"
- }
- },
- {
- "LocalSlot": "SwapChainOutput",
- "AttachmentRef": {
- "Pass": "Parent",
- "Attachment": "SwapChainOutput"
- }
- }
- ]
- },
- {
- "Name": "DisplayMapperPass",
- "TemplateName": "DisplayMapperTemplate",
- "Enabled": true,
- "Connections": [
- {
- "LocalSlot": "Input",
- "AttachmentRef": {
- "Pass": "LookModificationTransformPass",
- "Attachment": "Output"
- }
},
{
"LocalSlot": "SwapChainOutput",
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SkyBox.pass b/Gems/Atom/Feature/Common/Assets/Passes/SkyBox.pass
index 57f442e5de..fb16271ba7 100644
--- a/Gems/Atom/Feature/Common/Assets/Passes/SkyBox.pass
+++ b/Gems/Atom/Feature/Common/Assets/Passes/SkyBox.pass
@@ -12,11 +12,6 @@
"SlotType": "InputOutput",
"ScopeAttachmentUsage": "RenderTarget"
},
- {
- "Name": "ReflectionInputOutput",
- "SlotType": "InputOutput",
- "ScopeAttachmentUsage": "RenderTarget"
- },
{
"Name": "SkyBoxDepth",
"SlotType": "InputOutput",
diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SkyBox_TwoOutputs.pass b/Gems/Atom/Feature/Common/Assets/Passes/SkyBox_TwoOutputs.pass
new file mode 100644
index 0000000000..0ed7b39288
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Passes/SkyBox_TwoOutputs.pass
@@ -0,0 +1,43 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "PassAsset",
+ "ClassData": {
+ "PassTemplate": {
+ "Name": "SkyBoxTwoOutputsTemplate",
+ "PassClass": "FullScreenTriangle",
+ "Slots": [
+ {
+ "Name": "SpecularInputOutput",
+ "SlotType": "InputOutput",
+ "ScopeAttachmentUsage": "RenderTarget"
+ },
+ {
+ "Name": "ReflectionInputOutput",
+ "SlotType": "InputOutput",
+ "ScopeAttachmentUsage": "RenderTarget"
+ },
+ {
+ "Name": "SkyBoxDepth",
+ "SlotType": "InputOutput",
+ "ScopeAttachmentUsage": "DepthStencil"
+ }
+ ],
+ "PassData": {
+ "$type": "FullscreenTrianglePassData",
+ "ShaderAsset": {
+ "FilePath": "shaders/skybox/skybox_twooutputs.shader"
+ },
+ "PipelineViewTag": "MainCamera",
+ "ShaderDataMappings": {
+ "FloatMappings": [
+ {
+ "Name": "m_sunIntensityMultiplier",
+ "Value": 1.0
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli
index 50896cdf25..abc4ec7fc4 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli
@@ -31,6 +31,16 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId);
}
+ //[GFX TODO][ATOM-15280] Move wrinkle mask data from the default object srg into something specific to the Skin shader
+ uint m_wrinkle_mask_count;
+ float4 m_wrinkle_mask_weights[4];
+ Texture2D m_wrinkle_masks[16];
+
+ float GetWrinkleMaskWeight(uint index)
+ {
+ return m_wrinkle_mask_weights[index / 4][index % 4];
+ }
+
//! Reflection Probe (smallest probe volume that overlaps the object position)
struct ReflectionProbeData
{
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassOutput.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassOutput.azsli
index acc215f1c9..5821deb3b1 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassOutput.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassOutput.azsli
@@ -10,6 +10,21 @@
*
*/
+#ifdef UNIFIED_FORWARD_OUTPUT
+
+struct ForwardPassOutput
+{
+ float4 m_color : SV_Target0;
+};
+
+struct ForwardPassOutputWithDepth
+{
+ float4 m_color : SV_Target0;
+ float m_depth : SV_Depth;
+};
+
+#else
+
struct ForwardPassOutput
{
float4 m_diffuseColor : SV_Target0; //!< RGB = Diffuse Lighting, A = Blend Alpha (for blended surfaces) OR A = special encoding of surfaceScatteringFactor, m_subsurfaceScatteringQuality, o_enableSubsurfaceScattering
@@ -30,3 +45,5 @@ struct ForwardPassOutputWithDepth
float4 m_normal : SV_Target4;
float m_depth : SV_Depth;
};
+
+#endif
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli
index 7400005508..3be9d5756a 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli
@@ -12,38 +12,39 @@
#pragma once
+// --- Static Options Available ---
+// FORCE_IBL_IN_FORWARD_PASS - forces IBL lighting to be run in the forward pass, used in pipelines that don't have a reflection pass
+
#include
#include
#include
#include
-void ApplyIblDiffuse(
+float3 GetIblDiffuse(
float3 normal,
float3 albedo,
- float3 diffuseResponse,
- out float3 outDiffuse)
+ float3 diffuseResponse)
{
float3 irradianceDir = MultiplyVectorQuaternion(normal, SceneSrg::m_iblOrientation);
float3 diffuseSample = SceneSrg::m_diffuseEnvMap.Sample(SceneSrg::m_samplerEnv, GetCubemapCoords(irradianceDir)).rgb;
- outDiffuse = diffuseResponse * albedo * diffuseSample;
+ return diffuseResponse * albedo * diffuseSample;
}
-void ApplyIblSpecular(
+float3 GetIblSpecular(
float3 position,
float3 normal,
float3 specularF0,
float roughnessLinear,
float3 dirToCamera,
- float2 brdf,
- out float3 outSpecular)
+ float2 brdf)
{
float3 reflectDir = reflect(-dirToCamera, normal);
reflectDir = MultiplyVectorQuaternion(reflectDir, SceneSrg::m_iblOrientation);
// global
- outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
+ float3 outSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughnessLinear)).rgb;
outSpecular *= (specularF0 * brdf.x + brdf.y);
// reflection probe
@@ -72,86 +73,55 @@ void ApplyIblSpecular(
outSpecular = lerp(outSpecular, probeSpecular, blendAmount);
}
+ return outSpecular;
}
void ApplyIBL(Surface surface, inout LightingData lightingData)
{
- if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
+#ifdef FORCE_IBL_IN_FORWARD_PASS
+ bool useDiffuseIbl = true;
+ bool useSpecularIbl = true;
+ bool useIbl = o_enableIBL;
+#else
+ bool isTransparent = (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent);
+ bool useDiffuseIbl = isTransparent;
+ bool useSpecularIbl = (isTransparent || o_meshUseForwardPassIBLSpecular || o_materialUseForwardPassIBLSpecular);
+ bool useIbl = o_enableIBL && (useDiffuseIbl || useSpecularIbl);
+#endif
+
+ if(useIbl)
{
- // transparencies currently require IBL in the forward pass
- if (o_enableIBL)
+ float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
+
+ if(useDiffuseIbl)
{
- float3 iblDiffuse = 0.0f;
- ApplyIblDiffuse(
- surface.normal,
- surface.albedo,
- lightingData.diffuseResponse,
- iblDiffuse);
-
- float3 iblSpecular = 0.0f;
- ApplyIblSpecular(
- surface.position,
- surface.normal,
- surface.specularF0,
- surface.roughnessLinear,
- lightingData.dirToCamera,
- lightingData.brdf,
- iblSpecular);
-
- // Adjust IBL lighting by exposure.
- float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
+ float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse);
lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.diffuseAmbientOcclusion);
- 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.dirToCamera,
- lightingData.brdf,
- iblSpecular);
+ if(useSpecularIbl)
+ {
+ float3 iblSpecular = GetIblSpecular(surface.position, surface.normal, surface.specularF0, surface.roughnessLinear, lightingData.dirToCamera, lightingData.brdf);
iblSpecular *= lightingData.multiScatterCompensation;
- if (o_clearCoat_feature_enabled)
+ if (o_clearCoat_feature_enabled && surface.clearCoat.factor > 0.0f)
{
- if (surface.clearCoat.factor > 0.0f)
- {
- float clearCoatNdotV = saturate(dot(surface.clearCoat.normal, lightingData.dirToCamera));
- clearCoatNdotV = max(clearCoatNdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
- float2 clearCoatBrdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(surface.clearCoat.roughness, clearCoatNdotV)).rg;
+ float clearCoatNdotV = saturate(dot(surface.clearCoat.normal, lightingData.dirToCamera));
+ clearCoatNdotV = max(clearCoatNdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
+ float2 clearCoatBrdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(surface.clearCoat.roughness, clearCoatNdotV)).rg;
- // clear coat uses fixed IOR = 1.5 represents polyurethane which is the most common material for gloss clear coat
- // coat layer assumed to be dielectric thus don't need multiple scattering compensation
- float3 clearCoatSpecularF0 = float3(0.04f, 0.04f, 0.04f);
- float3 clearCoatIblSpecular = 0.0f;
+ // clear coat uses fixed IOR = 1.5 represents polyurethane which is the most common material for gloss clear coat
+ // coat layer assumed to be dielectric thus don't need multiple scattering compensation
+ float3 clearCoatSpecularF0 = float3(0.04f, 0.04f, 0.04f);
+ float3 clearCoatIblSpecular = GetIblSpecular(surface.position, surface.clearCoat.normal, clearCoatSpecularF0, surface.clearCoat.roughness, lightingData.dirToCamera, clearCoatBrdf);
- ApplyIblSpecular(
- surface.position,
- surface.clearCoat.normal,
- clearCoatSpecularF0,
- surface.clearCoat.roughness,
- lightingData.dirToCamera,
- clearCoatBrdf,
- clearCoatIblSpecular);
-
- clearCoatIblSpecular *= surface.clearCoat.factor;
+ clearCoatIblSpecular *= surface.clearCoat.factor;
- // attenuate base layer energy
- float3 clearCoatResponse = FresnelSchlickWithRoughness(clearCoatNdotV, clearCoatSpecularF0, surface.clearCoat.roughness) * surface.clearCoat.factor;
- iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular;
- }
+ // attenuate base layer energy
+ float3 clearCoatResponse = FresnelSchlickWithRoughness(clearCoatNdotV, clearCoatSpecularF0, surface.clearCoat.roughness) * surface.clearCoat.factor;
+ iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular;
}
-
- float iblExposureFactor = pow(2.0f, SceneSrg::m_iblExposure);
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
}
}
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ShaderQualityOptions.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ShaderQualityOptions.azsli
new file mode 100644
index 0000000000..cc4aa7cf42
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ShaderQualityOptions.azsli
@@ -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
+
+// This file translates quality option macros like QUALITY_LOW_END to their relevant settings
+
+#ifdef QUALITY_LOW_END
+
+ // Unifies the forward output into a single lighting buffer instead of splitting it into a GBuffer
+ #define UNIFIED_FORWARD_OUTPUT 1
+
+ // Forces IBL lighting to be executed in the forward pass instead of subsequent refleciton passes
+ #define FORCE_IBL_IN_FORWARD_PASS 1
+
+#endif
+
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox.azsl
index 1ee30a4f98..1bebb2ec47 100644
--- a/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox.azsl
@@ -10,6 +10,9 @@
*
*/
+// --- Static Options Available ---
+// SKYBOX_TWO_OUTPUTS - Skybox renders to two rendertargets instead of one (SkyBox_TwoOutputs.pass writes to specular and reflection targets)
+
#include
#include
#include
@@ -102,7 +105,9 @@ float3 GetCubemapCoords(float3 original)
struct PSOutput
{
float4 m_specular : SV_Target0;
+#ifdef SKYBOX_TWO_OUTPUTS
float4 m_reflection : SV_Target1;
+#endif
};
PSOutput MainPS(VSOutput input)
@@ -163,6 +168,8 @@ PSOutput MainPS(VSOutput input)
PSOutput OUT;
OUT.m_specular = float4(color, 1.0);
+#ifdef SKYBOX_TWO_OUTPUTS
OUT.m_reflection = float4(color, 1.0);
+#endif
return OUT;
}
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.azsl
new file mode 100644
index 0000000000..feacd2f44f
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.azsl
@@ -0,0 +1,17 @@
+/*
+* 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.
+*
+*/
+
+// NOTE: This file is a temporary workaround until .shader files can #define macros for their .azsl files
+
+#define SKYBOX_TWO_OUTPUTS
+
+#include "SkyBox.azsl"
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.shader b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.shader
new file mode 100644
index 0000000000..ec80d4a20e
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkyBox/SkyBox_TwoOutputs.shader
@@ -0,0 +1,22 @@
+{
+ "Source" : "SkyBox_TwoOutputs",
+
+ "DepthStencilState" : {
+ "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
+ },
+
+ "ProgramSettings":
+ {
+ "EntryPoints":
+ [
+ {
+ "name": "MainVS",
+ "type": "Vertex"
+ },
+ {
+ "name": "MainPS",
+ "type": "Fragment"
+ }
+ ]
+ }
+}
diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
index 84ef494216..f1d8fa81be 100644
--- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
+++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
@@ -38,6 +38,7 @@ set(FILES
Materials/Types/StandardMultilayerPBR_ForwardPass_EDS.shader
Materials/Types/StandardMultilayerPBR_Parallax.lua
Materials/Types/StandardMultilayerPBR_ParallaxPerLayer.lua
+ Materials/Types/StandardMultilayerPBR_ShaderEnable.lua
Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.azsl
Materials/Types/StandardMultilayerPBR_Shadowmap_WithPS.shader
Materials/Types/StandardPBR.materialtype
@@ -52,6 +53,9 @@ set(FILES
Materials/Types/StandardPBR_ForwardPass_EDS.shader
Materials/Types/StandardPBR_HandleOpacityDoubleSided.lua
Materials/Types/StandardPBR_HandleOpacityMode.lua
+ Materials/Types/StandardPBR_LowEndForward.azsl
+ Materials/Types/StandardPBR_LowEndForward.shader
+ Materials/Types/StandardPBR_LowEndForward_EDS.shader
Materials/Types/StandardPBR_ParallaxState.lua
Materials/Types/StandardPBR_Roughness.lua
Materials/Types/StandardPBR_ShaderEnable.lua
@@ -116,6 +120,7 @@ set(FILES
Passes/DiffuseProbeGridBlendDistance.pass
Passes/DiffuseProbeGridBlendIrradiance.pass
Passes/DiffuseProbeGridBorderUpdate.pass
+ Passes/DiffuseProbeGridClassification.pass
Passes/DiffuseProbeGridDownsample.pass
Passes/DiffuseProbeGridRayTracing.pass
Passes/DiffuseProbeGridRelocation.pass
@@ -144,6 +149,7 @@ set(FILES
Passes/FullscreenCopy.pass
Passes/FullscreenOutputOnly.pass
Passes/ImGui.pass
+ Passes/LightAdaptationParent.pass
Passes/LightCulling.pass
Passes/LightCullingHeatmap.pass
Passes/LightCullingParent.pass
@@ -152,6 +158,8 @@ set(FILES
Passes/LightCullingTilePrepareMSAA.pass
Passes/LookModificationComposite.pass
Passes/LookModificationTransform.pass
+ Passes/LowEndForward.pass
+ Passes/LowEndPipeline.pass
Passes/LuminanceHeatmap.pass
Passes/LuminanceHistogramGenerator.pass
Passes/MainPipeline.pass
@@ -179,13 +187,16 @@ set(FILES
Passes/ReflectionScreenSpace.pass
Passes/ReflectionScreenSpaceBlur.pass
Passes/ReflectionScreenSpaceBlurHorizontal.pass
+ Passes/ReflectionScreenSpaceBlurMobile.pass
Passes/ReflectionScreenSpaceBlurVertical.pass
Passes/ReflectionScreenSpaceComposite.pass
+ Passes/ReflectionScreenSpaceMobile.pass
Passes/ReflectionScreenSpaceTrace.pass
Passes/Reflections_nomsaa.pass
Passes/ShadowParent.pass
Passes/Skinning.pass
Passes/SkyBox.pass
+ Passes/SkyBox_TwoOutputs.pass
Passes/SMAA1xApplyLinearHDRColor.pass
Passes/SMAA1xApplyPerceptualColor.pass
Passes/SMAABlendingWeightCalculation.pass
@@ -205,6 +216,7 @@ set(FILES
ShaderLib/Atom/Features/IndirectRendering.azsli
ShaderLib/Atom/Features/MatrixUtility.azsli
ShaderLib/Atom/Features/ParallaxMapping.azsli
+ ShaderLib/Atom/Features/ShaderQualityOptions.azsli
ShaderLib/Atom/Features/SphericalHarmonicsUtility.azsli
ShaderLib/Atom/Features/SrgSemantics.azsli
ShaderLib/Atom/Features/ColorManagement/TransformColor.azsli
@@ -272,6 +284,7 @@ set(FILES
ShaderLib/Atom/Features/PostProcessing/GlyphData.azsli
ShaderLib/Atom/Features/PostProcessing/GlyphRender.azsli
ShaderLib/Atom/Features/PostProcessing/PostProcessUtil.azsli
+ ShaderLib/Atom/Features/RayTracing/RayTracingSceneSrg.azsli
ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli
ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli
ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
@@ -471,4 +484,6 @@ set(FILES
Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli
Shaders/SkyBox/SkyBox.azsl
Shaders/SkyBox/SkyBox.shader
+ Shaders/SkyBox/SkyBox_TwoOutputs.azsl
+ Shaders/SkyBox/SkyBox_TwoOutputs.shader
)
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h
index a89653c359..03fbb93923 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h
@@ -60,6 +60,12 @@ namespace AZ
: public DisplayMapperFeatureProcessorInterface
{
public:
+ enum OutputDeviceTransformFlags
+ {
+ AlterSurround = 0x1, // Apply gamma adjustment to compensate for dim surround
+ ApplyDesaturation = 0x2, // Apply desaturation to compensate for luminance difference
+ ApplyCATD60toD65 = 0x4, // Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point
+ };
AZ_RTTI(AZ::Render::AcesDisplayMapperFeatureProcessor, "{995C2B93-8B08-4313-89B0-02394F90F1B8}", AZ::Render::DisplayMapperFeatureProcessorInterface);
@@ -92,12 +98,6 @@ namespace AZ
static void ApplyLdrOdtParameters(DisplayMapperParameters* pOutParameters);
static void ApplyHdrOdtParameters(DisplayMapperParameters* pOutParameters, const OutputDeviceTransformType& odtType);
- enum OutputDeviceTransformFlags {
- AlterSurround = 0x1, // Apply gamma adjustment to compensate for dim surround
- ApplyDesaturation = 0x2, // Apply desaturation to compensate for luminance difference
- ApplyCATD60toD65 = 0x4, // Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point
- };
-
enum OutputDeviceTransformMode {
Srgb = 0,
PerceptualQuantizer,
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h
index 5fce71fc07..5a0ccdb32a 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h
@@ -46,6 +46,7 @@ namespace AZ
static RPI::Ptr Create(const RPI::PassDescriptor& descriptor);
void SetDisplayBufferFormat(RHI::Format format);
+ void SetAcesParameterOverrides(const AcesParameterOverrides& acesParameterOverrides);
private:
explicit AcesOutputTransformPass(const RPI::PassDescriptor& descriptor);
@@ -65,6 +66,8 @@ namespace AZ
AZ::Render::DisplayMapperParameters m_displayMapperParameters = {};
RHI::Format m_displayBufferFormat = RHI::Format::Unknown;
+
+ AcesParameterOverrides m_acesParameterOverrides;
};
} // namespace Render
} // namespace AZ
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h
index b645df4f6f..4dc090b831 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h
@@ -24,6 +24,48 @@ namespace AZ
namespace Render
{
+ /**
+ * The ACES display mapper parameter overrides.
+ * These parameters override default ACES parameters when m_overrideDefaults is true.
+ */
+ struct AcesParameterOverrides final
+ {
+ AZ_TYPE_INFO(AcesParameterOverrides, "{3EE8C0D4-3792-46C0-B91C-B89A81C36B91}");
+ static void Reflect(ReflectContext* context);
+
+ void LoadPreset();
+
+ // When enabled allows parameter overrides for ACES configuration
+ bool m_overrideDefaults = false;
+
+ // Apply gamma adjustment to compensate for dim surround
+ bool m_alterSurround = true;
+ // Apply desaturation to compensate for luminance difference
+ bool m_applyDesaturation = true;
+ // Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point
+ bool m_applyCATD60toD65 = true;
+
+ // Reference white and black luminance values
+ float m_cinemaLimitsBlack = 0.02f;
+ float m_cinemaLimitsWhite = 48.0f;
+
+ // luminance linear extension below this
+ float m_minPoint = 0.0028798957f;
+ // luminance mid grey
+ float m_midPoint = 4.8f;
+ // luminance linear extension above this
+ float m_maxPoint = 1005.71912f;
+
+ // Gamma adjustment to be applied to compensate for the condition of the viewing environment.
+ // Note that ACES uses a value of 0.9811 for adjusting from dark to dim surrounding.
+ float m_surroundGamma = 0.9811f;
+ // Optional gamma value that is applied as basic gamma curve OETF
+ float m_gamma = 2.2f;
+
+ // Allows specifying default preset for different ODT modes
+ OutputDeviceTransformType m_preset = OutputDeviceTransformType_48Nits;
+ };
+
//! A descriptor used to configure the DisplayMapper
struct DisplayMapperConfigurationDescriptor final
{
@@ -37,6 +79,8 @@ namespace AZ
bool m_ldrGradingLutEnabled = false;
Data::Asset m_ldrColorGradingLut;
+
+ AcesParameterOverrides m_acesParameterOverrides;
};
//! Custom pass data for DisplayMapperPass.
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
index 7875e38fc0..0d61ef82d1 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
@@ -148,6 +148,8 @@ namespace AZ
Data::Instance GetModel(const MeshHandle& meshHandle) const override;
Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override;
+ Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const override;
+ void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override;
const MaterialAssignmentMap& GetMaterialAssignmentMap(const MeshHandle& meshHandle) const override;
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
index c2360068de..fb5bff5584 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
@@ -61,6 +61,14 @@ namespace AZ
virtual Data::Instance GetModel(const MeshHandle& meshHandle) const = 0;
//! Gets the underlying RPI::ModelAsset for a meshHandle.
virtual Data::Asset GetModelAsset(const MeshHandle& meshHandle) const = 0;
+ //! Gets the ObjectSrg for a meshHandle.
+ //! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile,
+ //! instead of compiling the srg directly. This way, if the srg has already been queued for compile,
+ //! it will not be queued twice in the same frame. The ObjectSrg should not be updated during
+ //! Simulate, or it will create a race between updating the data and the call to Compile
+ virtual Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const = 0;
+ //! Queues the object srg for compile.
+ virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0;
//! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId.
//! Note if there is already a material assignment map, this will replace the entire map with just a single material.
virtual void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) = 0;
diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
index 39fd7b4380..418ee0cfb8 100644
--- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
@@ -23,6 +23,8 @@ namespace UnitTest
MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&));
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&));
MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&));
+ MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr(const MeshHandle&));
+ MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
MOCK_METHOD3(SetTransform, void(const MeshHandle&, const AZ::Transform&, const AZ::Vector3&));
diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp
index b2103739ba..6fe38ff032 100644
--- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp
@@ -102,6 +102,36 @@ namespace AZ
AcesDisplayMapperFeatureProcessor::GetAcesDisplayMapperParameters(&m_displayMapperParameters, OutputDeviceTransformType_48Nits);
}
}
+
+ if (m_acesParameterOverrides.m_overrideDefaults)
+ {
+ m_displayMapperParameters.m_OutputDisplayTransformFlags = 0;
+ if (m_acesParameterOverrides.m_alterSurround)
+ {
+ m_displayMapperParameters.m_OutputDisplayTransformFlags |= AcesDisplayMapperFeatureProcessor::AlterSurround;
+ }
+ if (m_acesParameterOverrides.m_applyDesaturation)
+ {
+ m_displayMapperParameters.m_OutputDisplayTransformFlags |= AcesDisplayMapperFeatureProcessor::ApplyDesaturation;
+ }
+ if (m_acesParameterOverrides.m_applyCATD60toD65)
+ {
+ m_displayMapperParameters.m_OutputDisplayTransformFlags |= AcesDisplayMapperFeatureProcessor::ApplyCATD60toD65;
+ }
+
+ m_displayMapperParameters.m_cinemaLimits[0] = m_acesParameterOverrides.m_cinemaLimitsBlack;
+ m_displayMapperParameters.m_cinemaLimits[1] = m_acesParameterOverrides.m_cinemaLimitsWhite;
+ m_displayMapperParameters.m_acesSplineParams.minPoint[0] = m_acesParameterOverrides.m_minPoint;
+ m_displayMapperParameters.m_acesSplineParams.midPoint[0] = m_acesParameterOverrides.m_midPoint;
+ m_displayMapperParameters.m_acesSplineParams.maxPoint[0] = m_acesParameterOverrides.m_maxPoint;
+ m_displayMapperParameters.m_surroundGamma = m_acesParameterOverrides.m_surroundGamma;
+ m_displayMapperParameters.m_gamma = m_acesParameterOverrides.m_gamma;
+ }
+ }
+
+ void AcesOutputTransformPass::SetAcesParameterOverrides(const AcesParameterOverrides& acesParameterOverrides)
+ {
+ m_acesParameterOverrides = acesParameterOverrides;
}
} // namespace Render
} // namespace AZ
diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
index d80a02d083..e91e125b40 100644
--- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp
@@ -9,14 +9,54 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
+
#include
#include
+#include
namespace AZ
{
namespace Render
{
+ void AcesParameterOverrides::Reflect(ReflectContext* context)
+ {
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()
+ ->Version(0)
+ ->Field("OverrideDefaults", &AcesParameterOverrides::m_overrideDefaults)
+ ->Field("AlterSurround", &AcesParameterOverrides::m_alterSurround)
+ ->Field("ApplyDesaturation", &AcesParameterOverrides::m_applyDesaturation)
+ ->Field("ApplyCATD60toD65", &AcesParameterOverrides::m_applyCATD60toD65)
+ ->Field("PresetODT", &AcesParameterOverrides::m_preset)
+ ->Field("CinemaLimitsBlack", &AcesParameterOverrides::m_cinemaLimitsBlack)
+ ->Field("CinemaLimitsWhite", &AcesParameterOverrides::m_cinemaLimitsWhite)
+ ->Field("MinPoint", &AcesParameterOverrides::m_minPoint)
+ ->Field("MidPoint", &AcesParameterOverrides::m_midPoint)
+ ->Field("MaxPoint", &AcesParameterOverrides::m_maxPoint)
+ ->Field("SurroundGamma", &AcesParameterOverrides::m_surroundGamma)
+ ->Field("Gamma", &AcesParameterOverrides::m_gamma);
+ }
+ }
+
+ void AcesParameterOverrides::LoadPreset()
+ {
+ DisplayMapperParameters displayMapperParameters;
+ AcesDisplayMapperFeatureProcessor::GetAcesDisplayMapperParameters(&displayMapperParameters, m_preset);
+
+ m_alterSurround = (displayMapperParameters.m_OutputDisplayTransformFlags & AcesDisplayMapperFeatureProcessor::AlterSurround) != 0;
+ m_applyDesaturation = (displayMapperParameters.m_OutputDisplayTransformFlags & AcesDisplayMapperFeatureProcessor::ApplyDesaturation) != 0;
+ m_applyCATD60toD65 = (displayMapperParameters.m_OutputDisplayTransformFlags & AcesDisplayMapperFeatureProcessor::ApplyCATD60toD65) != 0;
+ m_cinemaLimitsBlack = displayMapperParameters.m_cinemaLimits[0];
+ m_cinemaLimitsWhite = displayMapperParameters.m_cinemaLimits[1];
+ m_minPoint = displayMapperParameters.m_acesSplineParams.minPoint[0];
+ m_midPoint = displayMapperParameters.m_acesSplineParams.midPoint[0];
+ m_maxPoint = displayMapperParameters.m_acesSplineParams.maxPoint[0];
+ m_surroundGamma = displayMapperParameters.m_surroundGamma;
+ m_gamma = displayMapperParameters.m_gamma;
+ }
+
void DisplayMapperConfigurationDescriptor::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast(context))
diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp
index 1de92c42f6..8ae790e12c 100644
--- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp
@@ -106,6 +106,7 @@ namespace AZ
{
if (m_acesOutputTransformPass)
{
+ m_acesOutputTransformPass->SetAcesParameterOverrides(m_displayMapperConfigurationDescriptor.m_acesParameterOverrides);
m_acesOutputTransformPass->SetDisplayBufferFormat(m_displayBufferFormat);
}
if (m_bakeAcesOutputTransformLutPass)
@@ -509,7 +510,8 @@ namespace AZ
if (desc.m_operationType != m_displayMapperConfigurationDescriptor.m_operationType ||
desc.m_ldrGradingLutEnabled != m_displayMapperConfigurationDescriptor.m_ldrGradingLutEnabled ||
- desc.m_ldrColorGradingLut != m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut)
+ desc.m_ldrColorGradingLut != m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut ||
+ desc.m_acesParameterOverrides.m_overrideDefaults != m_displayMapperConfigurationDescriptor.m_acesParameterOverrides.m_overrideDefaults)
{
m_needToRebuildChildren = true;
}
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index 29f0636e9e..4059d65cbb 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -231,6 +231,19 @@ namespace AZ
return {};
}
+ Data::Instance MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const
+ {
+ return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr;
+ }
+
+ void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
+ {
+ if (meshHandle.IsValid())
+ {
+ meshHandle->m_objectSrgNeedsUpdate = true;
+ }
+ }
+
void MeshFeatureProcessor::SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material)
{
Render::MaterialAssignmentMap materials;
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
index 388f4112a0..cb2d6a69ef 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
@@ -71,16 +71,6 @@ namespace AZ
}
- void SkinnedMeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
- {
- AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
- AZ_ATOM_PROFILE_FUNCTION("SkinnedMesh", "SkinnedMeshFeatureProcessor: Simulate");
- AZ_UNUSED(packet);
-
- SkinnedMeshFeatureProcessorNotificationBus::Broadcast(&SkinnedMeshFeatureProcessorNotificationBus::Events::OnUpdateSkinningMatrices);
-
- }
-
void SkinnedMeshFeatureProcessor::Render(const FeatureProcessor::RenderPacket& packet)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
@@ -268,6 +258,8 @@ namespace AZ
void SkinnedMeshFeatureProcessor::OnBeginPrepareRender()
{
m_renderProxiesChecker.soft_lock();
+
+ SkinnedMeshFeatureProcessorNotificationBus::Broadcast(&SkinnedMeshFeatureProcessorNotificationBus::Events::OnUpdateSkinningMatrices);
}
void SkinnedMeshFeatureProcessor::OnRenderEnd()
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h
index bb3dd242a1..75d41742b2 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h
@@ -49,7 +49,6 @@ namespace AZ
// FeatureProcessor overrides ...
void Activate() override;
void Deactivate() override;
- void Simulate(const FeatureProcessor::SimulatePacket& packet) override;
void Render(const FeatureProcessor::RenderPacket& packet) override;
void OnRenderEnd() override;
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h
index b0d6bd4117..1cba71ae7e 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h
@@ -381,6 +381,7 @@ namespace AZ
uint64_t m_createdByPassRequest : 1;
uint64_t m_initialized : 1;
uint64_t m_enabled : 1;
+ uint64_t m_parentEnabled : 1;
uint64_t m_alreadyCreated : 1;
uint64_t m_alreadyReset : 1;
uint64_t m_alreadyPrepared : 1;
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/MorphTargetMetaAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/MorphTargetMetaAsset.h
index 5b92047226..4aa3faa6c9 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/MorphTargetMetaAsset.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/MorphTargetMetaAsset.h
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
namespace AZ::RPI
{
@@ -56,6 +57,9 @@ namespace AZ::RPI
float m_minPositionDelta;
float m_maxPositionDelta;
+ //! Reference to the wrinkle mask, if it exists
+ AZ::Data::Asset m_wrinkleMask;
+
//! Boolean to indicate the presence or absence of color deltas
bool m_hasColorDeltas = false;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp
index 7aace50760..3d0cbca8e6 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp
@@ -18,6 +18,9 @@
#include
#include
+#include
+#include
+
namespace AZ::RPI
{
using namespace AZ::SceneAPI;
@@ -114,7 +117,7 @@ namespace AZ::RPI
meshNodeName, sourceMesh.m_name.GetCStr());
const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex);
- BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter);
+ BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename());
}
}
}
@@ -157,7 +160,8 @@ namespace AZ::RPI
const AZStd::string& blendShapeName,
const AZStd::shared_ptr& blendShapeData,
const DataTypes::MatrixType& globalTransform,
- const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter)
+ const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter,
+ const AZStd::string& sourceSceneFilename)
{
const float tolerance = CalcPositionDeltaTolerance(sourceMesh);
AZ::Aabb deltaPositionAabb = AZ::Aabb::CreateNull();
@@ -288,6 +292,8 @@ namespace AZ::RPI
metaData.m_maxPositionDelta = maxValue;
}
+ metaData.m_wrinkleMask = GetWrinkleMask(sourceSceneFilename, blendShapeName);
+
metaAssetCreator.AddMorphTarget(metaData);
AZ_Assert(uncompressedPositionDeltas.size() == compressedDeltas.size(), "Number of uncompressed (%d) and compressed position delta components (%d) do not match.",
@@ -312,4 +318,47 @@ namespace AZ::RPI
AZ_Assert((packedCompressedMorphTargetVertexData.size() - metaData.m_startIndex) == numMorphedVertices, "Vertex index range (%d) in morph target meta data does not match number of morphed vertices (%d).",
packedCompressedMorphTargetVertexData.size() - metaData.m_startIndex, numMorphedVertices);
}
+
+ Data::Asset MorphTargetExporter::GetWrinkleMask(const AZStd::string& sourceSceneFullFilePath, const AZStd::string& blendShapeName) const
+ {
+ AZ::Data::Asset imageAsset;
+
+ // See if there is a wrinkle map mask for this mesh
+ AZStd::string sceneRelativeFilePath;
+ bool relativePathFound = true;
+ AzToolsFramework::AssetSystemRequestBus::BroadcastResult(relativePathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetRelativeProductPathFromFullSourceOrProductPath, sourceSceneFullFilePath, sceneRelativeFilePath);
+
+ if (relativePathFound)
+ {
+ AZ::StringFunc::Path::StripFullName(sceneRelativeFilePath);
+
+ // Get the folder the masks are supposed to be in
+ AZStd::string folderName;
+ AZ::StringFunc::Path::GetFileName(sourceSceneFullFilePath.c_str(), folderName);
+ folderName += "_wrinklemasks";
+
+ // Note: for now, we're assuming the mask is always authored as a .tif
+ AZStd::string blendMaskFileName = blendShapeName + "_wrinklemask.tif.streamingimage";
+
+ AZStd::string maskFolderAndFile;
+ AZ::StringFunc::Path::Join(folderName.c_str(), blendMaskFileName.c_str(), maskFolderAndFile);
+
+ AZStd::string maskRelativePath;
+ AZ::StringFunc::Path::Join(sceneRelativeFilePath.c_str(), maskFolderAndFile.c_str(), maskRelativePath);
+ AZ::StringFunc::Path::Normalize(maskRelativePath);
+
+ // Now see if the file exists
+ AZ::Data::AssetId maskAssetId;
+ Data::AssetCatalogRequestBus::BroadcastResult(maskAssetId, &Data::AssetCatalogRequests::GetAssetIdByPath, maskRelativePath.c_str(), AZ::Data::s_invalidAssetType, false);
+
+ if (maskAssetId.IsValid())
+ {
+ // Flush asset manager events to ensure no asset references are held by closures queued on Ebuses.
+ AZ::Data::AssetManager::Instance().DispatchEvents();
+
+ imageAsset.Create(maskAssetId, AZ::Data::AssetLoadBehavior::PreLoad, false);
+ }
+ }
+ return imageAsset;
+ }
} // namespace AZ::RPI
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h
index d968a803d6..4845d7d1da 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h
+++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h
@@ -64,7 +64,11 @@ namespace AZ
const AZStd::string& blendShapeName,
const AZStd::shared_ptr& blendShapeData,
const AZ::SceneAPI::DataTypes::MatrixType& globalTransform,
- const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter);
+ const AZ::SceneAPI::CoordinateSystemConverter& coordSysConverter,
+ const AZStd::string& sourceSceneFilename);
+
+ // Find a wrinkle mask for this morph target, if it exists
+ Data::Asset GetWrinkleMask(const AZStd::string& sourceSceneFullFilePath, const AZStd::string& blendShapeName) const;
};
} // namespace RPI
} // namespace AZ
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp
index 2ab6ee92e9..109af70166 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp
@@ -422,7 +422,7 @@ namespace AZ
const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex);
AZ::Name enumName = AZ::Name(property.m_value.GetValue());
- uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
+ uint32_t enumValue = propertyDescriptor ? propertyDescriptor->GetEnumValue(enumName) : MaterialPropertyDescriptor::InvalidEnumValue;
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
{
materialTypeAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp
index 9401d1a9e0..6ed8ac018c 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp
@@ -93,11 +93,12 @@ namespace AZ
void Pass::SetEnabled(bool enabled)
{
m_flags.m_enabled = enabled;
+ OnHierarchyChange();
}
bool Pass::IsEnabled() const
{
- return m_flags.m_enabled;
+ return m_flags.m_enabled && (m_flags.m_parentEnabled || m_parent == nullptr);
}
// --- Error Logging ---
@@ -140,6 +141,7 @@ namespace AZ
}
// Set new tree depth and path
+ m_flags.m_parentEnabled = m_parent->m_flags.m_enabled && (m_parent->m_flags.m_parentEnabled || m_parent->m_parent == nullptr);
m_treeDepth = m_parent->m_treeDepth + 1;
m_path = ConcatPassName(m_parent->m_path, m_name);
m_flags.m_partOfHierarchy = m_parent->m_flags.m_partOfHierarchy;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp
index 1fad385fa6..3f5c16678c 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp
@@ -163,6 +163,11 @@ namespace AZ
binding.m_shaderInputIndex = idx.IsValid() ? static_cast(idx.GetIndex()) : PassAttachmentBinding::ShaderInputNoBind;
}
}
+ else
+ {
+ AZ_Error("Pass System", false, "[Pass %s] Could not bind shader buffer index '%s' because it has no attachment.", GetName().GetCStr(), shaderName.GetCStr());
+ binding.m_shaderInputIndex = PassAttachmentBinding::ShaderInputNoBind;
+ }
}
}
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp
index 313e0bea31..3c0f832807 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp
@@ -28,6 +28,7 @@ namespace AZ::RPI
->Field("numVertices", &MorphTargetMetaAsset::MorphTarget::m_numVertices)
->Field("minPositionDelta", &MorphTargetMetaAsset::MorphTarget::m_minPositionDelta)
->Field("maxPositionDelta", &MorphTargetMetaAsset::MorphTarget::m_maxPositionDelta)
+ ->Field("wrinkleMask", &MorphTargetMetaAsset::MorphTarget::m_wrinkleMask)
->Field("hasColorDeltas", &MorphTargetMetaAsset::MorphTarget::m_hasColorDeltas)
;
}
diff --git a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/001_lucy_regression_test.material b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/001_lucy_regression_test.material
index f43f6d0808..c359fea3b5 100644
--- a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/001_lucy_regression_test.material
+++ b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/001_lucy_regression_test.material
@@ -11,7 +11,7 @@
0.29372090101242068,
1.0
],
- "textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png",
"useTexture": false
},
"detailLayerGroup": {
@@ -30,7 +30,7 @@
},
"normal": {
"flipY": true,
- "textureMap": "Objects/Lucy/Lucy_normal.tif"
+ "textureMap": "Objects/Lucy/Lucy_normal.png"
},
"subsurfaceScattering": {
"enableSubsurfaceScattering": true,
diff --git a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material
index c611b992b6..ce42f32b67 100644
--- a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material
+++ b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material
@@ -29,7 +29,7 @@
},
"normal": {
"flipY": true,
- "textureMap": "Objects/Lucy/Lucy_normal.tif"
+ "textureMap": "Objects/Lucy/Lucy_normal.png"
},
"subsurfaceScattering": {
"enableSubsurfaceScattering": true,
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material
index 2c711a3bf3..7b1f0ba6a9 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material
@@ -5,20 +5,20 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
- "textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png",
"textureMapUv": "Unwrapped"
},
"metallic": {
- "textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
- "textureMap": "Objects/Lucy/Lucy_normal.tif",
+ "textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
- "textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material
index 7a94386a18..55a01866b5 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
- "textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png",
"textureMapUv": "Unwrapped"
},
"detailLayerGroup": {
@@ -22,16 +22,16 @@
"scale": 10.0
},
"metallic": {
- "textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
- "textureMap": "Objects/Lucy/Lucy_normal.tif",
+ "textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
- "textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}
diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material
index ddeace43da..6193cf4eed 100644
--- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material
+++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material
@@ -5,7 +5,7 @@
"propertyLayoutVersion": 3,
"properties": {
"baseColor": {
- "textureMap": "Objects/Lucy/Lucy_brass_baseColor.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png",
"textureMapUv": "Unwrapped"
},
"detailLayerGroup": {
@@ -21,16 +21,16 @@
"scale": 10.0
},
"metallic": {
- "textureMap": "Objects/Lucy/Lucy_brass_metalness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png",
"textureMapUv": "Unwrapped"
},
"normal": {
"flipY": true,
- "textureMap": "Objects/Lucy/Lucy_normal.tif",
+ "textureMap": "Objects/Lucy/Lucy_normal.png",
"textureMapUv": "Unwrapped"
},
"roughness": {
- "textureMap": "Objects/Lucy/Lucy_brass_roughness.tif",
+ "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png",
"textureMapUv": "Unwrapped"
}
}
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h
index 81645b25a9..3c5bcbea00 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h
@@ -20,7 +20,6 @@ namespace AZ
{
namespace Render
{
-
class DisplayMapperComponentConfig final
: public ComponentConfig
{
@@ -33,6 +32,7 @@ namespace AZ
DisplayMapperOperationType m_displayMapperOperation = DisplayMapperOperationType::Aces;
bool m_ldrColorGradingLutEnabled = false;
Data::Asset m_ldrColorGradingLut = {};
+ AcesParameterOverrides m_acesParameterOverrides;
};
}
}
diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp
index e6afd4f21f..317fa96450 100644
--- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp
+++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentConfig.cpp
@@ -20,16 +20,18 @@ namespace AZ
{
void DisplayMapperComponentConfig::Reflect(ReflectContext* context)
{
+ AcesParameterOverrides::Reflect(context);
+
if (auto serializeContext = azrtti_cast