Merge branch 'development' into Atom/dmcdiar/ATOM-4126
This commit is contained in:
@@ -47,7 +47,7 @@ namespace ImageProcessingAtomEditor
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//EditorInternalNotificationBus
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace ImageProcessingAtomEditor
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//EditorInternalNotificationBus
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace ImageProcessingAtomEditor
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//EditorInternalNotificationBus
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform);
|
||||
void OnEditorSettingsChanged(bool needRefresh, const AZStd::string& platform) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace ImageProcessingAtom
|
||||
StepAll
|
||||
};
|
||||
|
||||
const char ProcessStepNames[StepAll][64] =
|
||||
[[maybe_unused]] const char ProcessStepNames[StepAll][64] =
|
||||
{
|
||||
"ValidateInput",
|
||||
"GenerateColorChart",
|
||||
|
||||
@@ -65,6 +65,7 @@ ly_add_target(
|
||||
AZ::AzFramework
|
||||
AZ::AzToolsFramework
|
||||
Gem::Atom_RHI.Edit
|
||||
Gem::Atom_RPI.Edit
|
||||
Gem::Atom_RPI.Public
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace AZ
|
||||
{
|
||||
namespace AtomShaderConfig
|
||||
{
|
||||
static constexpr char AtomShaderConfigName[] = "AtomShaderConfig";
|
||||
[[maybe_unused]] static constexpr char AtomShaderConfigName[] = "AtomShaderConfig";
|
||||
|
||||
bool MutateToFirstAbsoluteFolderThatExists(AZStd::string& relativeFolder, AZStd::vector<AZStd::string>& watchFolders)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
|
||||
#include <Atom/RHI.Edit/Utils.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroupLayout.h>
|
||||
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
@@ -1149,7 +1150,7 @@ namespace AZ
|
||||
return BuildResult::CompilationFailed;
|
||||
}
|
||||
|
||||
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile);
|
||||
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
|
||||
if (readJsonResult.IsSuccess())
|
||||
{
|
||||
@@ -1170,7 +1171,7 @@ namespace AZ
|
||||
AZStd::string outputFile = m_inputFilePath;
|
||||
AzFramework::StringFunc::Path::ReplaceExtension(outputFile, outputExtension);
|
||||
|
||||
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile);
|
||||
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
|
||||
if (readJsonResult.IsSuccess())
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AZ
|
||||
{
|
||||
namespace ShaderBuilder
|
||||
{
|
||||
static const char* s_azslShaderCompilerName = "AZSL Compiler";
|
||||
[[maybe_unused]] static const char* s_azslShaderCompilerName = "AZSL Compiler";
|
||||
|
||||
AZ::RHI::Format StringToFormat(const char* format)
|
||||
{
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
@@ -56,7 +56,7 @@ namespace AZ
|
||||
m_predefinedMacros.begin(), m_predefinedMacros.end(),
|
||||
[&](const AZStd::string& predefinedMacro) {
|
||||
// Haystack, needle, bCaseSensitive
|
||||
if (!AzFramework::StringFunc::StartsWith(predefinedMacro, macroName, true))
|
||||
if (!AZ::StringFunc::StartsWith(predefinedMacro, macroName, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -117,11 +117,11 @@ namespace AZ
|
||||
char localBuffer[DefaultFprintfBufferSize];
|
||||
|
||||
va_list args;
|
||||
|
||||
|
||||
va_start(args, format);
|
||||
int count = azvsnprintf(localBuffer, DefaultFprintfBufferSize, format, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
char* result = localBuffer;
|
||||
|
||||
// @result will be bound to @biggerData in case @localBuffer is not big enough.
|
||||
@@ -134,7 +134,7 @@ namespace AZ
|
||||
count++; // vsnprintf returns a size that doesn't include the null character.
|
||||
biggerData.reset(new char[count]);
|
||||
result = &biggerData[0];
|
||||
|
||||
|
||||
// Remark: for MacOS & Linux it is important to call va_start again before
|
||||
// each call to azvsnprintf. Not required for Windows.
|
||||
va_start(args, format);
|
||||
@@ -149,7 +149,7 @@ namespace AZ
|
||||
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l?view=msvc-160
|
||||
// In particular: "If the number of characters to write is greater than count,
|
||||
// these functions return -1 indicating that output has been truncated."
|
||||
|
||||
|
||||
// There wasn't enough space in the local store.
|
||||
// Remark: for MacOS & Linux it is important to call va_start again before
|
||||
// each call to azvsnprintf. Not required for Windows.
|
||||
@@ -157,10 +157,10 @@ namespace AZ
|
||||
count = azvscprintf(format, args);
|
||||
count += 1; // vscprintf returns a size that doesn't include the null character.
|
||||
va_end(args);
|
||||
|
||||
|
||||
biggerData.reset(new char[count]);
|
||||
result = &biggerData[0];
|
||||
|
||||
|
||||
va_start(args, format);
|
||||
count = azvsnprintf(result, count, format, args);
|
||||
va_end(args);
|
||||
@@ -191,7 +191,7 @@ namespace AZ
|
||||
|
||||
// definitions for the linker
|
||||
AZStd::mutex McppBinder::s_mcppExclusiveProtection;
|
||||
McppBinder* McppBinder::s_currentInstance = nullptr;
|
||||
McppBinder* McppBinder::s_currentInstance = nullptr;
|
||||
|
||||
// McppBinder ends
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -204,7 +204,7 @@ namespace AZ
|
||||
|
||||
// create the argc/argv
|
||||
const char* processName = "builder";
|
||||
const char* inputPath = fullPath.c_str();
|
||||
const char* inputPath = fullPath.c_str();
|
||||
// let's create the equivalent of that expression but in dynamic form:
|
||||
//const char* argv[] = { processName, szInPath, "-C", "-+", "-D macro1"..., "-I path"..., NULL };
|
||||
AZStd::vector< const char* > argv;
|
||||
@@ -230,7 +230,7 @@ namespace AZ
|
||||
argv.push_back(nullptr); // usual argv terminator
|
||||
// output the command line:
|
||||
AZStd::string stringifiedCommandLine;
|
||||
AzFramework::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
|
||||
AZ::StringFunc::Join(stringifiedCommandLine, argv.begin(), argv.end() - 1, " ");
|
||||
AZ_TracePrintf("Preprocessor", "%s", stringifiedCommandLine.c_str());
|
||||
// when we don't specify an -o outfile, mcpp uses stdout.
|
||||
// the trick is that since we hijacked putc & puts, stdout will not be written.
|
||||
@@ -238,17 +238,12 @@ namespace AZ
|
||||
return result;
|
||||
}
|
||||
|
||||
static void VerifySameFolder(const AZStd::string& path1, const AZStd::string& path2)
|
||||
static void VerifySameFolder([[maybe_unused]] AZStd::string_view path1, [[maybe_unused]] AZStd::string_view path2)
|
||||
{
|
||||
AZStd::string folder1, folder2;
|
||||
AzFramework::StringFunc::Path::GetFolderPath(path1.c_str(), folder1);
|
||||
AzFramework::StringFunc::Path::GetFolderPath(path2.c_str(), folder2);
|
||||
AzFramework::StringFunc::Path::Normalize(folder1);
|
||||
AzFramework::StringFunc::Path::Normalize(folder2);
|
||||
AZ_Warning("Preprocessing",
|
||||
folder1 == folder2,
|
||||
"The preprocessed file %s is in a different folder than its origin %s. Watch for #include problems with relative paths.",
|
||||
path1.c_str(), path2.c_str()
|
||||
AZ::IO::PathView(path1).ParentPath().LexicallyNormal() == AZ::IO::PathView(path2).ParentPath().LexicallyNormal(),
|
||||
"The preprocessed file %.*s is in a different folder than its origin %.*s. Watch for #include problems with relative paths.",
|
||||
AZ_STRING_ARG(path1), AZ_STRING_ARG(path2)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -260,7 +255,7 @@ namespace AZ
|
||||
// containing file names, to match the ORIGINAL source, and not the actual source in use by azslc.
|
||||
// That gymnastic is better for error messages anyway, so instead of making the SRG layout builder more intelligent,
|
||||
// we'll fake the origin of the file, by setting the original source as a filename
|
||||
// note that it is not possible to build a file in a different folder and fake it to a file eslewhere because relative includes will fail.
|
||||
// note that it is not possible to build a file in a different folder and fake it to a file elsewhere because relative includes will fail.
|
||||
void MutateLineDirectivesFileOrigin(
|
||||
AZStd::string& sourceCode,
|
||||
AZStd::string newFileOrigin)
|
||||
@@ -272,11 +267,11 @@ namespace AZ
|
||||
// we will use that as the information of the source path to mutate.
|
||||
if (sourceCode.starts_with("#line"))
|
||||
{
|
||||
auto firstQuote = sourceCode.find('"');
|
||||
auto secondQuote = sourceCode.find('"', firstQuote + 1);
|
||||
auto firstQuote = sourceCode.find('"');
|
||||
auto secondQuote = firstQuote != AZStd::string::npos ? sourceCode.find('"', firstQuote + 1) : AZStd::string::npos;
|
||||
auto originalFile = sourceCode.substr(firstQuote + 1, secondQuote - firstQuote - 1); // start +1, count -1 because we don't want the quotes included.
|
||||
VerifySameFolder(originalFile, newFileOrigin);
|
||||
[[maybe_unused]] bool didReplace = AzFramework::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
|
||||
[[maybe_unused]] bool didReplace = AZ::StringFunc::Replace(sourceCode, originalFile.c_str(), newFileOrigin.c_str(), true /*case sensitive*/);
|
||||
AZ_Assert(didReplace, "Failed to replace %s for %s in preprocessed source.", originalFile.c_str(), newFileOrigin.c_str());
|
||||
}
|
||||
else
|
||||
@@ -285,26 +280,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template< typename Container1, typename Container2 >
|
||||
void TransferContent(Container1& destination, Container2&& source)
|
||||
{
|
||||
destination.insert(AZStd::end(destination),
|
||||
AZStd::make_move_iterator(AZStd::begin(source)),
|
||||
AZStd::make_move_iterator(AZStd::end(source)));
|
||||
}
|
||||
|
||||
void DeleteFromSet(const AZStd::string& string, AZStd::set<AZStd::string>& set)
|
||||
{
|
||||
auto iter = set.find(string);
|
||||
if (iter != set.end())
|
||||
{
|
||||
set.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate options with scan folders and contents of parsing shader_global_build_options.json
|
||||
void InitializePreprocessorOptions(
|
||||
PreprocessorOptions& options, [[maybe_unused]] const char* builderName, const char* optionalIncludeFolder)
|
||||
@@ -315,44 +290,61 @@ namespace AZ
|
||||
bool success = true;
|
||||
AZStd::vector<AZStd::string> scanFoldersVector;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(success,
|
||||
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
|
||||
scanFoldersVector);
|
||||
&AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders,
|
||||
scanFoldersVector);
|
||||
AZ_Warning(builderName, success, "Preprocessor option: Could not acquire a list of scan folders from the database.");
|
||||
|
||||
// we transfer to a set, to order the folders, uniquify them, and ensure deterministic build behavior
|
||||
AZStd::set<AZStd::string> scanFoldersSet;
|
||||
// Add the project path to list of include paths
|
||||
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
|
||||
scanFoldersSet.emplace(projectPath.c_str(), projectPath.size());
|
||||
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
|
||||
auto FindPath = [](AZ::IO::PathView searchPath)
|
||||
{
|
||||
return [searchPath](AZStd::string_view includePathView)
|
||||
{
|
||||
return searchPath == AZ::IO::PathView(includePathView);
|
||||
};
|
||||
};
|
||||
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(projectPath));
|
||||
it == options.m_projectIncludePaths.end())
|
||||
{
|
||||
options.m_projectIncludePaths.emplace_back(projectPath.c_str(), projectPath.Native().size());
|
||||
}
|
||||
if (optionalIncludeFolder)
|
||||
{
|
||||
scanFoldersSet.emplace(optionalIncludeFolder, strnlen(optionalIncludeFolder, AZ::IO::MaxPathLength));
|
||||
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(optionalIncludeFolder));
|
||||
it == options.m_projectIncludePaths.end())
|
||||
{
|
||||
if (AZ::IO::SystemFile::Exists(optionalIncludeFolder))
|
||||
{
|
||||
options.m_projectIncludePaths.emplace_back(AZStd::move(AZ::IO::Path(optionalIncludeFolder).LexicallyNormal().Native()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// but while we transfer to the set, we're going to keep only folders where +/ShaderLib exists
|
||||
for (AZStd::string folder : scanFoldersVector)
|
||||
for (AZ::IO::Path shaderScanFolder : scanFoldersVector)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Join(folder.c_str(), "ShaderLib", folder);
|
||||
if (AZ::IO::SystemFile::Exists(folder.c_str()))
|
||||
shaderScanFolder /= "ShaderLib";
|
||||
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(shaderScanFolder));
|
||||
it == options.m_projectIncludePaths.end())
|
||||
{
|
||||
scanFoldersSet.emplace(std::move(folder));
|
||||
// the folders constructed this fashion constitute the base of automatic include search paths
|
||||
if (AZ::IO::SystemFile::Exists(shaderScanFolder.c_str()))
|
||||
{
|
||||
options.m_projectIncludePaths.emplace_back(AZStd::move(shaderScanFolder.LexicallyNormal().Native()));
|
||||
}
|
||||
}
|
||||
} // the folders constructed this fashion constitute the base of automatic include search paths
|
||||
|
||||
// get the engine root:
|
||||
AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
|
||||
|
||||
// add optional additional options
|
||||
for (AZStd::string& path : options.m_projectIncludePaths)
|
||||
{
|
||||
path = (engineRoot / path).String();
|
||||
DeleteFromSet(path, scanFoldersSet); // no need to add a path two times.
|
||||
}
|
||||
// back-insert the default paths (after the config-read paths we just read)
|
||||
TransferContent(/*to:*/options.m_projectIncludePaths, /*from:*/scanFoldersSet);
|
||||
|
||||
// finally the <engineroot>/Gems fallback
|
||||
AZStd::string gemsFolder;
|
||||
AzFramework::StringFunc::Path::Join(engineRoot.c_str(), "Gems", gemsFolder);
|
||||
options.m_projectIncludePaths.push_back(gemsFolder);
|
||||
AZ::IO::Path engineGemsFolder(AZStd::string_view{ AZ::Utils::GetEnginePath() });
|
||||
engineGemsFolder /= "Gems";
|
||||
if (auto it = AZStd::find_if(options.m_projectIncludePaths.begin(), options.m_projectIncludePaths.end(), FindPath(engineGemsFolder));
|
||||
it == options.m_projectIncludePaths.end())
|
||||
{
|
||||
if (AZ::IO::SystemFile::Exists(engineGemsFolder.c_str()))
|
||||
{
|
||||
options.m_projectIncludePaths.emplace_back(AZStd::move(engineGemsFolder.Native()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ShaderBuilder
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace AZ
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static const char* PrecompiledShaderBuilderName = "PrecompiledShaderBuilder";
|
||||
[[maybe_unused]] static const char* PrecompiledShaderBuilderName = "PrecompiledShaderBuilder";
|
||||
static const char* PrecompiledShaderBuilderJobKey = "PrecompiledShader Asset Builder";
|
||||
static const char* ShaderAssetExtension = "azshader";
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <Atom/RHI.Reflect/ConstantsLayout.h>
|
||||
#include <Atom/RHI.Reflect/PipelineLayoutDescriptor.h>
|
||||
#include <Atom/RHI.Reflect/ShaderStageFunction.h>
|
||||
@@ -60,10 +61,99 @@ namespace AZ
|
||||
static constexpr char ShaderAssetBuilderName[] = "ShaderAssetBuilder";
|
||||
static constexpr uint32_t ShaderAssetBuildTimestampParam = 0;
|
||||
|
||||
//! The search will start in @currentFolderPath.
|
||||
//! if the file is not found then it searches in order of appearence in @includeDirectories.
|
||||
//! If the search yields no existing file it returns an empty string.
|
||||
static AZStd::string DiscoverFullPath(AZStd::string_view normalizedRelativePath, AZStd::string_view currentFolderPath, const AZStd::vector<AZStd::string>& includeDirectories)
|
||||
{
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::Join(currentFolderPath.data(), normalizedRelativePath.data(), fullPath);
|
||||
if (AZ::IO::SystemFile::Exists(fullPath.c_str()))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
for (const auto &includeDir : includeDirectories)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Join(includeDir.c_str(), normalizedRelativePath.data(), fullPath);
|
||||
if (AZ::IO::SystemFile::Exists(fullPath.c_str()))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// Appends to @includedFiles normalized paths of possible future locations of the file @normalizedRelativePath.
|
||||
// The future locations are each directory listed in @includeDirectories joined with @normalizedRelativePath.
|
||||
// This function is called when an included file doesn't exist but We need to declare source dependency so a .shader
|
||||
// asset is rebuilt when the missing file appears in the future.
|
||||
static void AppendListOfPossibleFutureLocations(AZStd::unordered_set<AZStd::string>& includedFiles, AZStd::string_view normalizedRelativePath, AZStd::string_view currentFolderPath, const AZStd::vector<AZStd::string>& includeDirectories)
|
||||
{
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::Join(currentFolderPath.data(), normalizedRelativePath.data(), fullPath);
|
||||
includedFiles.insert(fullPath);
|
||||
for (const auto &includeDir : includeDirectories)
|
||||
{
|
||||
AzFramework::StringFunc::Path::Join(includeDir.c_str(), normalizedRelativePath.data(), fullPath);
|
||||
includedFiles.insert(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
//! Parses, using depth-first recursive approach, azsl files. Looks for '#include <foo/bar/blah.h>' or '#include "foo/bar/blah.h"' lines
|
||||
//! and in turn parses the included files.
|
||||
//! The included files are searched in the directories listed in @includeDirectories. Basically it's a similar approach
|
||||
//! as how most C-preprocessors would find included files.
|
||||
static void GetListOfIncludedFiles(AZStd::string_view sourceFilePath, const AZStd::vector<AZStd::string>& includeDirectories,
|
||||
const ShaderBuilderUtility::IncludedFilesParser& includedFilesParser, AZStd::unordered_set<AZStd::string>& includedFiles)
|
||||
{
|
||||
auto outcome = includedFilesParser.ParseFileAndGetIncludedFiles(sourceFilePath);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Warning(ShaderAssetBuilderName, false, outcome.GetError().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the path of the folder where @sourceFilePath is located.
|
||||
AZStd::string sourceFileFolderPath;
|
||||
{
|
||||
AZStd::string drive;
|
||||
AzFramework::StringFunc::Path::Split(sourceFilePath.data(), &drive, &sourceFileFolderPath);
|
||||
if (!drive.empty())
|
||||
{
|
||||
AzFramework::StringFunc::Path::Join(drive.c_str(), sourceFileFolderPath.c_str(), sourceFileFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
auto listOfRelativePaths = outcome.TakeValue();
|
||||
for (auto relativePath : listOfRelativePaths)
|
||||
{
|
||||
auto fullPath = DiscoverFullPath(relativePath, sourceFileFolderPath, includeDirectories);
|
||||
if (fullPath.empty())
|
||||
{
|
||||
// The file doesn't exist in any of the includeDirectories. It doesn't exist in @sourceFileFolderPath either.
|
||||
// The file may appear in the future in one of those directories, We must build an exhaustive list
|
||||
// of full file paths where the file may appear in the future.
|
||||
AppendListOfPossibleFutureLocations(includedFiles, relativePath, sourceFileFolderPath, includeDirectories);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the file to the list and keep parsing recursively.
|
||||
if (includedFiles.count(fullPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
includedFiles.insert(fullPath);
|
||||
GetListOfIncludedFiles(fullPath, includeDirectories, includedFilesParser, includedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderAssetBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
|
||||
{
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, true);
|
||||
ShaderBuilderUtility::IncludedFilesParser includedFilesParser;
|
||||
|
||||
AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for Shader \"%s\"\n", fullPath.data());
|
||||
|
||||
@@ -89,36 +179,6 @@ namespace AZ
|
||||
|
||||
AZStd::string azslFullPath;
|
||||
ShaderBuilderUtility::GetAbsolutePathToAzslFile(fullPath, shaderSourceData.m_source, azslFullPath);
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(azslFullPath.c_str()))
|
||||
{
|
||||
AZ_Error(
|
||||
ShaderAssetBuilderName, false, "Shader program listed as the source entry does not exist: %s.", azslFullPath.c_str());
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName);
|
||||
|
||||
// [GFX TODO] [ATOM-14966] In principle, based on macro definitions, included files can change per supervariant.
|
||||
// So, the list of source asset dependencies must be collected by running MCPP on each supervariant.
|
||||
// For now, we will run MCPP only once because CreateJobs() should be as light as possible.
|
||||
//
|
||||
// Regardless of the PlatformInfo and enabled ShaderPlatformInterfaces, the azsl file will be preprocessed
|
||||
// with the sole purpose of extracting all included files. For each included file a SourceDependency will be declared.
|
||||
PreprocessorData output;
|
||||
buildOptions.m_compilerArguments.Merge(shaderSourceData.m_compiler);
|
||||
PreprocessFile(azslFullPath, output, buildOptions.m_preprocessorSettings, true, true);
|
||||
for (auto includePath : output.includedPaths)
|
||||
{
|
||||
// m_sourceFileDependencyList does not support paths with "." or ".." for relative lookup, but the preprocessor
|
||||
// may produce path strings like "C:/a/b/c/../../d/file.azsli" so we have to normalize
|
||||
AzFramework::StringFunc::Path::Normalize(includePath);
|
||||
|
||||
AssetBuilderSDK::SourceFileDependency includeFileDependency;
|
||||
includeFileDependency.m_sourceFileDependencyPath = includePath;
|
||||
response.m_sourceFileDependencyList.emplace_back(includeFileDependency);
|
||||
}
|
||||
|
||||
{
|
||||
// Add the AZSL as source dependency
|
||||
@@ -127,6 +187,26 @@ namespace AZ
|
||||
response.m_sourceFileDependencyList.emplace_back(azslFileDependency);
|
||||
}
|
||||
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(azslFullPath.c_str()))
|
||||
{
|
||||
AZ_Error(
|
||||
ShaderAssetBuilderName, false, "Shader program listed as the source entry does not exist: %s.", azslFullPath.c_str());
|
||||
// Treat as success, so when the azsl file shows up the AP will try to recompile.
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
return;
|
||||
}
|
||||
|
||||
GlobalBuildOptions buildOptions = ReadBuildOptions(ShaderAssetBuilderName);
|
||||
|
||||
AZStd::unordered_set<AZStd::string> includedFiles;
|
||||
GetListOfIncludedFiles(azslFullPath, buildOptions.m_preprocessorSettings.m_projectIncludePaths, includedFilesParser, includedFiles);
|
||||
for (auto includePath : includedFiles)
|
||||
{
|
||||
AssetBuilderSDK::SourceFileDependency includeFileDependency;
|
||||
includeFileDependency.m_sourceFileDependencyPath = includePath;
|
||||
response.m_sourceFileDependencyList.emplace_back(includeFileDependency);
|
||||
}
|
||||
|
||||
for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
|
||||
{
|
||||
AZ_TraceContext("For platform", platformInfo.m_identifier.data());
|
||||
@@ -148,6 +228,10 @@ namespace AZ
|
||||
response.m_createJobOutputs.push_back(jobDescriptor);
|
||||
} // for all request.m_enabledPlatforms
|
||||
|
||||
const AZStd::sys_time_t createJobsEndStamp = AZStd::GetTimeNowMicroSecond();
|
||||
const u64 createJobDurationMicros = createJobsEndStamp - shaderAssetBuildTimestamp;
|
||||
AZ_TracePrintf(ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", fullPath.c_str(), createJobDurationMicros );
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
@@ -285,6 +369,13 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// CreateJobs was not successful if there's no timestamp property in m_jobParameters.
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
AZ_Assert(false, "Missing ShaderAssetBuildTimestampParam");
|
||||
return;
|
||||
}
|
||||
|
||||
auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceData);
|
||||
|
||||
@@ -555,7 +646,7 @@ namespace AZ
|
||||
shaderAssetCreator.SetRenderStates(renderStates);
|
||||
}
|
||||
|
||||
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath);
|
||||
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!hlslSourceCodeOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
#include <AzCore/IO/IOUtils.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
|
||||
|
||||
@@ -45,13 +47,13 @@ namespace AZ
|
||||
{
|
||||
namespace ShaderBuilderUtility
|
||||
{
|
||||
static constexpr char ShaderBuilderUtilityName[] = "ShaderBuilderUtility";
|
||||
[[maybe_unused]] static constexpr char ShaderBuilderUtilityName[] = "ShaderBuilderUtility";
|
||||
|
||||
Outcome<RPI::ShaderSourceData, AZStd::string> LoadShaderDataJson(const AZStd::string& fullPathToJsonFile)
|
||||
{
|
||||
RPI::ShaderSourceData shaderSourceData;
|
||||
|
||||
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile);
|
||||
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
|
||||
if (!document.IsSuccess())
|
||||
{
|
||||
@@ -127,7 +129,7 @@ namespace AZ
|
||||
AZStd::unordered_map<int, Outcome<rapidjson::Document, AZStd::string>> outcomes;
|
||||
for (int i : indicesOfInterest)
|
||||
{
|
||||
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i]);
|
||||
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i], AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!outcomes[i].IsSuccess())
|
||||
{
|
||||
AZ_Error(builderName, false, "%s", outcomes[i].GetError().c_str());
|
||||
@@ -622,7 +624,7 @@ namespace AZ
|
||||
StructData inputStruct;
|
||||
inputStruct.m_id = "";
|
||||
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -715,7 +717,7 @@ namespace AZ
|
||||
StructData outputStruct;
|
||||
outputStruct.m_id = "";
|
||||
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -813,6 +815,51 @@ namespace AZ
|
||||
return success;
|
||||
}
|
||||
|
||||
IncludedFilesParser::IncludedFilesParser()
|
||||
{
|
||||
AZStd::regex regex(R"(#\s*include\s+[<|"]([\w|/|\\|\.|-]+)[>|"])", AZStd::regex::ECMAScript);
|
||||
m_includeRegex.swap(regex);
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> IncludedFilesParser::ParseStringAndGetIncludedFiles(AZStd::string_view haystack) const
|
||||
{
|
||||
AZStd::vector<AZStd::string> listOfFilePaths;
|
||||
AZStd::smatch match;
|
||||
AZStd::string::const_iterator searchStart(haystack.cbegin());
|
||||
while (AZStd::regex_search(searchStart, haystack.cend(), match, m_includeRegex))
|
||||
{
|
||||
if (match.size() > 1)
|
||||
{
|
||||
AZStd::string relativeFilePath(match[1].str().c_str());
|
||||
AzFramework::StringFunc::Path::Normalize(relativeFilePath);
|
||||
listOfFilePaths.push_back(relativeFilePath);
|
||||
}
|
||||
searchStart = match.suffix().first;
|
||||
}
|
||||
return listOfFilePaths;
|
||||
}
|
||||
|
||||
AZ::Outcome<AZStd::vector<AZStd::string>, AZStd::string> IncludedFilesParser::ParseFileAndGetIncludedFiles(AZStd::string_view sourceFilePath) const
|
||||
{
|
||||
AZ::IO::FileIOStream stream(sourceFilePath.data(), AZ::IO::OpenMode::ModeRead);
|
||||
if (!stream.IsOpen())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("\"%s\" source file could not be opened.", sourceFilePath.data()));
|
||||
}
|
||||
|
||||
if (!stream.CanRead())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("\"%s\" source file could not be read.", sourceFilePath.data()));
|
||||
}
|
||||
|
||||
AZStd::string hayStack;
|
||||
hayStack.resize_no_construct(stream.GetLength());
|
||||
stream.Read(stream.GetLength(), hayStack.data());
|
||||
|
||||
auto listOfFilePaths = ParseStringAndGetIncludedFiles(hayStack);
|
||||
return AZ::Success(AZStd::move(listOfFilePaths));
|
||||
}
|
||||
|
||||
} // namespace ShaderBuilderUtility
|
||||
} // namespace ShaderBuilder
|
||||
} // AZ
|
||||
|
||||
@@ -141,6 +141,29 @@ namespace AZ
|
||||
const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
|
||||
const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId);
|
||||
|
||||
|
||||
class IncludedFilesParser
|
||||
{
|
||||
public:
|
||||
IncludedFilesParser();
|
||||
~IncludedFilesParser() = default;
|
||||
|
||||
//! This static function was made public for testability purposes only.
|
||||
//! Parses the string @haystack, looking for "#include file" lines with a regular expression.
|
||||
//! Returns the list of relative paths as included by the file.
|
||||
//! REMARK: The algorithm may over prescribe what files to include because it doesn't discern between comments, etc.
|
||||
//! Also, a #include line may be protected by #ifdef macros but this algorithm doesn't care.
|
||||
//! Over prescribing is not a real problem, albeit potential waste in processing. Under prescribing would be a real problem.
|
||||
AZStd::vector<AZStd::string> ParseStringAndGetIncludedFiles(AZStd::string_view haystack) const;
|
||||
|
||||
//! This static function was made public for testability purposes only.
|
||||
//! Opens the file @sourceFilePath, loads the content into a string and returns ParseStringAndGetIncludedFiles(content)
|
||||
AZ::Outcome<AZStd::vector<AZStd::string>, AZStd::string> ParseFileAndGetIncludedFiles(AZStd::string_view sourceFilePath) const;
|
||||
|
||||
private:
|
||||
AZStd::regex m_includeRegex;
|
||||
};
|
||||
|
||||
} // ShaderBuilderUtility namespace
|
||||
} // ShaderBuilder namespace
|
||||
} // AZ
|
||||
|
||||
@@ -478,7 +478,7 @@ namespace AZ
|
||||
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = RPI::ShaderOptionGroupLayout::Create();
|
||||
// The shader options define what options are available, what are the allowed values/range
|
||||
// for each option and what is its default value.
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -509,7 +509,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
auto functionsJsonPath = functionsJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -541,7 +541,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
auto srgJsonPath = srgJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -598,7 +598,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath);
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
@@ -630,7 +630,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
hlslSourcePath = hlslSourcePathOutcome.TakeValue();
|
||||
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath);
|
||||
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
|
||||
if (!hlslSourceOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include "Common/ShaderBuilderTestFixture.h"
|
||||
|
||||
#include <ShaderBuilderUtility.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ;
|
||||
|
||||
// The main purpose of this class is to test ShaderBuilderUtility functions
|
||||
class ShaderBuilderUtilityTests : public ShaderBuilderTestFixture
|
||||
{
|
||||
}; // class ShaderBuilderUtilityTests
|
||||
|
||||
|
||||
TEST_F(ShaderBuilderUtilityTests, IncludedFilesParser_ParseStringAndGetIncludedFiles)
|
||||
{
|
||||
AZStd::string haystack(
|
||||
"Some content to parse\n"
|
||||
"#include <valid_file1.azsli>\n"
|
||||
"// #include <valid_file2.azsli>\n"
|
||||
"blah # include \"valid_file3.azsli\"\n"
|
||||
"bar include <a\\dire-ctory\\invalid-file4.azsli>\n"
|
||||
"foo # include \"a/directory/valid-file5.azsli\"\n"
|
||||
"# include <a\\dire-ctory\\valid-file6.azsli>\n"
|
||||
"#includ \"a\\dire-ctory\\invalid-file7.azsli\"\n"
|
||||
);
|
||||
|
||||
AZ::ShaderBuilder::ShaderBuilderUtility::IncludedFilesParser includedFilesParser;
|
||||
auto fileList = includedFilesParser.ParseStringAndGetIncludedFiles(haystack);
|
||||
EXPECT_EQ(fileList.size(), 5);
|
||||
|
||||
auto it = AZStd::find(fileList.begin(), fileList.end(), "valid_file1.azsli");
|
||||
EXPECT_TRUE(it != fileList.end());
|
||||
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), "valid_file2.azsli");
|
||||
EXPECT_TRUE(it != fileList.end());
|
||||
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), "valid_file3.azsli");
|
||||
EXPECT_TRUE(it != fileList.end());
|
||||
|
||||
// Remark: From now on We must normalize because internally AZ::ShaderBuilder::ShaderBuilderUtility::IncludedFilesParser
|
||||
// always returns normalized paths.
|
||||
{
|
||||
AZStd::string fileName("a\\dire-ctory\\invalid-file4.azsli");
|
||||
AzFramework::StringFunc::Path::Normalize(fileName);
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
|
||||
EXPECT_TRUE(it == fileList.end());
|
||||
}
|
||||
|
||||
{
|
||||
AZStd::string fileName("a\\directory\\valid-file5.azsli");
|
||||
AzFramework::StringFunc::Path::Normalize(fileName);
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
|
||||
EXPECT_TRUE(it != fileList.end());
|
||||
}
|
||||
|
||||
{
|
||||
AZStd::string fileName("a\\dire-ctory\\valid-file6.azsli");
|
||||
AzFramework::StringFunc::Path::Normalize(fileName);
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
|
||||
EXPECT_TRUE(it != fileList.end());
|
||||
}
|
||||
|
||||
{
|
||||
AZStd::string fileName("a\\dire-ctory\\invalid-file7.azsli");
|
||||
AzFramework::StringFunc::Path::Normalize(fileName);
|
||||
it = AZStd::find(fileList.begin(), fileList.end(), fileName);
|
||||
EXPECT_TRUE(it == fileList.end());
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace UnitTest
|
||||
|
||||
//AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
|
||||
@@ -11,4 +11,5 @@ set(FILES
|
||||
Tests/Common/ShaderBuilderTestFixture.cpp
|
||||
Tests/SupervariantCmdArgumentTests.cpp
|
||||
Tests/McppBinderTests.cpp
|
||||
Tests/ShaderBuilderUtilityTests.cpp
|
||||
)
|
||||
|
||||
@@ -56,7 +56,8 @@ namespace AZ
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0;
|
||||
virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){}
|
||||
virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){}
|
||||
};
|
||||
using NotificationBus = AZ::EBus<Notification>;
|
||||
} // namespace Bootstrap
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace AZ::Render::Bootstrap
|
||||
|
||||
virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0;
|
||||
virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0;
|
||||
virtual float GetFrameRateLimit() const = 0;
|
||||
virtual void SetFrameRateLimit(float fpsLimit) = 0;
|
||||
|
||||
protected:
|
||||
~Request() = default;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderSystem.h>
|
||||
|
||||
#include <Atom/Bootstrap/DefaultWindowBus.h>
|
||||
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
|
||||
@@ -41,7 +42,14 @@
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <BootstrapSystemComponent_Traits_Platform.h>
|
||||
|
||||
static void OnFrameRateLimitChanged(const float& fpsLimit)
|
||||
{
|
||||
AZ::Render::Bootstrap::RequestBus::Broadcast(
|
||||
&AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit);
|
||||
}
|
||||
|
||||
AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name");
|
||||
AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited");
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -253,34 +261,6 @@ namespace AZ
|
||||
RPI::SceneDescriptor sceneDesc;
|
||||
AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
|
||||
atomScene->EnableAllFeatureProcessors();
|
||||
|
||||
// Setup scene srg modification callback.
|
||||
RPI::ShaderResourceGroupCallback callback = [this](RPI::ShaderResourceGroup* srg)
|
||||
{
|
||||
if (srg == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool needCompile = false;
|
||||
RHI::ShaderInputConstantIndex timeIndex = srg->FindShaderInputConstantIndex(Name{ "m_time" });
|
||||
if (timeIndex.IsValid())
|
||||
{
|
||||
srg->SetConstant(timeIndex, m_simulateTime);
|
||||
needCompile = true;
|
||||
}
|
||||
RHI::ShaderInputConstantIndex deltaTimeIndex = srg->FindShaderInputConstantIndex(Name{ "m_deltaTime" });
|
||||
if (deltaTimeIndex.IsValid())
|
||||
{
|
||||
srg->SetConstant(deltaTimeIndex, m_deltaTime);
|
||||
needCompile = true;
|
||||
}
|
||||
|
||||
if (needCompile)
|
||||
{
|
||||
srg->Compile();
|
||||
}
|
||||
};
|
||||
atomScene->SetShaderResourceGroupCallback(callback);
|
||||
atomScene->Activate();
|
||||
|
||||
// Register scene to RPI system so it will be processed/rendered per tick
|
||||
@@ -324,6 +304,11 @@ namespace AZ
|
||||
RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset<RPI::RenderPipelineDescriptor>(pipelineAsset);
|
||||
renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId());
|
||||
|
||||
// Make sure non-msaa super variant is used for non-msaa pipeline
|
||||
bool isNonMsaaPipeline = (renderPipelineDescriptor.m_renderSettings.m_multisampleState.m_samples == 1);
|
||||
const char* supervariantName = isNonMsaaPipeline ? AZ::RPI::NoMsaaSupervariantName : "";
|
||||
AZ::RPI::ShaderSystemInterface::Get()->SetSupervariantName(AZ::Name(supervariantName));
|
||||
|
||||
if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name)))
|
||||
{
|
||||
RPI::RenderPipelinePtr renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDescriptor, *viewportContext->GetWindowContext().get());
|
||||
@@ -370,6 +355,22 @@ namespace AZ
|
||||
return true;
|
||||
}
|
||||
|
||||
float BootstrapSystemComponent::GetFrameRateLimit() const
|
||||
{
|
||||
return r_fps_limit;
|
||||
}
|
||||
|
||||
void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit)
|
||||
{
|
||||
r_fps_limit = fpsLimit;
|
||||
if (m_viewportContext)
|
||||
{
|
||||
m_viewportContext->SetFpsLimit(r_fps_limit);
|
||||
}
|
||||
Render::Bootstrap::NotificationBus::Broadcast(
|
||||
&Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit);
|
||||
}
|
||||
|
||||
void BootstrapSystemComponent::CreateDefaultRenderPipeline()
|
||||
{
|
||||
EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext);
|
||||
@@ -391,7 +392,7 @@ namespace AZ
|
||||
// Unbind m_defaultScene to the GameEntityContext's AzFramework::Scene
|
||||
if (m_defaultFrameworkScene)
|
||||
{
|
||||
m_defaultFrameworkScene->UnsetSubsystem<RPI::Scene>();
|
||||
m_defaultFrameworkScene->UnsetSubsystem(m_defaultScene);
|
||||
}
|
||||
|
||||
m_defaultScene = nullptr;
|
||||
@@ -408,27 +409,12 @@ namespace AZ
|
||||
m_renderPipelineId = "";
|
||||
}
|
||||
|
||||
void BootstrapSystemComponent::OnTick(float deltaTime, [[maybe_unused]] ScriptTimePoint time)
|
||||
{
|
||||
m_simulateTime += deltaTime;
|
||||
m_deltaTime = deltaTime;
|
||||
|
||||
// Temp: When running in the launcher without the legacy renderer
|
||||
// we need to call RenderTick on the viewport context each frame.
|
||||
if (m_viewportContext)
|
||||
{
|
||||
AZ::ApplicationTypeQuery appType;
|
||||
ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
|
||||
if (appType.IsGame())
|
||||
{
|
||||
m_viewportContext->RenderTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
|
||||
{ }
|
||||
|
||||
int BootstrapSystemComponent::GetTickOrder()
|
||||
{
|
||||
return TICK_LAST;
|
||||
return TICK_PRE_RENDER;
|
||||
}
|
||||
|
||||
void BootstrapSystemComponent::OnWindowClosed()
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace AZ
|
||||
// Render::Bootstrap::RequestBus::Handler overrides ...
|
||||
AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override;
|
||||
bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override;
|
||||
float GetFrameRateLimit() const override;
|
||||
void SetFrameRateLimit(float fpsLimit) override;
|
||||
|
||||
protected:
|
||||
// Component overrides ...
|
||||
@@ -105,9 +107,6 @@ namespace AZ
|
||||
RPI::ScenePtr m_defaultScene = nullptr;
|
||||
AZStd::shared_ptr<AzFramework::Scene> m_defaultFrameworkScene = nullptr;
|
||||
|
||||
float m_simulateTime = 0;
|
||||
float m_deltaTime = 0.016f;
|
||||
|
||||
bool m_isAssetCatalogLoaded = false;
|
||||
|
||||
// The id of the render pipeline created by this component
|
||||
|
||||
@@ -40,9 +40,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"Name": "HorizontalGaussianFilter",
|
||||
"TemplateName": "FilterDepthHorizontalTemplate",
|
||||
"Name": "KawaseBlur0",
|
||||
"TemplateName": "KawaseShadowBlurTemplate",
|
||||
"Enabled": true,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
@@ -54,26 +56,27 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerticalGaussianFiter",
|
||||
"TemplateName": "FilterDepthVerticalTemplate",
|
||||
"Name": "KawaseBlur1",
|
||||
"TemplateName": "KawaseShadowBlurTemplate",
|
||||
"Enabled": true,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
"AttachmentRef": {
|
||||
"Pass": "HorizontalGaussianFilter",
|
||||
"Pass": "KawaseBlur0",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "EsmShadowmaps",
|
||||
"AttachmentRef": {
|
||||
"Pass": "VerticalGaussianFiter",
|
||||
"Pass": "KawaseBlur1",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "FilterDepthHorizontalTemplate",
|
||||
"PassClass": "ComputePass",
|
||||
"Slots": [
|
||||
{
|
||||
"Name": "Input",
|
||||
"SlotType": "Input",
|
||||
"ShaderInputName": "m_inputImage",
|
||||
"ScopeAttachmentUsage": "Shader",
|
||||
"LoadStoreAction": {
|
||||
"LoadAction": "Load",
|
||||
"StoreAction": "DontCare"
|
||||
},
|
||||
"ImageViewDesc": {
|
||||
"IsArray": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Output",
|
||||
"SlotType": "Output",
|
||||
"ShaderInputName": "m_outputImage",
|
||||
"ScopeAttachmentUsage": "Shader",
|
||||
"LoadStoreAction": {
|
||||
"LoadAction": "DontCare",
|
||||
"StoreAction": "Store"
|
||||
},
|
||||
"ImageViewDesc": {
|
||||
"IsArray": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "ComputePassData",
|
||||
"ShaderAsset": {
|
||||
"FilePath": "Shaders/Math/GaussianFilterFloatHorizontal.shader"
|
||||
}
|
||||
},
|
||||
"ImageAttachments": [
|
||||
{
|
||||
"Name": "HorizontalFiltered",
|
||||
"SizeSource": {
|
||||
"Source": {
|
||||
"Pass": "This",
|
||||
"Attachment": "Input"
|
||||
}
|
||||
},
|
||||
"ArraySizeSource": {
|
||||
"Pass": "This",
|
||||
"Attachment": "Input"
|
||||
},
|
||||
"ImageDescriptor": {
|
||||
"Format": "R32_FLOAT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Connections": [
|
||||
{
|
||||
"localSlot": "Output",
|
||||
"AttachmentRef": {
|
||||
"Pass": "This",
|
||||
"Attachment": "HorizontalFiltered"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "HDRColorGradingTemplate",
|
||||
"PassClass": "FullScreenTriangle",
|
||||
"Slots": [
|
||||
{
|
||||
"Name": "Input",
|
||||
"SlotType": "Input",
|
||||
"ShaderInputName": "m_framebuffer",
|
||||
"ScopeAttachmentUsage": "Shader"
|
||||
},
|
||||
{
|
||||
"Name": "Output",
|
||||
"SlotType": "Output",
|
||||
"ScopeAttachmentUsage": "RenderTarget",
|
||||
"LoadStoreAction": {
|
||||
"LoadAction": "DontCare"
|
||||
}
|
||||
}
|
||||
],
|
||||
"ImageAttachments": [
|
||||
{
|
||||
"Name": "ColorGradingOutput",
|
||||
"SizeSource": {
|
||||
"Source": {
|
||||
"Pass": "This",
|
||||
"Attachment": "Input"
|
||||
}
|
||||
},
|
||||
"FormatSource": {
|
||||
"Pass": "This",
|
||||
"Attachment": "Input"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Output",
|
||||
"AttachmentRef": {
|
||||
"Pass": "This",
|
||||
"Attachment": "ColorGradingOutput"
|
||||
}
|
||||
}
|
||||
],
|
||||
"FallbackConnections": [
|
||||
{
|
||||
"Input": "Input",
|
||||
"Output": "Output"
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "FullscreenTrianglePassData",
|
||||
"ShaderAsset": {
|
||||
"FilePath": "Shaders/PostProcessing/HDRColorGrading.shader"
|
||||
},
|
||||
"ShaderDataMappings": {
|
||||
"FloatMappings": [
|
||||
{
|
||||
"Name": "m_colorGradingExposure",
|
||||
"Value": 0.0 // unconstrained, log2 stops
|
||||
},
|
||||
{
|
||||
"Name": "m_colorGradingContrast",
|
||||
"Value": 0.0 // -100 ... 100
|
||||
},
|
||||
{
|
||||
"Name": "m_colorGradingHueShift",
|
||||
"Value": 0.0 // 0 ... 1, can wrap
|
||||
},
|
||||
{
|
||||
"Name": "m_colorGradingPreSaturation",
|
||||
"Value": 1.0 // -100 ... 100
|
||||
},
|
||||
{
|
||||
"Name": "m_colorFilterIntensity",
|
||||
"Value": 1.0 // unconstrained, log2 stops
|
||||
},
|
||||
{
|
||||
"Name": "m_colorFilterMultiply",
|
||||
"Value": 0.0 // modulate, 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_whiteBalanceKelvin",
|
||||
"Value": 6500.0 // 1000.0f ... 40000.0f kelvin
|
||||
},
|
||||
{
|
||||
"Name": "m_whiteBalanceTint",
|
||||
"Value": 0.0 // -100 ... 100
|
||||
},
|
||||
{
|
||||
"Name": "m_splitToneBalance",
|
||||
"Value": 0.0 // -1 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_splitToneMix",
|
||||
"Value": 0.0 // 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_colorGradingPostSaturation",
|
||||
"Value": 1.0 // -100 ... 100
|
||||
},
|
||||
{
|
||||
"Name": "m_smhShadowsStart",
|
||||
"Value": 0.0 // 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_smhShadowsEnd",
|
||||
"Value": 0.3 // 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_smhHighlightsStart",
|
||||
"Value": 0.55 // 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_smhHighlightsEnd",
|
||||
"Value": 1.0 // 0 ... 1
|
||||
},
|
||||
{
|
||||
"Name": "m_smhMix",
|
||||
"Value": 0.0 // 0 ... 1
|
||||
}
|
||||
],
|
||||
// The colors defined here are expected to be in linear rgb color space.
|
||||
// These are converted to ACEScg color space within the HDRColorGrading.azsl shader
|
||||
"ColorMappings": [
|
||||
{
|
||||
"Name": "m_colorFilterSwatch",
|
||||
"Value": [
|
||||
1.0,
|
||||
0.5,
|
||||
0.5,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_splitToneShadowsColor",
|
||||
"Value": [
|
||||
1.0,
|
||||
0.1,
|
||||
0.1,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_splitToneHighlightsColor",
|
||||
"Value": [
|
||||
0.1,
|
||||
1.0,
|
||||
0.1,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_smhShadowsColor",
|
||||
"Value": [
|
||||
1.0,
|
||||
0.25,
|
||||
0.25,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_smhMidtonesColor",
|
||||
"Value": [
|
||||
0.1,
|
||||
0.1,
|
||||
1.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_smhHighlightsColor",
|
||||
"Value": [
|
||||
1.0,
|
||||
0.0,
|
||||
1.0,
|
||||
1.0
|
||||
]
|
||||
}
|
||||
],
|
||||
"Float3Mappings": [
|
||||
{
|
||||
"Name": "m_channelMixingRed",
|
||||
"Value": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_channelMixingGreen",
|
||||
"Value": [
|
||||
0.0,
|
||||
1.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "m_channelMixingBlue",
|
||||
"Value": [
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -4,7 +4,7 @@
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "FilterDepthVerticalTemplate",
|
||||
"Name": "KawaseShadowBlurTemplate",
|
||||
"PassClass": "ComputePass",
|
||||
"Slots": [
|
||||
{
|
||||
@@ -28,7 +28,7 @@
|
||||
"LoadStoreAction": {
|
||||
"LoadAction": "DontCare",
|
||||
"StoreAction": "Store"
|
||||
},
|
||||
},
|
||||
"ImageViewDesc": {
|
||||
"IsArray": 1
|
||||
}
|
||||
@@ -37,12 +37,12 @@
|
||||
"PassData": {
|
||||
"$type": "ComputePassData",
|
||||
"ShaderAsset": {
|
||||
"FilePath": "Shaders/Math/GaussianFilterFloatVertical.shader"
|
||||
"FilePath": "Shaders/Shadow/KawaseShadowBlur.shader"
|
||||
}
|
||||
},
|
||||
"ImageAttachments": [
|
||||
{
|
||||
"Name": "VerticalFiltered",
|
||||
"Name": "FilteredImage",
|
||||
"SizeSource": {
|
||||
"Source": {
|
||||
"Pass": "This",
|
||||
@@ -63,7 +63,7 @@
|
||||
"localSlot": "Output",
|
||||
"AttachmentRef": {
|
||||
"Pass": "This",
|
||||
"Attachment": "VerticalFiltered"
|
||||
"Attachment": "FilteredImage"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -184,14 +184,6 @@
|
||||
"Name": "DepthOfFieldWriteFocusDepthFromGpuTemplate",
|
||||
"Path": "Passes/DepthOfFieldWriteFocusDepthFromGpu.pass"
|
||||
},
|
||||
{
|
||||
"Name": "FilterDepthHorizontalTemplate",
|
||||
"Path": "Passes/FilterDepthHorizontal.pass"
|
||||
},
|
||||
{
|
||||
"Name": "FilterDepthVerticalTemplate",
|
||||
"Path": "Passes/FilterDepthVertical.pass"
|
||||
},
|
||||
{
|
||||
"Name": "EsmShadowmapsTemplate",
|
||||
"Path": "Passes/EsmShadowmaps.pass"
|
||||
@@ -503,7 +495,15 @@
|
||||
{
|
||||
"Name": "LowEndPipelineTemplate",
|
||||
"Path": "Passes/LowEndPipeline.pass"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "KawaseShadowBlurTemplate",
|
||||
"Path": "Passes/KawaseShadowBlur.pass"
|
||||
},
|
||||
{
|
||||
"Name": "HDRColorGradingTemplate",
|
||||
"Path": "Passes/HDRColorGrading.pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ local FindMaterialAssignmentTest =
|
||||
"materials/presets/macbeth/12_orange_yellow_srgb.tif.streamingimage",
|
||||
"materials/presets/macbeth/17_magenta_srgb.tif.streamingimage"
|
||||
},
|
||||
MaterialSlotFilter = ""
|
||||
},
|
||||
}
|
||||
|
||||
@@ -50,18 +51,6 @@ function FindMaterialAssignmentTest:OnActivate()
|
||||
self.colors = {}
|
||||
self.lerpDirs = {}
|
||||
|
||||
self.assignmentIds =
|
||||
{
|
||||
MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, "lambert"),
|
||||
}
|
||||
|
||||
for index = 1, #self.assignmentIds do
|
||||
local id = self.assignmentIds[index]
|
||||
if (id ~= nil) then
|
||||
self.colors[index] = randomColor()
|
||||
self.lerpDirs[index] = randomDir()
|
||||
end
|
||||
end
|
||||
self.tickBusHandler = TickBus.Connect(self);
|
||||
end
|
||||
|
||||
@@ -144,10 +133,33 @@ function FindMaterialAssignmentTest:lerpColors(deltaTime)
|
||||
end
|
||||
|
||||
function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint)
|
||||
|
||||
|
||||
if(nil == self.assignmentIds) then
|
||||
|
||||
local originalAssignments = MaterialComponentRequestBus.Event.GetOriginalMaterialAssignments(self.entityId)
|
||||
if(nil == originalAssignments or #originalAssignments <= 1) then -- There is always 1 entry for the default assignment; a loaded model will have at least 2 assignments
|
||||
return
|
||||
end
|
||||
|
||||
self.assignmentIds =
|
||||
{
|
||||
MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, self.Properties.MaterialSlotFilter),
|
||||
}
|
||||
|
||||
for index = 1, #self.assignmentIds do
|
||||
local id = self.assignmentIds[index]
|
||||
if (id ~= nil) then
|
||||
self.colors[index] = randomColor()
|
||||
self.lerpDirs[index] = randomDir()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.timer = self.timer + deltaTime
|
||||
self.totalTime = self.totalTime + deltaTime
|
||||
self:lerpColors(deltaTime)
|
||||
|
||||
|
||||
if (self.timer > self.timeUpdate and self.totalTime < self.totalTimeMax) then
|
||||
self.timer = self.timer - self.timeUpdate
|
||||
self:UpdateProperties()
|
||||
@@ -155,6 +167,7 @@ function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint)
|
||||
self:ClearProperties()
|
||||
self.tickBusHandler:Disconnect(self);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return FindMaterialAssignmentTest
|
||||
return FindMaterialAssignmentTest
|
||||
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: (Apache-2.0 OR MIT) AND Creative Commons 3.0
|
||||
*
|
||||
*/
|
||||
|
||||
// Ref: https://www.shadertoy.com/view/lsSXW1
|
||||
// ported by Renaud Bédard (@renaudbedard) from original code from Tanner Helland
|
||||
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
|
||||
// color space functions translated from HLSL versions on Chilli Ant (by Ian Taylor)
|
||||
// http://www.chilliant.com/rgb2hsv.html
|
||||
|
||||
// licensed and released under Creative Commons 3.0 Attribution
|
||||
// https://creativecommons.org/licenses/by/3.0/
|
||||
|
||||
float3 HueToRgb(float hue)
|
||||
{
|
||||
return saturate(float3(abs(hue * 6.0f - 3.0f) - 1.0f,
|
||||
2.0f - abs(hue * 6.0f - 2.0f),
|
||||
2.0f - abs(hue * 6.0f - 4.0f)));
|
||||
}
|
||||
|
||||
float3 RgbToHcv(float3 rgb)
|
||||
{
|
||||
// Based on work by Sam Hocevar and Emil Persson
|
||||
const float4 p = (rgb.g < rgb.b) ? float4(rgb.bg, -1.0f, 2.0f/3.0f) : float4(rgb.gb, 0.0f, -1.0f/3.0f);
|
||||
const float4 q1 = (rgb.r < p.x) ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
|
||||
const float c = q1.x - min(q1.w, q1.y);
|
||||
const float h = abs((q1.w - q1.y) / (6.0f * c + 0.000001f ) + q1.z);
|
||||
return float3(h, c, q1.x);
|
||||
}
|
||||
|
||||
float3 RgbToHsl(float3 rgb)
|
||||
{
|
||||
rgb.xyz = max(rgb.xyz, 0.000001f);
|
||||
const float3 hcv = RgbToHcv(rgb);
|
||||
const float L = hcv.z - hcv.y * 0.5f;
|
||||
const float S = hcv.y / (1.0f - abs(L * 2.0f - 1.0f) + 0.000001f);
|
||||
return float3(hcv.x, S, L);
|
||||
}
|
||||
|
||||
float3 HslToRgb(float3 hsl)
|
||||
{
|
||||
const float3 rgb = HueToRgb(hsl.x);
|
||||
const float c = (1.0f - abs(2.0f * hsl.z - 1.0f)) * hsl.y;
|
||||
return (rgb - 0.5f) * c + hsl.z;
|
||||
}
|
||||
|
||||
// Color temperature
|
||||
float3 KelvinToRgb(float kelvin)
|
||||
{
|
||||
float3 ret;
|
||||
kelvin = clamp(kelvin, 1000.0f, 40000.0f) / 100.0f;
|
||||
if(kelvin <= 66.0f)
|
||||
{
|
||||
ret.r = 1.0f;
|
||||
ret.g = saturate(0.39008157876901960784f * log(kelvin) - 0.63184144378862745098f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float t = max(kelvin - 60.0f, 0.0f);
|
||||
ret.r = saturate(1.29293618606274509804f * pow(t, -0.1332047592f));
|
||||
ret.g = saturate(1.12989086089529411765f * pow(t, -0.0755148492f));
|
||||
}
|
||||
if(kelvin >= 66.0f)
|
||||
ret.b = 1.0f;
|
||||
else if(kelvin < 19.0f)
|
||||
ret.b = 0.0f;
|
||||
else
|
||||
ret.b = saturate(0.54320678911019607843f * log(kelvin - 10.0f) - 1.19625408914f);
|
||||
return ret;
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
Public Domain
|
||||
------------------------------------------------------------------------------
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
|
||||
*/
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
float Color_GetLuminosity(float3 c)
|
||||
{
|
||||
return 0.3*c.r + 0.59*c.g + 0.11*c.b;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
float3 Color_SetLuminosity(float3 c, float lum)
|
||||
{
|
||||
float d = lum - Color_GetLuminosity(c);
|
||||
c.rgb += float3(d,d,d);
|
||||
|
||||
// clip back into legal range
|
||||
lum = Color_GetLuminosity(c);
|
||||
float cMin = min(c.r, min(c.g, c.b));
|
||||
float cMax = max(c.r, max(c.g, c.b));
|
||||
|
||||
if(cMin < 0)
|
||||
c = lerp(float3(lum,lum,lum), c, lum / (lum - cMin));
|
||||
|
||||
if(cMax > 1)
|
||||
c = lerp(float3(lum,lum,lum), c, (1 - lum) / (cMax - lum));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
float Color_GetSaturation(float3 c)
|
||||
{
|
||||
return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Set saturation if color components are sorted in ascending order.
|
||||
//******************************************************************************
|
||||
float3 Color_SetSaturation_MinMidMax(float3 cSorted, float s)
|
||||
{
|
||||
if(cSorted.z > cSorted.x)
|
||||
{
|
||||
cSorted.y = (((cSorted.y - cSorted.x) * s) / (cSorted.z - cSorted.x));
|
||||
cSorted.z = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
cSorted.y = 0;
|
||||
cSorted.z = 0;
|
||||
}
|
||||
|
||||
cSorted.x = 0;
|
||||
|
||||
return cSorted;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
float3 Color_SetSaturation(float3 c, float s)
|
||||
{
|
||||
if (c.r <= c.g && c.r <= c.b)
|
||||
{
|
||||
if (c.g <= c.b)
|
||||
c.rgb = Color_SetSaturation_MinMidMax(c.rgb, s);
|
||||
else
|
||||
c.rbg = Color_SetSaturation_MinMidMax(c.rbg, s);
|
||||
}
|
||||
else if (c.g <= c.r && c.g <= c.b)
|
||||
{
|
||||
if (c.r <= c.b)
|
||||
c.grb = Color_SetSaturation_MinMidMax(c.grb, s);
|
||||
else
|
||||
c.gbr = Color_SetSaturation_MinMidMax(c.gbr, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c.r <= c.g)
|
||||
c.brg = Color_SetSaturation_MinMidMax(c.brg, s);
|
||||
else
|
||||
c.bgr = Color_SetSaturation_MinMidMax(c.bgr, s);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Creates a color with the hue of the blend color and the saturation and
|
||||
// luminosity of the base color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Hue(float3 base, float3 blend)
|
||||
{
|
||||
return Color_SetLuminosity(Color_SetSaturation(blend, Color_GetSaturation(base)), Color_GetLuminosity(base));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Creates a color with the saturation of the blend color and the hue and
|
||||
// luminosity of the base color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Saturation(float3 base, float3 blend)
|
||||
{
|
||||
return Color_SetLuminosity(Color_SetSaturation(base, Color_GetSaturation(blend)), Color_GetLuminosity(base));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Creates a color with the hue and saturation of the blend color and the
|
||||
// luminosity of the base color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Color(float3 base, float3 blend)
|
||||
{
|
||||
return Color_SetLuminosity(blend, Color_GetLuminosity(base));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Creates a color with the luminosity of the blend color and the hue and
|
||||
// saturation of the base color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Luminosity(float3 base, float3 blend)
|
||||
{
|
||||
return Color_SetLuminosity(base, Color_GetLuminosity(blend));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Compares the total of all channel values for the blend and base color and
|
||||
// displays the lower value color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_DarkerColor(float3 base, float3 blend)
|
||||
{
|
||||
return Color_GetLuminosity(base) <= Color_GetLuminosity(blend) ? base : blend;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Compares the total of all channel values for the blend and base color and
|
||||
// displays the higher value color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_LighterColor(float3 base, float3 blend)
|
||||
{
|
||||
return Color_GetLuminosity(base) > Color_GetLuminosity(blend) ? base : blend;
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
Public Domain
|
||||
------------------------------------------------------------------------------
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
Source: https://www.ryanjuckett.com/photoshop-blend-modes-in-hlsl/
|
||||
*/
|
||||
//******************************************************************************
|
||||
// Selects the blend color, ignoring the base.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Normal(float3 base, float3 blend)
|
||||
{
|
||||
return blend;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and selects the base or blend
|
||||
// color—whichever is darker—as the result color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Darken(float3 base, float3 blend)
|
||||
{
|
||||
return min(base, blend);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and multiplies the base color
|
||||
// by the blend color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Multiply(float3 base, float3 blend)
|
||||
{
|
||||
return base*blend;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and darkens the base color to
|
||||
// reflect the blend color by increasing the contrast between the two.
|
||||
//******************************************************************************
|
||||
float BlendMode_ColorBurn(float base, float blend)
|
||||
{
|
||||
return blend > 0 ? 1 - min(1, (1-base) / blend) : 0;
|
||||
}
|
||||
|
||||
float3 BlendMode_ColorBurn(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_ColorBurn(base.r, blend.r),
|
||||
BlendMode_ColorBurn(base.g, blend.g),
|
||||
BlendMode_ColorBurn(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and darkens the base color to
|
||||
// reflect the blend color by decreasing the brightness.
|
||||
//******************************************************************************
|
||||
float BlendMode_LinearBurn(float base, float blend)
|
||||
{
|
||||
return max(0, base + blend - 1);
|
||||
}
|
||||
|
||||
float3 BlendMode_LinearBurn(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_LinearBurn(base.r, blend.r),
|
||||
BlendMode_LinearBurn(base.g, blend.g),
|
||||
BlendMode_LinearBurn(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and selects the base or blend
|
||||
// color—whichever is lighter—as the result color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Lighten(float3 base, float3 blend)
|
||||
{
|
||||
return max(base, blend);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at each channel’s color information and multiplies the inverse of the
|
||||
// blend and base colors.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Screen(float3 base, float3 blend)
|
||||
{
|
||||
return base + blend - base*blend;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and brightens the base color
|
||||
// to reflect the blend color by decreasing contrast between the two.
|
||||
//******************************************************************************
|
||||
float BlendMode_ColorDodge(float base, float blend)
|
||||
{
|
||||
return blend < 1 ? min(1, base / (1-blend)) : 1;
|
||||
}
|
||||
|
||||
float3 BlendMode_ColorDodge(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_ColorDodge(base.r, blend.r),
|
||||
BlendMode_ColorDodge(base.g, blend.g),
|
||||
BlendMode_ColorDodge(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and brightens the base color
|
||||
// to reflect the blend color by decreasing contrast between the two.
|
||||
//******************************************************************************
|
||||
float BlendMode_LinearDodge(float base, float blend)
|
||||
{
|
||||
return min(1, base + blend);
|
||||
}
|
||||
|
||||
float3 BlendMode_LinearDodge(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_LinearDodge(base.r, blend.r),
|
||||
BlendMode_LinearDodge(base.g, blend.g),
|
||||
BlendMode_LinearDodge(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Multiplies or screens the colors, depending on the base color.
|
||||
//******************************************************************************
|
||||
float BlendMode_Overlay(float base, float blend)
|
||||
{
|
||||
return (base <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
|
||||
}
|
||||
|
||||
float3 BlendMode_Overlay(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_Overlay(base.r, blend.r),
|
||||
BlendMode_Overlay(base.g, blend.g),
|
||||
BlendMode_Overlay(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Darkens or lightens the colors, depending on the blend color.
|
||||
//******************************************************************************
|
||||
float BlendMode_SoftLight(float base, float blend)
|
||||
{
|
||||
if (blend <= 0.5)
|
||||
{
|
||||
return base - (1-2*blend)*base*(1-base);
|
||||
}
|
||||
else
|
||||
{
|
||||
float d = (base <= 0.25) ? ((16*base-12)*base+4)*base : sqrt(base);
|
||||
return base + (2*blend-1)*(d-base);
|
||||
}
|
||||
}
|
||||
|
||||
float3 BlendMode_SoftLight(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_SoftLight(base.r, blend.r),
|
||||
BlendMode_SoftLight(base.g, blend.g),
|
||||
BlendMode_SoftLight(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Multiplies or screens the colors, depending on the blend color.
|
||||
//******************************************************************************
|
||||
float BlendMode_HardLight(float base, float blend)
|
||||
{
|
||||
return (blend <= 0.5) ? 2*base*blend : 1 - 2*(1-base)*(1-blend);
|
||||
}
|
||||
|
||||
float3 BlendMode_HardLight(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_HardLight(base.r, blend.r),
|
||||
BlendMode_HardLight(base.g, blend.g),
|
||||
BlendMode_HardLight(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Burns or dodges the colors by increasing or decreasing the contrast,
|
||||
// depending on the blend color.
|
||||
//******************************************************************************
|
||||
float BlendMode_VividLight(float base, float blend)
|
||||
{
|
||||
return (blend <= 0.5) ? BlendMode_ColorBurn(base,2*blend) : BlendMode_ColorDodge(base,2*(blend-0.5));
|
||||
}
|
||||
|
||||
float3 BlendMode_VividLight(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_VividLight(base.r, blend.r),
|
||||
BlendMode_VividLight(base.g, blend.g),
|
||||
BlendMode_VividLight(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Burns or dodges the colors by decreasing or increasing the brightness,
|
||||
// depending on the blend color.
|
||||
//******************************************************************************
|
||||
float BlendMode_LinearLight(float base, float blend)
|
||||
{
|
||||
return (blend <= 0.5) ? BlendMode_LinearBurn(base,2*blend) : BlendMode_LinearDodge(base,2*(blend-0.5));
|
||||
}
|
||||
|
||||
float3 BlendMode_LinearLight(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_LinearLight(base.r, blend.r),
|
||||
BlendMode_LinearLight(base.g, blend.g),
|
||||
BlendMode_LinearLight(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Replaces the colors, depending on the blend color.
|
||||
//******************************************************************************
|
||||
float BlendMode_PinLight(float base, float blend)
|
||||
{
|
||||
return (blend <= 0.5) ? min(base,2*blend) : max(base,2*(blend-0.5));
|
||||
}
|
||||
|
||||
float3 BlendMode_PinLight(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_PinLight(base.r, blend.r),
|
||||
BlendMode_PinLight(base.g, blend.g),
|
||||
BlendMode_PinLight(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Adds the red, green and blue channel values of the blend color to the RGB
|
||||
// values of the base color. If the resulting sum for a channel is 255 or
|
||||
// greater, it receives a value of 255; if less than 255, a value of 0.
|
||||
//******************************************************************************
|
||||
float BlendMode_HardMix(float base, float blend)
|
||||
{
|
||||
return (base + blend >= 1.0) ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
float3 BlendMode_HardMix(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_HardMix(base.r, blend.r),
|
||||
BlendMode_HardMix(base.g, blend.g),
|
||||
BlendMode_HardMix(base.b, blend.b) );
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and subtracts either the
|
||||
// blend color from the base color or the base color from the blend color,
|
||||
// depending on which has the greater brightness value.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Difference(float3 base, float3 blend)
|
||||
{
|
||||
return abs(base-blend);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Creates an effect similar to but lower in contrast than the Difference mode.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Exclusion(float3 base, float3 blend)
|
||||
{
|
||||
return base + blend - 2*base*blend;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and subtracts the blend color
|
||||
// from the base color.
|
||||
//******************************************************************************
|
||||
float3 BlendMode_Subtract(float3 base, float3 blend)
|
||||
{
|
||||
return max(0, base - blend);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Looks at the color information in each channel and divides the blend color
|
||||
// from the base color.
|
||||
//******************************************************************************
|
||||
float BlendMode_Divide(float base, float blend)
|
||||
{
|
||||
return blend > 0 ? min(1, base / blend) : 1;
|
||||
}
|
||||
|
||||
float3 BlendMode_Divide(float3 base, float3 blend)
|
||||
{
|
||||
return float3( BlendMode_Divide(base.r, blend.r),
|
||||
BlendMode_Divide(base.g, blend.g),
|
||||
BlendMode_Divide(base.b, blend.b) );
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR Apache-2.0) AND LicenseRef-ACES
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
License Terms for Academy Color Encoding System Components
|
||||
|
||||
Academy Color Encoding System (ACES) software and tools are provided by the
|
||||
Academy under the following terms and conditions: A worldwide, royalty-free,
|
||||
non-exclusive right to copy, modify, create derivatives, and use, in source and
|
||||
binary forms, is hereby granted, subject to acceptance of this license.
|
||||
|
||||
Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
|
||||
Portions contributed by others as indicated. All rights reserved.
|
||||
|
||||
Performance of any of the aforementioned acts indicates acceptance to be bound
|
||||
by the following terms and conditions:
|
||||
|
||||
* Copies of source code, in whole or in part, must retain the above copyright
|
||||
notice, this list of conditions and the Disclaimer of Warranty.
|
||||
* Use in binary form must retain the above copyright notice, this list of
|
||||
conditions and the Disclaimer of Warranty in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
* Nothing in this license shall be deemed to grant any rights to trademarks,
|
||||
copyrights, patents, trade secrets or any other intellectual property of
|
||||
A.M.P.A.S. or any contributors, except as expressly stated herein.
|
||||
* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
|
||||
software may be used to endorse or promote products derivative of or based on
|
||||
this software without express prior written permission of A.M.P.A.S. or the
|
||||
contributors, as appropriate.
|
||||
|
||||
This license shall be construed pursuant to the laws of the State of California,
|
||||
and any disputes related thereto shall be subject to the jurisdiction of the
|
||||
courts therein.
|
||||
|
||||
Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
|
||||
CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
|
||||
DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
|
||||
OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
|
||||
APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
|
||||
UNDISCLOSED.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
static const float HALF_MAX = 65504.0f;
|
||||
|
||||
float AcesCcToLinear(float value)
|
||||
{
|
||||
if (value < -0.3013698630) // (9.72-15)/17.52
|
||||
return (pow( 2., value*17.52-9.72) - pow( 2.,-16.))*2.0;
|
||||
else if (value < (log2(HALF_MAX)+9.72)/17.52)
|
||||
return pow( 2., value*17.52-9.72);
|
||||
else // (value >= (log2(HALF_MAX)+9.72)/17.52)
|
||||
return HALF_MAX;
|
||||
}
|
||||
|
||||
float3 AcesCcToAcesCg(float3 color)
|
||||
{
|
||||
return float3(
|
||||
AcesCcToLinear(color.r),
|
||||
AcesCcToLinear(color.g),
|
||||
AcesCcToLinear(color.b));
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR Apache-2.0) AND LicenseRef-ACES
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
License Terms for Academy Color Encoding System Components
|
||||
|
||||
Academy Color Encoding System (ACES) software and tools are provided by the
|
||||
Academy under the following terms and conditions: A worldwide, royalty-free,
|
||||
non-exclusive right to copy, modify, create derivatives, and use, in source and
|
||||
binary forms, is hereby granted, subject to acceptance of this license.
|
||||
|
||||
Copyright © 2015 Academy of Motion Picture Arts and Sciences (A.M.P.A.S.).
|
||||
Portions contributed by others as indicated. All rights reserved.
|
||||
|
||||
Performance of any of the aforementioned acts indicates acceptance to be bound
|
||||
by the following terms and conditions:
|
||||
|
||||
* Copies of source code, in whole or in part, must retain the above copyright
|
||||
notice, this list of conditions and the Disclaimer of Warranty.
|
||||
* Use in binary form must retain the above copyright notice, this list of
|
||||
conditions and the Disclaimer of Warranty in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
* Nothing in this license shall be deemed to grant any rights to trademarks,
|
||||
copyrights, patents, trade secrets or any other intellectual property of
|
||||
A.M.P.A.S. or any contributors, except as expressly stated herein.
|
||||
* Neither the name "A.M.P.A.S." nor the name of any other contributors to this
|
||||
software may be used to endorse or promote products derivative of or based on
|
||||
this software without express prior written permission of A.M.P.A.S. or the
|
||||
contributors, as appropriate.
|
||||
|
||||
This license shall be construed pursuant to the laws of the State of California,
|
||||
and any disputes related thereto shall be subject to the jurisdiction of the
|
||||
courts therein.
|
||||
|
||||
Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL A.M.P.A.S., OR ANY
|
||||
CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, RESITUTIONARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY SPECIFICALLY
|
||||
DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER RELATED TO PATENT OR
|
||||
OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY COLOR ENCODING SYSTEM, OR
|
||||
APPLICATIONS THEREOF, HELD BY PARTIES OTHER THAN A.M.P.A.S.,WHETHER DISCLOSED OR
|
||||
UNDISCLOSED.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
float LinearToAcesCc(float value)
|
||||
{
|
||||
if (value <= 0)
|
||||
return -0.3584474886; // =(log2( pow(2.,-16.))+9.72)/17.52
|
||||
else if (value < pow(2.,-15.))
|
||||
return (log2( pow(2.,-16.) + value * 0.5) + 9.72) / 17.52;
|
||||
else // (value >= pow(2.,-15))
|
||||
return (log2(value) + 9.72) / 17.52;
|
||||
}
|
||||
|
||||
float3 AcesCgToAcesCc(float3 color)
|
||||
{
|
||||
return float3(
|
||||
LinearToAcesCc(color.r),
|
||||
LinearToAcesCc(color.g),
|
||||
LinearToAcesCc(color.b)
|
||||
);
|
||||
}
|
||||
+44
-1
@@ -8,11 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RPI/Math.azsli>
|
||||
#include "GeneratedTransforms/LinearSrgb_To_AcesCg.azsli"
|
||||
#include "GeneratedTransforms/AcesCg_To_LinearSrgb.azsli"
|
||||
#include "GeneratedTransforms/LinearSrgb_To_Srgb.azsli"
|
||||
#include "GeneratedTransforms/Srgb_To_LinearSrgb.azsli"
|
||||
#include "GeneratedTransforms/Aces_To_AcesCg.azsli"
|
||||
#include "GeneratedTransforms/AcesCcToAcesCg.azsli"
|
||||
#include "GeneratedTransforms/AcesCgToAcesCc.azsli"
|
||||
#include "GeneratedTransforms/CalculateLuminance_LinearSrgb.azsli"
|
||||
#include "GeneratedTransforms/CalculateLuminance_AcesCg.azsli"
|
||||
|
||||
@@ -20,6 +23,7 @@ enum class ColorSpaceId
|
||||
{
|
||||
SRGB = 0,
|
||||
LinearSRGB,
|
||||
ACEScc,
|
||||
ACEScg,
|
||||
ACES2065,
|
||||
XYZ,
|
||||
@@ -51,15 +55,27 @@ float3 TransformColor(in float3 color, ColorSpaceId fromColorSpace, ColorSpaceId
|
||||
color = AcesCg_To_LinearSrgb(color);
|
||||
color = LinearSrgb_To_Srgb(color);
|
||||
}
|
||||
else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::LinearSRGB)
|
||||
{
|
||||
color = AcesCg_To_LinearSrgb(color);
|
||||
}
|
||||
else if (fromColorSpace == ColorSpaceId::ACEScg && toColorSpace == ColorSpaceId::ACEScc)
|
||||
{
|
||||
color = AcesCgToAcesCc(color);
|
||||
}
|
||||
else if (fromColorSpace == ColorSpaceId::ACES2065 && toColorSpace == ColorSpaceId::ACEScg)
|
||||
{
|
||||
color = Aces_To_AcesCg(color);
|
||||
}
|
||||
else if (fromColorSpace == ColorSpaceId::ACEScc && toColorSpace == ColorSpaceId::ACEScg)
|
||||
{
|
||||
color = AcesCcToAcesCg(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = float3(1, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -75,6 +91,7 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
|
||||
luminance = CalculateLuminance_AcesCg(color);
|
||||
break;
|
||||
case ColorSpaceId::SRGB:
|
||||
case ColorSpaceId::ACEScc:
|
||||
case ColorSpaceId::ACES2065:
|
||||
case ColorSpaceId::XYZ:
|
||||
case ColorSpaceId::Invalid:
|
||||
@@ -83,3 +100,29 @@ float CalculateLuminance(in float3 color, ColorSpaceId colorSpace)
|
||||
|
||||
return luminance;
|
||||
}
|
||||
|
||||
float RotateHue(float hue, float low, float hi)
|
||||
{
|
||||
return (hue < low)
|
||||
? hue + hi
|
||||
: (hue > hi)
|
||||
? hue - hi
|
||||
: hue;
|
||||
}
|
||||
|
||||
float3 RgbToHsv(float3 color)
|
||||
{
|
||||
const float4 k = float4(0.0f, -1.0f / 3.0f, 2.0f / 3.0f, -1.0f);
|
||||
const float4 p = lerp(float4(color.bg, k.wz), float4(color.gb, k.xy), step(color.b, color.g));
|
||||
const float4 q = lerp(float4(p.xyw, color.r), float4(color.r, p.yzx), step(p.x, color.r));
|
||||
const float d = q.x - min(q.w, q.y);
|
||||
const float e = EPSILON;
|
||||
return float3(abs(q.z + (q.w - q.y) / (6.0f * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
float3 HsvToRgb(float3 color)
|
||||
{
|
||||
const float4 k = float4(1.0f, 2.0f / 3.0f, 1.0f / 3.0f, 3.0f);
|
||||
const float3 p = abs(frac(color.xxx + k.xyz) * 6.0f - k.www);
|
||||
return color.z * lerp(k.xxx, saturate(p - k.xxx), color.y);
|
||||
}
|
||||
|
||||
+14
-82
@@ -101,7 +101,6 @@ class DirectionalLightShadow
|
||||
// This outputs visibility ratio (from 0.0 to 1.0) for ESM+PCF.
|
||||
float GetVisibilityFromLightEsmPcf();
|
||||
|
||||
float SamplePcfBicubic();
|
||||
float SamplePcfBicubic(float3 shadowCoord, uint indexOfCascade);
|
||||
|
||||
uint m_lightIndex;
|
||||
@@ -278,70 +277,26 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter()
|
||||
}
|
||||
|
||||
float DirectionalLightShadow::GetVisibilityFromLightPcf()
|
||||
{
|
||||
const uint predictionCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_predictionSampleCount;
|
||||
{
|
||||
static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
|
||||
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
|
||||
|
||||
if (predictionCount <= 1)
|
||||
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;
|
||||
for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade)
|
||||
{
|
||||
return GetVisibilityFromLightNoFilter();
|
||||
}
|
||||
const float3 shadowCoord = m_shadowCoords[indexOfCascade];
|
||||
|
||||
if (ViewSrg::m_directionalLightShadows[m_lightIndex].m_pcfFilterMethod == PcfFilterMethod_Bicubic)
|
||||
{
|
||||
return SamplePcfBicubic();
|
||||
}
|
||||
|
||||
const float3 lightDirection =
|
||||
normalize(SceneSrg::m_directionalLights[m_lightIndex].m_direction);
|
||||
const float4 jitterUnitVectorDepthDiffBase =
|
||||
Shadow::GetJitterUnitVectorDepthDiffBase(m_normalVector, lightDirection);
|
||||
const float3 jitterUnit = jitterUnitVectorDepthDiffBase.xyz;
|
||||
const float jitterDepthDiffBase = jitterUnitVectorDepthDiffBase.w;
|
||||
|
||||
uint shadowedCount = 0;
|
||||
uint jitterIndex = 0;
|
||||
|
||||
// Predicting
|
||||
for (; jitterIndex < predictionCount; ++jitterIndex)
|
||||
{
|
||||
if (IsShadowedWithJitter(
|
||||
jitterUnit,
|
||||
jitterDepthDiffBase,
|
||||
jitterIndex))
|
||||
if (shadowCoord.x >= 0. && shadowCoord.x * size < size - PixelMargin &&
|
||||
shadowCoord.y >= 0. && shadowCoord.y * size < size - PixelMargin &&
|
||||
shadowCoord.z < 1. - DepthMargin)
|
||||
{
|
||||
++shadowedCount;
|
||||
m_debugInfo.m_cascadeIndex = indexOfCascade;
|
||||
return SamplePcfBicubic(shadowCoord, indexOfCascade);
|
||||
}
|
||||
}
|
||||
if (shadowedCount == 0)
|
||||
{
|
||||
return 1.;
|
||||
}
|
||||
else if (shadowedCount == predictionCount)
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
// Filtering
|
||||
|
||||
// When the prediction detects the point on the boundary of shadow,
|
||||
// i.e., both of a lit point and a a shadowed one exists in the jittering area,
|
||||
// we calculate the more precious lit ratio in the area.
|
||||
const uint filteringCount = max(
|
||||
predictionCount,
|
||||
ViewSrg::m_directionalLightShadows[m_lightIndex].m_filteringSampleCount);
|
||||
|
||||
for (; jitterIndex < filteringCount; ++jitterIndex)
|
||||
{
|
||||
if (IsShadowedWithJitter(
|
||||
jitterUnit,
|
||||
jitterDepthDiffBase,
|
||||
jitterIndex))
|
||||
{
|
||||
++shadowedCount;
|
||||
}
|
||||
}
|
||||
|
||||
return (filteringCount - shadowedCount) * 1. / filteringCount;
|
||||
m_debugInfo.m_cascadeIndex = cascadeCount;
|
||||
return 1.;
|
||||
}
|
||||
|
||||
float DirectionalLightShadow::GetVisibilityFromLightEsm()
|
||||
@@ -415,29 +370,6 @@ float DirectionalLightShadow::GetVisibilityFromLightEsmPcf()
|
||||
return 1.;
|
||||
}
|
||||
|
||||
float DirectionalLightShadow::SamplePcfBicubic()
|
||||
{
|
||||
static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
|
||||
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
|
||||
|
||||
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;
|
||||
for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade)
|
||||
{
|
||||
const float3 shadowCoord = m_shadowCoords[indexOfCascade];
|
||||
|
||||
if (shadowCoord.x >= 0. && shadowCoord.x * size < size - PixelMargin &&
|
||||
shadowCoord.y >= 0. && shadowCoord.y * size < size - PixelMargin &&
|
||||
shadowCoord.z < 1. - DepthMargin)
|
||||
{
|
||||
m_debugInfo.m_cascadeIndex = indexOfCascade;
|
||||
return SamplePcfBicubic(shadowCoord, indexOfCascade);
|
||||
}
|
||||
}
|
||||
m_debugInfo.m_cascadeIndex = cascadeCount;
|
||||
return 1.;
|
||||
}
|
||||
|
||||
float DirectionalLightShadow::SamplePcfBicubic(float3 shadowCoord, uint indexOfCascade)
|
||||
{
|
||||
const uint filteringSampleCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_filteringSampleCount;
|
||||
|
||||
+18
-91
@@ -44,8 +44,6 @@ class ProjectedShadow
|
||||
float GetVisibilityEsmPcf();
|
||||
float GetThickness();
|
||||
|
||||
float SamplePcfBicubic();
|
||||
|
||||
bool IsShadowed(float3 shadowPosition);
|
||||
bool IsShadowedWithJitter(
|
||||
float3 jitterUnitX,
|
||||
@@ -87,8 +85,7 @@ float ProjectedShadow::GetVisibility(
|
||||
shadow.SetShadowPosition();
|
||||
|
||||
float visibility = 1.;
|
||||
// Filter method is stored in top 16 bits.
|
||||
uint filterMethod = ViewSrg::m_projectedShadows[shadow.m_shadowIndex].m_shadowFilterMethod & 0x0000FFFF;
|
||||
const uint filterMethod = ViewSrg::m_projectedShadows[shadow.m_shadowIndex].m_shadowFilterMethod;
|
||||
switch (filterMethod)
|
||||
{
|
||||
case ViewSrg::ShadowFilterMethodNone:
|
||||
@@ -145,72 +142,29 @@ float ProjectedShadow::GetVisibilityNoFilter()
|
||||
|
||||
float ProjectedShadow::GetVisibilityPcf()
|
||||
{
|
||||
// PCF filter method is stored in bottom 16 bits.
|
||||
const uint pcfFilterMethod = ViewSrg::m_projectedShadows[m_shadowIndex].m_shadowFilterMethod >> 16;
|
||||
if (pcfFilterMethod == PcfFilterMethod_Bicubic)
|
||||
const uint filteringSampleCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount;
|
||||
const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy);
|
||||
|
||||
SampleShadowMapBicubicParameters param;
|
||||
param.shadowMap = PassSrg::m_projectedShadowmaps;
|
||||
param.shadowPos = float3(atlasPosition.xy * ViewSrg::m_invShadowmapAtlasSize, atlasPosition.z);
|
||||
param.shadowMapSize = ViewSrg::m_shadowmapAtlasSize;
|
||||
param.invShadowMapSize = ViewSrg::m_invShadowmapAtlasSize;
|
||||
param.comparisonValue = m_shadowPosition.z - m_bias;
|
||||
param.samplerState = SceneSrg::m_hwPcfSampler;
|
||||
|
||||
if (filteringSampleCount <= 4)
|
||||
{
|
||||
return SamplePcfBicubic();
|
||||
return SampleShadowMapBicubic_4Tap(param);
|
||||
}
|
||||
|
||||
const uint predictionCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_predictionSampleCount;
|
||||
|
||||
if (predictionCount <= 1)
|
||||
else if (filteringSampleCount <= 9)
|
||||
{
|
||||
return GetVisibilityNoFilter();
|
||||
return SampleShadowMapBicubic_9Tap(param);
|
||||
}
|
||||
|
||||
const float4 jitterUnitVectorDepthDiffBase =
|
||||
Shadow::GetJitterUnitVectorDepthDiffBase(m_normalVector, m_lightDirection);
|
||||
const float3 jitterUnitY = jitterUnitVectorDepthDiffBase.xyz;
|
||||
const float3 jitterUnitX = cross(jitterUnitY, m_lightDirection);
|
||||
const float jitterDepthDiffBase = jitterUnitVectorDepthDiffBase.w;
|
||||
|
||||
uint shadowedCount = 0;
|
||||
uint jitterIndex = 0;
|
||||
|
||||
// Predicting
|
||||
for (; jitterIndex < predictionCount; ++jitterIndex)
|
||||
else
|
||||
{
|
||||
if (IsShadowedWithJitter(
|
||||
jitterUnitX,
|
||||
jitterUnitY,
|
||||
jitterDepthDiffBase,
|
||||
jitterIndex))
|
||||
{
|
||||
++shadowedCount;
|
||||
}
|
||||
return SampleShadowMapBicubic_16Tap(param);
|
||||
}
|
||||
if (shadowedCount == 0)
|
||||
{
|
||||
return 1.;
|
||||
}
|
||||
else if (shadowedCount == predictionCount)
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
// Filtering
|
||||
|
||||
// When the prediction detects the point on the boundary of shadow,
|
||||
// i.e., both of a lit point and a a shadowed one exists in the jittering area,
|
||||
// we calculate the more precious lit ratio in the area.
|
||||
const uint filteringCount = max(
|
||||
predictionCount,
|
||||
ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount);
|
||||
|
||||
for (; jitterIndex < filteringCount; ++jitterIndex)
|
||||
{
|
||||
if (IsShadowedWithJitter(
|
||||
jitterUnitX,
|
||||
jitterUnitY,
|
||||
jitterDepthDiffBase,
|
||||
jitterIndex))
|
||||
{
|
||||
++shadowedCount;
|
||||
}
|
||||
}
|
||||
|
||||
return (filteringCount - shadowedCount) * 1. / filteringCount;
|
||||
}
|
||||
|
||||
float ProjectedShadow::GetVisibilityEsm()
|
||||
@@ -337,33 +291,6 @@ float ProjectedShadow::GetThickness()
|
||||
return 0.;
|
||||
}
|
||||
|
||||
float ProjectedShadow::SamplePcfBicubic()
|
||||
{
|
||||
const uint filteringSampleCount = ViewSrg::m_projectedShadows[m_shadowIndex].m_filteringSampleCount;
|
||||
const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy);
|
||||
|
||||
SampleShadowMapBicubicParameters param;
|
||||
param.shadowMap = PassSrg::m_projectedShadowmaps;
|
||||
param.shadowPos = float3(atlasPosition.xy * ViewSrg::m_invShadowmapAtlasSize, atlasPosition.z);
|
||||
param.shadowMapSize = ViewSrg::m_shadowmapAtlasSize;
|
||||
param.invShadowMapSize = ViewSrg::m_invShadowmapAtlasSize;
|
||||
param.comparisonValue = m_shadowPosition.z - m_bias;
|
||||
param.samplerState = SceneSrg::m_hwPcfSampler;
|
||||
|
||||
if (filteringSampleCount <= 4)
|
||||
{
|
||||
return SampleShadowMapBicubic_4Tap(param);
|
||||
}
|
||||
else if (filteringSampleCount <= 9)
|
||||
{
|
||||
return SampleShadowMapBicubic_9Tap(param);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SampleShadowMapBicubic_16Tap(param);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProjectedShadow::IsShadowed(float3 shadowPosition)
|
||||
{
|
||||
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
|
||||
|
||||
+1
-1
@@ -35,4 +35,4 @@ float ApplyReceiverPlaneDepthBias(const float2 receiverPlaneDepthBias, const flo
|
||||
// Clamping this will remove this effect
|
||||
fragmentDepthBias = min(fragmentDepthBias, 0.0);
|
||||
return fragmentDepthBias;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ partial ShaderResourceGroup ViewSrg
|
||||
{
|
||||
float4x4 m_depthBiasMatrix;
|
||||
uint m_shadowmapArraySlice; // array slice who has shadowmap in the atlas.
|
||||
uint m_shadowFilterMethod; // Includes overall filter method in top 16 bits and pcf method in bottom 16 bits.
|
||||
uint m_shadowFilterMethod;
|
||||
float m_boundaryScale;
|
||||
uint m_predictionSampleCount;
|
||||
uint m_filteringSampleCount;
|
||||
@@ -117,8 +117,6 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_debugFlags;
|
||||
uint m_shadowFilterMethod;
|
||||
float m_far_minus_near;
|
||||
uint m_pcfFilterMethod; // Matches with PcfFilterMethod in ShadowConstants.h
|
||||
uint m_padding[3];
|
||||
};
|
||||
|
||||
enum ShadowFilterMethod
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
// Please review README.md to understand how this file is used in SceneSrg.azsrg generation
|
||||
|
||||
#ifdef AZ_COLLECTING_PARTIAL_SRGS
|
||||
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneTimeSrg.azsli>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultSceneSrg.azsli>
|
||||
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneSrg.azsli>
|
||||
#endif
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
|
||||
|
||||
#include <Atom/Features/Math/Filter.azsli>
|
||||
#include <Atom/Features/Math/FilterPassSrg.azsli>
|
||||
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
|
||||
|
||||
[numthreads(16,16,1)]
|
||||
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
|
||||
{
|
||||
const float3 inputSize = GetImageSize(FilterPassSrg::m_inputImage);
|
||||
const float3 outputSize = GetImageSize(FilterPassSrg::m_outputImage);
|
||||
|
||||
const uint shadowmapIndex = GetShadowmapIndex(
|
||||
FilterPassSrg::m_shadowmapIndexTable,
|
||||
dispatchId,
|
||||
inputSize.x);
|
||||
// Early return if thread is outside of shadowmaps.
|
||||
if (shadowmapIndex == ~0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
|
||||
const uint shadowmapSize = filterParameter.m_shadowmapSize;
|
||||
// Early return if filter is disabled.
|
||||
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
|
||||
{
|
||||
return; // early return if filter parameter is empty.
|
||||
}
|
||||
|
||||
const uint sourceMin = filterParameter.m_shadowmapOriginInSlice.x;
|
||||
const uint sourceMax = sourceMin + shadowmapSize - 1;
|
||||
|
||||
uint filterTableSize = 0;
|
||||
FilterPassSrg::m_filterTable.GetDimensions(filterTableSize);
|
||||
if (filterTableSize == 0 || filterParameter.m_parameterCount == 0)
|
||||
{
|
||||
return; // If filter parameter is empty, early return.
|
||||
}
|
||||
|
||||
// [GFX TODO][ATOM-5676] pass proper source min/max for each shadowmap
|
||||
const float result = FilteredFloat(
|
||||
dispatchId,
|
||||
FilterPassSrg::m_inputImage,
|
||||
uint2(1, 0), // horizontal
|
||||
sourceMin,
|
||||
sourceMax,
|
||||
FilterPassSrg::m_filterTable,
|
||||
filterParameter.m_parameterOffset,
|
||||
filterParameter.m_parameterCount);
|
||||
|
||||
FilterPassSrg::m_outputImage[dispatchId].r = result;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"Source" : "GaussianFilterFloatHorizontal",
|
||||
|
||||
"DrawList" : "shadow",
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "MainCS",
|
||||
"type": "Compute"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
|
||||
|
||||
#include <Atom/Features/Math/Filter.azsli>
|
||||
#include <Atom/Features/Math/FilterPassSrg.azsli>
|
||||
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
|
||||
|
||||
[numthreads(16,16,1)]
|
||||
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
|
||||
{
|
||||
const float3 inputSize = GetImageSize(FilterPassSrg::m_inputImage);
|
||||
const float3 outputSize = GetImageSize(FilterPassSrg::m_outputImage);
|
||||
|
||||
const uint shadowmapIndex = GetShadowmapIndex(
|
||||
FilterPassSrg::m_shadowmapIndexTable,
|
||||
dispatchId,
|
||||
inputSize.x);
|
||||
// Early return if thread is outside of shadowmaps.
|
||||
if (shadowmapIndex == ~0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
|
||||
const uint shadowmapSize = filterParameter.m_shadowmapSize;
|
||||
// Early return if filter is disabled.
|
||||
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
|
||||
{
|
||||
return; // early return if filter parameter is empty.
|
||||
}
|
||||
|
||||
const uint sourceMin = filterParameter.m_shadowmapOriginInSlice.y;
|
||||
const uint sourceMax = sourceMin + shadowmapSize - 1;
|
||||
|
||||
uint filterTableSize = 0;
|
||||
FilterPassSrg::m_filterTable.GetDimensions(filterTableSize);
|
||||
if (filterTableSize == 0 || filterParameter.m_parameterCount == 0)
|
||||
{
|
||||
return; // If filter parameter is empty, early return.
|
||||
}
|
||||
|
||||
// [GFX TODO][ATOM-5676] pass proper source min/max for each shadowmap
|
||||
const float result = FilteredFloat(
|
||||
dispatchId,
|
||||
FilterPassSrg::m_inputImage,
|
||||
uint2(0, 1), // vertical
|
||||
sourceMin,
|
||||
sourceMax,
|
||||
FilterPassSrg::m_filterTable,
|
||||
filterParameter.m_parameterOffset,
|
||||
filterParameter.m_parameterCount);
|
||||
|
||||
FilterPassSrg::m_outputImage[dispatchId].r = result;
|
||||
}
|
||||
@@ -78,10 +78,12 @@ void MainCS(uint3 dispatch_id : SV_DispatchThreadID)
|
||||
const float speed = exposureDifference > 0.0 ? ViewSrg::m_exposureControl.m_speedUp : ViewSrg::m_exposureControl.m_speedDown;
|
||||
|
||||
// Update the adjustment for this frame based on the frame deltaTime and speed
|
||||
float exposureAdjustment = exposureDifference * SceneSrg::m_deltaTime * speed;
|
||||
float deltaTime = clamp(SceneSrg::m_time - PassSrg::m_eyeAdaptationData[0].m_setValueTime, 0.0f, 1.0f);
|
||||
float exposureAdjustment = exposureDifference * deltaTime * speed;
|
||||
float newExposureLog2 = previousFrameExposureLog2 + exposureAdjustment;
|
||||
|
||||
// Store the linear exposure so it can be used by the look modification transform later.
|
||||
// newExposureLog2 is negated because m_exposureValue is used to correct for a given exposure.
|
||||
PassSrg::m_eyeAdaptationData[0].m_exposureValue = pow(2.0f, -newExposureLog2);
|
||||
PassSrg::m_eyeAdaptationData[0].m_setValueTime = SceneSrg::m_time;
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
|
||||
struct EyeAdaptation
|
||||
{
|
||||
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
|
||||
float m_exposureValue; // current frame's exposure value in stops (logarithmic space)
|
||||
float m_setValueTime; // the time when the m_exposureValue was set
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ int GetLdsIndex(int2 ldsPosition)
|
||||
|
||||
// --- Common file start ---
|
||||
|
||||
// #include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli>
|
||||
// include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli> ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
|
||||
// This include fails with the asset processor when generating the .shader for this file
|
||||
// Everything below this is copy pasted from FastDepthAwareBlurCommon.azsli up until the
|
||||
// "Common file end" marker below
|
||||
|
||||
@@ -55,7 +55,7 @@ int GetLdsIndex(int2 ldsPosition)
|
||||
|
||||
// --- Common file start ---
|
||||
|
||||
// #include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli>
|
||||
// include <Atom/Features/PostProcessing/FastDepthAwareBlurCommon.azsli> ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
|
||||
// This include fails with the asset processor when generating the .shader for this file
|
||||
// Everything below this is copy pasted from FastDepthAwareBlurCommon.azsli up until the
|
||||
// "Common file end" marker below
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/RPI/Math.azsli>
|
||||
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
|
||||
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
|
||||
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
|
||||
|
||||
#include <Atom/Features/ColorManagement/TransformColor.azsli>
|
||||
#include <Atom/Features/PostProcessing/AcesColorSpaceConversion.azsli>
|
||||
#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli>
|
||||
#include <3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli>
|
||||
#include <3rdParty/Features/PostProcessing/KelvinToRgb.azsli>
|
||||
|
||||
static const float FloatEpsilon = 1.192092896e-07; // 1.0 + FloatEpsilon != 1.0, smallest positive float
|
||||
static const float FloatMin = FLOAT_32_MIN; // Min float number that is positive
|
||||
static const float FloatMax = FLOAT_32_MAX; // Max float number representable
|
||||
|
||||
static const float AcesCcMidGrey = 0.4135884;
|
||||
|
||||
ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
|
||||
{
|
||||
// get the framebuffer
|
||||
Texture2D<float4> m_framebuffer;
|
||||
|
||||
// framebuffer sampler
|
||||
Sampler LinearSampler
|
||||
{
|
||||
MinFilter = Linear;
|
||||
MagFilter = Linear;
|
||||
MipFilter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
AddressW = Clamp;
|
||||
};
|
||||
|
||||
float m_colorGradingExposure;
|
||||
float m_colorGradingContrast;
|
||||
float m_colorGradingHueShift;
|
||||
float m_colorGradingPreSaturation;
|
||||
float m_colorFilterIntensity;
|
||||
float m_colorFilterMultiply;
|
||||
float m_whiteBalanceKelvin;
|
||||
float m_whiteBalanceTint;
|
||||
float m_splitToneBalance;
|
||||
float m_splitToneMix;
|
||||
float m_colorGradingPostSaturation;
|
||||
float m_smhShadowsStart;
|
||||
float m_smhShadowsEnd;
|
||||
float m_smhHighlightsStart;
|
||||
float m_smhHighlightsEnd;
|
||||
float m_smhMix;
|
||||
|
||||
float3 m_channelMixingRed;
|
||||
float3 m_channelMixingGreen;
|
||||
float3 m_channelMixingBlue;
|
||||
|
||||
float4 m_colorFilterSwatch;
|
||||
float4 m_splitToneShadowsColor;
|
||||
float4 m_splitToneHighlightsColor;
|
||||
|
||||
float4 m_smhShadowsColor;
|
||||
float4 m_smhMidtonesColor;
|
||||
float4 m_smhHighlightsColor;
|
||||
|
||||
// my color grading output
|
||||
float4 m_color;
|
||||
}
|
||||
|
||||
float SaturateWithEpsilon(float value)
|
||||
{
|
||||
return clamp(value, FloatEpsilon, 1.0f);
|
||||
}
|
||||
|
||||
// Below are the color grading functions. These expect the frame color to be in ACEScg space.
|
||||
// Note that some functions may have some quirks in their implementation and is subject to change.
|
||||
float3 ColorGradePostExposure (float3 frameColor, float exposure)
|
||||
{
|
||||
frameColor *= pow(2.0f, exposure);
|
||||
return frameColor;
|
||||
}
|
||||
|
||||
// The contrast equation is performed in ACEScc (logarithmic) color space.
|
||||
float3 ColorGradingContrast (float3 frameColor, float midgrey, float amount)
|
||||
{
|
||||
const float contrastAdjustment = amount * 0.01f + 1.0f;
|
||||
frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScg, ColorSpaceId::ACEScc);
|
||||
frameColor = (frameColor - midgrey) * contrastAdjustment + midgrey;
|
||||
return frameColor = TransformColor(frameColor.rgb, ColorSpaceId::ACEScc, ColorSpaceId::ACEScg);
|
||||
}
|
||||
|
||||
// The swatchColor param expects a linear RGB value.
|
||||
float3 ColorGradeColorFilter (float3 frameColor, float3 swatchColor, float alpha)
|
||||
{
|
||||
swatchColor = TransformColor(swatchColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
swatchColor *= pow(2.0f, PassSrg::m_colorFilterIntensity);
|
||||
const float3 frameAdjust = frameColor * swatchColor;
|
||||
return frameColor = lerp(frameColor, frameAdjust, alpha);
|
||||
}
|
||||
|
||||
float3 ColorGradeHueShift (float3 frameColor, float amount)
|
||||
{
|
||||
float3 frameHsv = RgbToHsv(frameColor);
|
||||
const float hue = frameHsv.x + amount;
|
||||
frameHsv.x = RotateHue(hue, 0.0, 1.0);
|
||||
return HsvToRgb(frameHsv);
|
||||
}
|
||||
|
||||
float3 ColorGradeSaturation (float3 frameColor, float control)
|
||||
{
|
||||
const float vLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
|
||||
return (frameColor - vLuminance) * control + vLuminance;
|
||||
}
|
||||
|
||||
float3 ColorGradeKelvinColorTemp(float3 frameColor, float kelvin)
|
||||
{
|
||||
const float3 kColor = TransformColor(KelvinToRgb(kelvin), ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
const float luminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
|
||||
const float3 resHsl = RgbToHsl(frameColor.rgb * kColor.rgb); // Apply Kelvin color and convert to HSL
|
||||
return HslToRgb(float3(resHsl.xy, luminance)); // Preserve luminance
|
||||
}
|
||||
|
||||
// pow(f, e) won't work if f is negative, or may cause inf/NAN.
|
||||
float3 NoNanPow(float3 base, float3 power)
|
||||
{
|
||||
return pow(max(abs(base), float3(FloatEpsilon, FloatEpsilon, FloatEpsilon)), power);
|
||||
}
|
||||
|
||||
float3 ColorGradeSplitTone (float3 frameColor, float balance, float mix)
|
||||
{
|
||||
float3 frameSplitTone = NoNanPow(frameColor, 1.0 / 2.2);
|
||||
const float t = SaturateWithEpsilon(CalculateLuminance(SaturateWithEpsilon(frameSplitTone), ColorSpaceId::ACEScg) + balance);
|
||||
const float3 shadows = lerp(0.5, PassSrg::m_splitToneShadowsColor.rgb, 1.0 - t);
|
||||
const float3 highlights = lerp(0.5, PassSrg::m_splitToneHighlightsColor.rgb, t);
|
||||
frameSplitTone = BlendMode_SoftLight(frameSplitTone, shadows);
|
||||
frameSplitTone = BlendMode_SoftLight(frameSplitTone, highlights);
|
||||
frameSplitTone = NoNanPow(frameSplitTone, 2.2);
|
||||
return lerp(frameColor.rgb, frameSplitTone.rgb, mix);
|
||||
}
|
||||
|
||||
float3 ColorGradeChannelMixer (float3 frameColor)
|
||||
{
|
||||
return mul(float3x3(PassSrg::m_channelMixingRed.rgb,
|
||||
PassSrg::m_channelMixingGreen.rgb,
|
||||
PassSrg::m_channelMixingBlue.rgb),
|
||||
frameColor);
|
||||
}
|
||||
|
||||
float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStart, float shadowsEnd,
|
||||
float highlightsStart, float highlightsEnd, float mix,
|
||||
float4 shadowsColor, float4 midtonesColor, float4 highlightsColor)
|
||||
{
|
||||
const float3 shadowsColorACEScg = TransformColor(shadowsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
const float3 midtonesColorACEScg = TransformColor(midtonesColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
const float3 highlightsColorACEScg = TransformColor(highlightsColor.rgb, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
|
||||
const float cLuminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
|
||||
const float shadowsWeight = 1.0 - smoothstep(shadowsStart, shadowsEnd, cLuminance);
|
||||
const float highlightsWeight = smoothstep(highlightsStart, highlightsEnd, cLuminance);
|
||||
const float midtonesWeight = 1.0 - shadowsWeight - highlightsWeight;
|
||||
|
||||
const float3 frameSmh = frameColor * shadowsColorACEScg * shadowsWeight +
|
||||
frameColor * midtonesColorACEScg * midtonesWeight +
|
||||
frameColor * highlightsColorACEScg * highlightsWeight;
|
||||
return lerp(frameColor.rgb, frameSmh.rgb, mix);
|
||||
}
|
||||
|
||||
float3 ColorGrade (float3 frameColor)
|
||||
{
|
||||
frameColor = ColorGradePostExposure(frameColor, PassSrg::m_colorGradingExposure);
|
||||
frameColor = ColorGradeKelvinColorTemp(frameColor, PassSrg::m_whiteBalanceKelvin);
|
||||
frameColor = ColorGradingContrast(frameColor, AcesCcMidGrey, PassSrg::m_colorGradingContrast);
|
||||
frameColor = ColorGradeColorFilter(frameColor, PassSrg::m_colorFilterSwatch.rgb,
|
||||
PassSrg::m_colorFilterMultiply);
|
||||
frameColor = max(frameColor, 0.0);
|
||||
frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPreSaturation);
|
||||
frameColor = ColorGradeSplitTone(frameColor, PassSrg::m_splitToneBalance, PassSrg::m_splitToneMix);
|
||||
frameColor = ColorGradeChannelMixer(frameColor);
|
||||
frameColor = max(frameColor, 0.0);
|
||||
frameColor = ColorGradeShadowsMidtonesHighlights(frameColor, PassSrg::m_smhShadowsStart, PassSrg::m_smhShadowsEnd,
|
||||
PassSrg::m_smhHighlightsStart, PassSrg::m_smhHighlightsEnd, PassSrg::m_smhMix,
|
||||
PassSrg::m_smhShadowsColor, PassSrg::m_smhMidtonesColor, PassSrg::m_smhHighlightsColor);
|
||||
frameColor = ColorGradeHueShift(frameColor, PassSrg::m_colorGradingHueShift);
|
||||
frameColor = ColorGradeSaturation(frameColor, PassSrg::m_colorGradingPostSaturation);
|
||||
return frameColor.rgb;
|
||||
}
|
||||
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
PSOutput OUT;
|
||||
|
||||
// Fetch the pixel color from the input texture
|
||||
float3 frameColor = PassSrg::m_framebuffer.Sample(PassSrg::LinearSampler, IN.m_texCoord).rgb;
|
||||
|
||||
OUT.m_color.rgb = ColorGrade(frameColor);
|
||||
OUT.m_color.w = 1;
|
||||
|
||||
return OUT;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Source" : "HDRColorGrading",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"Depth" : { "Enable" : false }
|
||||
},
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "MainVS",
|
||||
"type": "Vertex"
|
||||
},
|
||||
{
|
||||
"name": "MainPS",
|
||||
"type": "Fragment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@
|
||||
* #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0)
|
||||
* #define SMAA_HLSL_4
|
||||
* #define SMAA_PRESET_HIGH
|
||||
* #include "SMAA.h"
|
||||
* include "SMAA.h" ('#' symbol before 'include' was removed on purpose to avoid parsing this azsli file during ShaderAssetBuilder::CreateJobs)
|
||||
*
|
||||
* Note that SMAA_RT_METRICS doesn't need to be a macro, it can be a
|
||||
* uniform variable. The code is designed to minimize the impact of not
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// [GFX TODO][ATOM-3365] optimization using intermediary results in groupshared memory.
|
||||
|
||||
// This shader blurs the ESM results using a multi-pass kawase filter.
|
||||
// It should generally be faster than separable gaussian blur
|
||||
// https://software.intel.com/content/www/us/en/develop/blogs/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms.html
|
||||
|
||||
#include <Atom/Features/Math/Filter.azsli>
|
||||
#include <Atom/Features/Shadow/ShadowmapAtlasLib.azsli>
|
||||
#include <Atom/Features/Shadow/Shadow.azsli>
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
|
||||
ShaderResourceGroup FilterPassSrg : SRG_PerPass
|
||||
{
|
||||
// This shader filters multiple images with distinct filter parameters.
|
||||
// So, the input and output are arrays of texture2Ds.
|
||||
Texture2DArray<float> m_inputImage;
|
||||
RWTexture2DArray<float> m_outputImage;
|
||||
|
||||
// This can convert a coordinate in an atlas to
|
||||
// the shadowmap index.
|
||||
Buffer<uint2> m_shadowmapIndexTable;
|
||||
|
||||
// This contains parameters related to filtering.
|
||||
StructuredBuffer<FilterParameter> m_filterParameters;
|
||||
|
||||
// x and y contain the inverse of the texture map resolution, z contains the kawase iteration
|
||||
// i.e. a two pass kawase blur passes in 0 for the 1st pass and 1 for the second pass
|
||||
float4 m_rcpResolutionAndIteration;
|
||||
|
||||
Sampler LinearSampler
|
||||
{
|
||||
MinFilter = Linear;
|
||||
MagFilter = Linear;
|
||||
MipFilter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
AddressW = Clamp;
|
||||
};
|
||||
}
|
||||
|
||||
void CalculateBlurBoundaries(const uint shadowmapIndex, out float2 sourceMinTex, out float2 sourceMaxTex)
|
||||
{
|
||||
const float2 rcpPixelSize = FilterPassSrg::m_rcpResolutionAndIteration.xy;
|
||||
|
||||
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
|
||||
const uint shadowmapSize = filterParameter.m_shadowmapSize;
|
||||
|
||||
// location of the shadow bounds in texels
|
||||
const uint2 sourceMinPixel = filterParameter.m_shadowmapOriginInSlice.xy;
|
||||
const uint2 sourceMaxPixel = sourceMinPixel + shadowmapSize - 1;
|
||||
|
||||
// location of the shadow bounds in uv space
|
||||
sourceMinTex = (sourceMinPixel + 0.5f) * rcpPixelSize;
|
||||
sourceMaxTex = (sourceMaxPixel + 0.5f) * rcpPixelSize;
|
||||
}
|
||||
|
||||
float AccumulateShadowSamples(Texture2DArray<float> tex, float3 texCoord, SamplerState s)
|
||||
{
|
||||
float4 values = tex.GatherRed(s, texCoord);
|
||||
float result = values.x + values.y + values.z + values.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
[numthreads(16,16,1)]
|
||||
void MainCS(uint3 dispatchId: SV_DispatchThreadID)
|
||||
{
|
||||
const float inputSize = GetImageSize(FilterPassSrg::m_inputImage).x;
|
||||
const uint shadowmapIndex = GetShadowmapIndex(
|
||||
FilterPassSrg::m_shadowmapIndexTable,
|
||||
dispatchId,
|
||||
inputSize);
|
||||
|
||||
// Early return if thread is outside of shadowmaps.
|
||||
if (shadowmapIndex == ~0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FilterParameter filterParameter = FilterPassSrg::m_filterParameters[shadowmapIndex];
|
||||
const uint shadowmapSize = filterParameter.m_shadowmapSize;
|
||||
// Early return if filter is disabled.
|
||||
if (!filterParameter.m_isEnabled || shadowmapSize <= 1)
|
||||
{
|
||||
return; // early return if filter parameter is empty.
|
||||
}
|
||||
|
||||
const float2 rcpPixelSize = FilterPassSrg::m_rcpResolutionAndIteration.xy;
|
||||
const float blurIteration = FilterPassSrg::m_rcpResolutionAndIteration.z;
|
||||
|
||||
float2 sourceMinTex, sourceMaxTex;
|
||||
CalculateBlurBoundaries(shadowmapIndex, sourceMinTex, sourceMaxTex);
|
||||
|
||||
const float2 halfRcpPixelSize = rcpPixelSize / 2.0f;
|
||||
const float2 dUV = rcpPixelSize.xy * blurIteration + halfRcpPixelSize.xy;
|
||||
const float2 texCoord = (dispatchId.xy + 0.5f) * rcpPixelSize;
|
||||
|
||||
const float3 texCoordSamples[4] = {
|
||||
float3(texCoord.x - dUV.x, texCoord.y - dUV.y, dispatchId.z),
|
||||
float3(texCoord.x - dUV.x, texCoord.y + dUV.y, dispatchId.z),
|
||||
float3(texCoord.x + dUV.x, texCoord.y - dUV.y, dispatchId.z),
|
||||
float3(texCoord.x + dUV.x, texCoord.y + dUV.y, dispatchId.z),
|
||||
};
|
||||
|
||||
float accumulatedBlur = 0;
|
||||
float numSamplesAccumulated = 0;
|
||||
for(int i = 0 ; i < 4; ++i)
|
||||
{
|
||||
if (texCoordSamples[i].x >= sourceMinTex.x &&
|
||||
texCoordSamples[i].y >= sourceMinTex.y &&
|
||||
texCoordSamples[i].x < sourceMaxTex.x &&
|
||||
texCoordSamples[i].y < sourceMaxTex.y)
|
||||
{
|
||||
// we should be tapping the location directly in between 4 adjacent texels
|
||||
accumulatedBlur += AccumulateShadowSamples(FilterPassSrg::m_inputImage, texCoordSamples[i], FilterPassSrg::LinearSampler);
|
||||
numSamplesAccumulated += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSamplesAccumulated > 0)
|
||||
{
|
||||
float result = accumulatedBlur / numSamplesAccumulated;
|
||||
FilterPassSrg::m_outputImage[dispatchId].r = result;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Source" : "GaussianFilterFloatVertical",
|
||||
"Source" : "KawaseShadowBlur",
|
||||
|
||||
"DrawList" : "shadow",
|
||||
|
||||
@@ -86,6 +86,7 @@ set(FILES
|
||||
Passes/CascadedShadowmaps.pass
|
||||
Passes/CheckerboardResolveColor.pass
|
||||
Passes/CheckerboardResolveDepth.pass
|
||||
Passes/HDRColorGrading.pass
|
||||
Passes/ContrastAdaptiveSharpening.pass
|
||||
Passes/ConvertToAcescg.pass
|
||||
Passes/DebugOverlayParent.pass
|
||||
@@ -137,8 +138,6 @@ set(FILES
|
||||
Passes/FastDepthAwareBlur.pass
|
||||
Passes/FastDepthAwareBlurHor.pass
|
||||
Passes/FastDepthAwareBlurVer.pass
|
||||
Passes/FilterDepthHorizontal.pass
|
||||
Passes/FilterDepthVertical.pass
|
||||
Passes/Forward.pass
|
||||
Passes/ForwardCheckerboard.pass
|
||||
Passes/ForwardMSAA.pass
|
||||
@@ -146,6 +145,7 @@ set(FILES
|
||||
Passes/FullscreenCopy.pass
|
||||
Passes/FullscreenOutputOnly.pass
|
||||
Passes/ImGui.pass
|
||||
Passes/KawaseShadowBlur.pass
|
||||
Passes/LightAdaptationParent.pass
|
||||
Passes/LightCulling.pass
|
||||
Passes/LightCullingHeatmap.pass
|
||||
@@ -222,6 +222,8 @@ set(FILES
|
||||
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_AcesCg.azsli
|
||||
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/LinearSrgb_To_Srgb.azsli
|
||||
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/Srgb_To_LinearSrgb.azsli
|
||||
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCcToAcesCg.azsli
|
||||
ShaderLib/Atom/Features/ColorManagement/GeneratedTransforms/AcesCgToAcesCc.azsli
|
||||
ShaderLib/Atom/Features/CoreLights/PhotometricValue.azsli
|
||||
ShaderLib/Atom/Features/Decals/DecalTextureUtil.azsli
|
||||
ShaderLib/Atom/Features/LightCulling/LightCullingShared.azsli
|
||||
@@ -287,9 +289,11 @@ set(FILES
|
||||
ShaderLib/Atom/Features/Shadow/Shadow.azsli
|
||||
ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli
|
||||
ShaderLib/Atom/Features/Vertex/VertexHelper.azsli
|
||||
ShaderLib/3rdParty/Features/PostProcessing/KelvinToRgb.azsli
|
||||
ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_NonSeparable.azsli
|
||||
ShaderLib/3rdParty/Features/PostProcessing/PSstyleColorBlends_Separable.azsli
|
||||
ShaderResourceGroups/SceneSrg.azsli
|
||||
ShaderResourceGroups/SceneSrgAll.azsli
|
||||
ShaderResourceGroups/SceneTimeSrg.azsli
|
||||
ShaderResourceGroups/ViewSrg.azsli
|
||||
ShaderResourceGroups/ViewSrgAll.azsli
|
||||
ShaderResourceGroups/CoreLights/SceneSrg.azsli
|
||||
@@ -332,10 +336,6 @@ set(FILES
|
||||
Shaders/LightCulling/LightCullingTilePrepare.shader
|
||||
Shaders/LuxCore/RenderTexture.azsl
|
||||
Shaders/LuxCore/RenderTexture.shader
|
||||
Shaders/Math/GaussianFilterFloatHorizontal.azsl
|
||||
Shaders/Math/GaussianFilterFloatHorizontal.shader
|
||||
Shaders/Math/GaussianFilterFloatVertical.azsl
|
||||
Shaders/Math/GaussianFilterFloatVertical.shader
|
||||
Shaders/MorphTargets/MorphTargetCS.azsl
|
||||
Shaders/MorphTargets/MorphTargetCS.shader
|
||||
Shaders/MorphTargets/MorphTargetSRG.azsli
|
||||
@@ -398,6 +398,8 @@ set(FILES
|
||||
Shaders/PostProcessing/FastDepthAwareBlurVer.shader
|
||||
Shaders/PostProcessing/FullscreenCopy.azsl
|
||||
Shaders/PostProcessing/FullscreenCopy.shader
|
||||
Shaders/PostProcessing/HDRColorGrading.azsl
|
||||
Shaders/PostProcessing/HDRColorGrading.shader
|
||||
Shaders/PostProcessing/LookModificationTransform.azsl
|
||||
Shaders/PostProcessing/LookModificationTransform.shader
|
||||
Shaders/PostProcessing/LuminanceHeatmap.azsl
|
||||
@@ -458,6 +460,8 @@ set(FILES
|
||||
Shaders/ScreenSpace/DeferredFog.shader
|
||||
Shaders/Shadow/DepthExponentiation.azsl
|
||||
Shaders/Shadow/DepthExponentiation.shader
|
||||
Shaders/Shadow/KawaseShadowBlur.azsl
|
||||
Shaders/Shadow/KawaseShadowBlur.shader
|
||||
Shaders/Shadow/Shadowmap.azsl
|
||||
Shaders/Shadow/Shadowmap.shader
|
||||
Shaders/SkinnedMesh/LinearSkinningCS.azsl
|
||||
|
||||
-9
@@ -149,12 +149,6 @@ namespace AZ
|
||||
//! @param method filter method.
|
||||
virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0;
|
||||
|
||||
//! This sets sample count to predict boundary of shadow.
|
||||
//! @param handle the light handle.
|
||||
//! @param count Sample Count for prediction of whether the pixel is on the boundary (up to 16)
|
||||
//! The value should be less than or equal to m_filteringSampleCount.
|
||||
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
|
||||
|
||||
//! This sets sample count for filtering of shadow boundary.
|
||||
//! @param handle the light handle.
|
||||
//! @param count Sample Count for filtering (up to 64)
|
||||
@@ -166,9 +160,6 @@ namespace AZ
|
||||
//! If width == 0, softening edge is disabled. Units are in meters.
|
||||
virtual void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) = 0;
|
||||
|
||||
//! Sets the shadowmap Pcf method.
|
||||
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
|
||||
|
||||
//! Sets whether the directional shadowmap should use receiver plane bias.
|
||||
//! This attempts to reduce shadow acne when using large pcf filters.
|
||||
virtual void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) = 0;
|
||||
|
||||
-4
@@ -92,12 +92,8 @@ namespace AZ
|
||||
virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0;
|
||||
//! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on the boundary. 0 disables softening.
|
||||
virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0;
|
||||
//! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering sample count.
|
||||
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
|
||||
//! Sets sample count for filtering of shadow boundary (up to 64)
|
||||
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
|
||||
//! Sets the shadowmap Pcf (percentage closer filtering) method.
|
||||
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
|
||||
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow.
|
||||
virtual void SetEsmExponent(LightHandle handle, float exponent) = 0;
|
||||
|
||||
|
||||
-5
@@ -73,13 +73,8 @@ namespace AZ
|
||||
//! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on
|
||||
//! the boundary. 0 disables softening.
|
||||
virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0;
|
||||
//! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering
|
||||
//! sample count.
|
||||
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
|
||||
//! Sets sample count for filtering of shadow boundary (up to 64)
|
||||
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
|
||||
//! Sets the shadowmap Pcf (percentage closer filtering) method.
|
||||
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
|
||||
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow.
|
||||
virtual void SetEsmExponent(LightHandle handle, float exponent) = 0;
|
||||
//! Sets all of the the point data for the provided LightHandle.
|
||||
|
||||
@@ -37,14 +37,6 @@ namespace AZ
|
||||
Count
|
||||
};
|
||||
|
||||
enum class PcfMethod : uint16_t
|
||||
{
|
||||
BoundarySearch = 0, // Performs a variable number of taps, first to determine if we are on a shadow boundary, then the remaining taps are to find the occlusion amount
|
||||
Bicubic, // Uses a fixed size Pcf kernel with kernel weights set to approximate bicubic filtering
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
namespace Shadow
|
||||
{
|
||||
// [GFX TODO][ATOM-2408] Make the max number of cascade modifiable at runtime.
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// Auto-generates override function declarations for getters and setters of specified parameters and overrides
|
||||
|
||||
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue) \
|
||||
ValueType Get##Name() const override { return MemberName; } \
|
||||
void Set##Name(ValueType val) override { MemberName = val; } \
|
||||
|
||||
#define AZ_GFX_COMMON_OVERRIDE(ValueType, Name, MemberName, OverrideValueType) \
|
||||
OverrideValueType Get##Name##Override() const override { return MemberName##Override; } \
|
||||
void Set##Name##Override(OverrideValueType val) override { MemberName##Override = val; } \
|
||||
|
||||
#include <Atom/Feature/ParamMacros/MapAllCommon.inl>
|
||||
-4
@@ -52,14 +52,10 @@ namespace AZ::Render
|
||||
virtual void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) = 0;
|
||||
//! Sets the shadow bias
|
||||
virtual void SetShadowBias(ShadowId id, float bias) = 0;
|
||||
//! Sets the shadowmap Pcf method.
|
||||
virtual void SetPcfMethod(ShadowId id, PcfMethod method) = 0;
|
||||
//! Sets the shadow filter method
|
||||
virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0;
|
||||
//! Sets the width of boundary between shadowed area and lit area.
|
||||
virtual void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) = 0;
|
||||
//! Sets the sample count to predict the boundary of the shadow. Max 16, should be less than filtering sample count.
|
||||
virtual void SetPredictionSampleCount(ShadowId id, uint16_t count) = 0;
|
||||
//! Sets the sample count for filtering of the shadow boundary, max 64.
|
||||
virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0;
|
||||
//! Sets all of the shadow properites in one call
|
||||
|
||||
+8
-7
@@ -12,6 +12,7 @@
|
||||
#include <Atom/RHI/Buffer.h>
|
||||
#include <Atom/RHI/BufferPool.h>
|
||||
#include <Atom/RPI.Public/FeatureProcessor.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -36,8 +37,6 @@ namespace AZ
|
||||
void Activate() override;
|
||||
//! Releases GPU resources.
|
||||
void Deactivate() override;
|
||||
//! Binds buffers
|
||||
void Render(const FeatureProcessor::RenderPacket& packet) override;
|
||||
|
||||
// RPI::SceneNotificationBus overrides ...
|
||||
void OnBeginPrepareRender() override;
|
||||
@@ -68,11 +67,13 @@ namespace AZ
|
||||
// Prepare GPU buffers for object transformation matrices
|
||||
// Create the buffers if they don't exist. Otherwise, resize them if they are not large enough for the matrices
|
||||
void PrepareBuffers();
|
||||
|
||||
Data::Instance<RPI::ShaderResourceGroup> m_sceneSrg;
|
||||
RHI::ShaderInputBufferIndex m_objectToWorldBufferIndex;
|
||||
RHI::ShaderInputBufferIndex m_objectToWorldInverseTransposeBufferIndex;
|
||||
RHI::ShaderInputBufferIndex m_objectToWorldHistoryBufferIndex;
|
||||
|
||||
void UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg);
|
||||
|
||||
RPI::Scene::PrepareSceneSrgEvent::Handler m_updateSceneSrgHandler;
|
||||
RHI::ShaderInputNameIndex m_objectToWorldBufferIndex = "m_objectToWorldBuffer";
|
||||
RHI::ShaderInputNameIndex m_objectToWorldInverseTransposeBufferIndex = "m_objectToWorldInverseTransposeBuffer";
|
||||
RHI::ShaderInputNameIndex m_objectToWorldHistoryBufferIndex = "m_objectToWorldHistoryBuffer";
|
||||
|
||||
// Stores transforms that are uploaded to a GPU buffer. Used slots have float12(matrix3x4) values, empty slots
|
||||
// have a uint32_t that points to the next empty slot like a linked list. m_firstAvailableMeshTransformIndex stores the first
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace AZ
|
||||
|
||||
protected:
|
||||
// Pass overrides...
|
||||
void FrameBeginInternal(FramePrepareParams params);
|
||||
void FrameBeginInternal(FramePrepareParams params) override;
|
||||
void BuildInternal() override;
|
||||
void FrameEndInternal() override;
|
||||
|
||||
|
||||
@@ -571,20 +571,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
if (count > Shadow::MaxPcfSamplingCount)
|
||||
{
|
||||
AZ_Warning(FeatureProcessorName, false, "Sampling count exceed the limit.");
|
||||
count = Shadow::MaxPcfSamplingCount;
|
||||
}
|
||||
for (auto& it : m_shadowData)
|
||||
{
|
||||
it.second.GetData(handle.GetIndex()).m_predictionSampleCount = count;
|
||||
}
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
if (count > Shadow::MaxPcfSamplingCount)
|
||||
@@ -608,15 +594,6 @@ namespace AZ
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
|
||||
{
|
||||
for (auto& it : m_shadowData)
|
||||
{
|
||||
it.second.GetData(handle.GetIndex()).m_pcfMethod = method;
|
||||
}
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable)
|
||||
{
|
||||
m_shadowProperties.GetData(handle.GetIndex()).m_isReceiverPlaneBiasEnabled = enable;
|
||||
|
||||
@@ -102,8 +102,6 @@ namespace AZ
|
||||
uint32_t m_debugFlags = 0;
|
||||
uint32_t m_shadowFilterMethod = 0;
|
||||
float m_far_minus_near = 0;
|
||||
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch;
|
||||
uint32_t m_padding[3];
|
||||
};
|
||||
|
||||
class DirectionalLightFeatureProcessor final
|
||||
@@ -218,10 +216,8 @@ namespace AZ
|
||||
void SetViewFrustumCorrectionEnabled(LightHandle handle, bool enabled) override;
|
||||
void SetDebugFlags(LightHandle handle, DebugDrawFlags flags) override;
|
||||
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
|
||||
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) override;
|
||||
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override;
|
||||
|
||||
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
|
||||
|
||||
@@ -329,21 +329,11 @@ namespace AZ
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians);
|
||||
}
|
||||
|
||||
void DiskLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count);
|
||||
}
|
||||
|
||||
void DiskLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count);
|
||||
}
|
||||
|
||||
void DiskLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method);
|
||||
}
|
||||
|
||||
void DiskLightFeatureProcessor::SetEsmExponent(LightHandle handle, float exponent)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, exponent);
|
||||
|
||||
@@ -54,9 +54,7 @@ namespace AZ
|
||||
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
|
||||
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
|
||||
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
|
||||
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
|
||||
void SetEsmExponent(LightHandle handle, float esmExponent) override;
|
||||
|
||||
void SetDiskData(LightHandle handle, const DiskLightData& data) override;
|
||||
|
||||
@@ -130,32 +130,17 @@ namespace AZ
|
||||
const AZStd::array_view<RPI::Ptr<RPI::Pass>>& children = GetChildren();
|
||||
AZ_Assert(children.size() == EsmChildPassKindCount, "[EsmShadowmapsPass '%s'] The count of children is wrong.", GetPathName().GetCStr());
|
||||
|
||||
for (uint32_t index = 0; index < EsmChildPassKindCount; ++index)
|
||||
for (uint32_t childPassIndex = 0; childPassIndex < EsmChildPassKindCount; ++childPassIndex)
|
||||
{
|
||||
RPI::ComputePass* child = azrtti_cast<RPI::ComputePass*>(children[index].get());
|
||||
RPI::ComputePass* child = azrtti_cast<RPI::ComputePass*>(children[childPassIndex].get());
|
||||
AZ_Assert(child, "[EsmShadowmapsPass '%s'] A child does not compute.", GetPathName().GetCStr());
|
||||
|
||||
Data::Instance<RPI::ShaderResourceGroup> srg = child->GetShaderResourceGroup();
|
||||
|
||||
if (m_shadowmapIndexTableBufferIndices[index].IsNull())
|
||||
SetBlurParameters(srg, childPassIndex);
|
||||
if (childPassIndex >= aznumeric_cast<uint32_t>(EsmChildPassKind::KawaseBlur0))
|
||||
{
|
||||
m_shadowmapIndexTableBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_shadowmapIndexTable"));
|
||||
}
|
||||
srg->SetBuffer(m_shadowmapIndexTableBufferIndices[index], m_shadowmapIndexTableBuffer);
|
||||
|
||||
if (m_filterParameterBufferIndices[index].IsNull())
|
||||
{
|
||||
m_filterParameterBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_filterParameters"));
|
||||
}
|
||||
srg->SetBuffer(m_filterParameterBufferIndices[index], m_filterParameterBuffer);
|
||||
|
||||
if (index != static_cast<uint32_t>(EsmChildPassKind::Exponentiation))
|
||||
{
|
||||
if (m_filterTableBufferIndices[index].IsNull())
|
||||
{
|
||||
m_filterTableBufferIndices[index] = srg->FindShaderInputBufferIndex(Name("m_filterTable"));
|
||||
}
|
||||
srg->SetBuffer(m_filterTableBufferIndices[index], m_filterTableBuffer);
|
||||
SetKawaseBlurSpecificParameters(srg, childPassIndex - aznumeric_cast<uint32_t>(EsmChildPassKind::KawaseBlur0));
|
||||
}
|
||||
|
||||
child->SetTargetThreadCounts(
|
||||
@@ -165,5 +150,32 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EsmShadowmapsPass::SetBlurParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t childPassIndex)
|
||||
{
|
||||
if (m_shadowmapIndexTableBufferIndices[childPassIndex].IsNull())
|
||||
{
|
||||
m_shadowmapIndexTableBufferIndices[childPassIndex] = srg->FindShaderInputBufferIndex(Name("m_shadowmapIndexTable"));
|
||||
}
|
||||
srg->SetBuffer(m_shadowmapIndexTableBufferIndices[childPassIndex], m_shadowmapIndexTableBuffer);
|
||||
|
||||
if (m_filterParameterBufferIndices[childPassIndex].IsNull())
|
||||
{
|
||||
m_filterParameterBufferIndices[childPassIndex] = srg->FindShaderInputBufferIndex(Name("m_filterParameters"));
|
||||
}
|
||||
srg->SetBuffer(m_filterParameterBufferIndices[childPassIndex], m_filterParameterBuffer);
|
||||
}
|
||||
|
||||
void EsmShadowmapsPass::SetKawaseBlurSpecificParameters(Data::Instance<RPI::ShaderResourceGroup> srg, uint32_t kawaseBlurIndex)
|
||||
{
|
||||
if (m_kawaseBlurConstantIndices[kawaseBlurIndex].IsNull())
|
||||
{
|
||||
m_kawaseBlurConstantIndices[kawaseBlurIndex] = srg->FindShaderInputConstantIndex(Name("m_rcpResolutionAndIteration"));
|
||||
}
|
||||
const AZ::Vector4 data(
|
||||
1.0f / m_shadowmapImageSize.m_width, 1.0f / m_shadowmapImageSize.m_height, aznumeric_cast<float>(kawaseBlurIndex), 0.0f);
|
||||
|
||||
srg->SetConstant(m_kawaseBlurConstantIndices[kawaseBlurIndex], data);
|
||||
}
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -21,12 +21,17 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
class ShaderResourceGroup;
|
||||
}
|
||||
|
||||
namespace Render
|
||||
{
|
||||
AZ_ENUM_CLASS_WITH_UNDERLYING_TYPE(EsmChildPassKind, uint32_t,
|
||||
(Exponentiation, 0),
|
||||
HorizontalFilter,
|
||||
VerticalFilter);
|
||||
KawaseBlur0,
|
||||
KawaseBlur1);
|
||||
|
||||
//! This pass outputs filtered shadowmap images used in ESM.
|
||||
//! ESM is an abbreviation of Exponential Shadow Maps.
|
||||
@@ -88,6 +93,9 @@ namespace AZ
|
||||
void FrameBeginInternal(FramePrepareParams params) override;
|
||||
|
||||
void UpdateChildren();
|
||||
// Parameters for both the depth exponentiation pass along with the kawase blur passes
|
||||
void SetBlurParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t childPassIndex);
|
||||
void SetKawaseBlurSpecificParameters(Data::Instance<RPI::ShaderResourceGroup> srg, const uint32_t kawaseBlurIndex);
|
||||
|
||||
bool m_computationEnabled = false;
|
||||
Name m_lightTypeName;
|
||||
@@ -102,6 +110,8 @@ namespace AZ
|
||||
Data::Instance<RPI::Buffer> m_shadowmapIndexTableBuffer;
|
||||
AZStd::array<RHI::ShaderInputBufferIndex, EsmChildPassKindCount> m_filterParameterBufferIndices;
|
||||
Data::Instance<RPI::Buffer> m_filterParameterBuffer;
|
||||
|
||||
AZStd::array<RHI::ShaderInputConstantIndex, 2> m_kawaseBlurConstantIndices;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -298,21 +298,11 @@ namespace AZ
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians);
|
||||
}
|
||||
|
||||
void PointLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count);
|
||||
}
|
||||
|
||||
void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count);
|
||||
}
|
||||
|
||||
void PointLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method);
|
||||
}
|
||||
|
||||
void PointLightFeatureProcessor::SetEsmExponent(LightHandle handle, float esmExponent)
|
||||
{
|
||||
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent);
|
||||
|
||||
@@ -51,9 +51,7 @@ namespace AZ
|
||||
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
|
||||
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
|
||||
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
|
||||
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
|
||||
void SetEsmExponent(LightHandle handle, float esmExponent) override;
|
||||
void SetPointData(LightHandle handle, const PointLightData& data) override;
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace AZ
|
||||
void RenderImguiDrawData(const ImDrawData& drawData);
|
||||
|
||||
// TickBus::Handler overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint);
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
|
||||
|
||||
// AzFramework::InputTextEventListener overrides...
|
||||
bool OnInputTextEventFiltered(const AZStd::string& textUTF8) override;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
using RPI::MaterialFunctor::Process;
|
||||
void Process(RuntimeContext& context) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
using RPI::MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
using RPI::MaterialFunctor::Process;
|
||||
void Process(RuntimeContext& context) override;
|
||||
|
||||
private:
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
using AZ::RPI::MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
using RPI::MaterialFunctor::Process;
|
||||
void Process(RuntimeContext& context) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
using AZ::RPI::MaterialFunctorSourceData::CreateFunctor;
|
||||
FunctorResult CreateFunctor(const RuntimeContext& context) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -479,8 +479,6 @@ namespace AZ
|
||||
: m_modelAsset(modelAsset)
|
||||
, m_parent(parent)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzRender);
|
||||
|
||||
if (!m_modelAsset.GetId().IsValid())
|
||||
{
|
||||
AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
|
||||
@@ -508,7 +506,6 @@ namespace AZ
|
||||
//! AssetBus::Handler overrides...
|
||||
void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzRender);
|
||||
Data::Asset<RPI::ModelAsset> modelAsset = asset;
|
||||
|
||||
// Assign the fully loaded asset back to the mesh handle to not only hold asset id, but the actual data as well.
|
||||
@@ -580,8 +577,6 @@ namespace AZ
|
||||
|
||||
void MeshDataInstance::Init(Data::Instance<RPI::Model> model)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzRender);
|
||||
|
||||
m_model = model;
|
||||
const size_t modelLodCount = m_model->GetLodCount();
|
||||
m_drawPacketListsByLod.resize(modelLodCount);
|
||||
@@ -612,8 +607,6 @@ namespace AZ
|
||||
|
||||
void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzRender);
|
||||
|
||||
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
|
||||
const size_t meshCount = modelLod.GetMeshes().size();
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace AZ
|
||||
void ApplySettingsTo(BloomSettings* target, float alpha) const;
|
||||
|
||||
// Generate getters and setters.
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
|
||||
#include <Atom/Feature/PostProcess/Bloom/BloomParams.inl>
|
||||
#include <Atom/Feature/ParamMacros/EndParams.inl>
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace AZ
|
||||
#undef POST_PROCESS_MEMBER
|
||||
|
||||
// Auto-gen getter and setter functions for post process members...
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
|
||||
#include <Atom/Feature/PostProcess/PostProcessParams.inl>
|
||||
#include <Atom/Feature/ParamMacros/EndParams.inl>
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace AZ
|
||||
void ApplySettingsTo(SsaoSettings* target, float alpha) const;
|
||||
|
||||
// Generate getters and setters.
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctions.inl>
|
||||
#include <Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl>
|
||||
#include <Atom/Feature/PostProcess/Ssao/SsaoParams.inl>
|
||||
#include <Atom/Feature/ParamMacros/EndParams.inl>
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ namespace AZ
|
||||
m_viewPtr = view;
|
||||
m_viewSrg = view->GetShaderResourceGroup();
|
||||
|
||||
m_exposureControlBufferInputIndex = m_viewSrg->FindShaderInputBufferIndex(Name("m_exposureControl"));
|
||||
|
||||
m_eyeAdaptationBuffer.Init(m_viewSrg, idNumber);
|
||||
}
|
||||
|
||||
@@ -109,14 +107,10 @@ namespace AZ
|
||||
|
||||
m_eyeAdaptationBuffer.UpdateSrg();
|
||||
|
||||
if (m_exposureControlBufferInputIndex.IsValid())
|
||||
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
|
||||
if (m_viewPtr)
|
||||
{
|
||||
m_viewSrg->SetBufferView(m_exposureControlBufferInputIndex, m_buffer->GetBufferView());
|
||||
|
||||
if (m_viewPtr)
|
||||
{
|
||||
m_viewPtr->InvalidateSrg();
|
||||
}
|
||||
m_viewPtr->InvalidateSrg();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace AZ
|
||||
struct ExposureCalculationData
|
||||
{
|
||||
float m_exposureValue = 1.0f;
|
||||
float m_setValueTime = 0;
|
||||
};
|
||||
|
||||
void BuildInternal() override;
|
||||
|
||||
@@ -367,11 +367,27 @@ namespace AZ
|
||||
{
|
||||
// set draw list mask
|
||||
m_cullable.m_cullData.m_drawListMask.reset();
|
||||
m_cullable.m_cullData.m_drawListMask =
|
||||
m_stencilDrawPacket->GetDrawListMask() |
|
||||
m_blendWeightDrawPacket->GetDrawListMask() |
|
||||
m_renderOuterDrawPacket->GetDrawListMask() |
|
||||
m_renderInnerDrawPacket->GetDrawListMask();
|
||||
|
||||
// check for draw packets due certain render pipelines such as lowend render pipeline that might not have this feature enabled
|
||||
if (m_stencilDrawPacket)
|
||||
{
|
||||
m_cullable.m_cullData.m_drawListMask |= m_stencilDrawPacket->GetDrawListMask();
|
||||
}
|
||||
|
||||
if (m_blendWeightDrawPacket)
|
||||
{
|
||||
m_cullable.m_cullData.m_drawListMask |= m_blendWeightDrawPacket->GetDrawListMask();
|
||||
}
|
||||
|
||||
if (m_renderOuterDrawPacket)
|
||||
{
|
||||
m_cullable.m_cullData.m_drawListMask |= m_renderOuterDrawPacket->GetDrawListMask();
|
||||
}
|
||||
|
||||
if (m_renderInnerDrawPacket)
|
||||
{
|
||||
m_cullable.m_cullData.m_drawListMask |= m_renderInnerDrawPacket->GetDrawListMask();
|
||||
}
|
||||
|
||||
// setup the Lod entry, using one entry for all four draw packets
|
||||
m_cullable.m_lodData.m_lods.clear();
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace AZ
|
||||
~DeferredFogSettings() = default;
|
||||
|
||||
// DeferredFogSettingsInterface overrides...
|
||||
void OnSettingsChanged();
|
||||
void OnSettingsChanged() override;
|
||||
bool GetSettingsNeedUpdate()
|
||||
{
|
||||
return m_needUpdate;
|
||||
@@ -66,35 +66,35 @@ namespace AZ
|
||||
m_needUpdate = needUpdate;
|
||||
}
|
||||
|
||||
void SetEnabled(bool value);
|
||||
virtual bool GetEnabled() const override
|
||||
void SetEnabled(bool value) override;
|
||||
bool GetEnabled() const override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual void SetInitialized(bool isInitialized) override
|
||||
void SetInitialized(bool isInitialized) override
|
||||
{
|
||||
m_isInitialized = isInitialized;
|
||||
}
|
||||
virtual bool IsInitialized() override
|
||||
bool IsInitialized() override
|
||||
{
|
||||
return m_isInitialized;
|
||||
}
|
||||
|
||||
virtual void SetUseNoiseTextureShaderOption(bool value) override
|
||||
void SetUseNoiseTextureShaderOption(bool value) override
|
||||
{
|
||||
m_useNoiseTextureShaderOption = value;
|
||||
}
|
||||
virtual bool GetUseNoiseTextureShaderOption() override
|
||||
bool GetUseNoiseTextureShaderOption() override
|
||||
{
|
||||
return m_useNoiseTextureShaderOption;
|
||||
}
|
||||
|
||||
virtual void SetEnableFogLayerShaderOption(bool value) override
|
||||
void SetEnableFogLayerShaderOption(bool value) override
|
||||
{
|
||||
m_enableFogLayerShaderOption = value;
|
||||
}
|
||||
virtual bool GetEnableFogLayerShaderOption() override
|
||||
bool GetEnableFogLayerShaderOption() override
|
||||
{
|
||||
return m_enableFogLayerShaderOption;
|
||||
}
|
||||
|
||||
@@ -165,15 +165,6 @@ namespace AZ::Render
|
||||
m_filterParameterNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetPcfMethod(ShadowId id, PcfMethod method)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPcfMethod().");
|
||||
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
|
||||
shadowData.m_pcfMethod = method;
|
||||
|
||||
m_deviceBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetEsmExponent().");
|
||||
@@ -188,7 +179,7 @@ namespace AZ::Render
|
||||
|
||||
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id);
|
||||
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
|
||||
shadowData.m_shadowFilterMethod = aznumeric_cast<uint16_t>(method);
|
||||
shadowData.m_shadowFilterMethod = aznumeric_cast<uint32_t>(method);
|
||||
|
||||
UpdateShadowView(shadowProperty);
|
||||
|
||||
@@ -207,19 +198,6 @@ namespace AZ::Render
|
||||
m_filterParameterNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetPredictionSampleCount(ShadowId id, uint16_t count)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPredictionSampleCount().");
|
||||
|
||||
AZ_Warning("ProjectedShadowFeatureProcessor", count <= Shadow::MaxPcfSamplingCount, "Sampling count exceed the limit.");
|
||||
count = GetMin(count, Shadow::MaxPcfSamplingCount);
|
||||
|
||||
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
|
||||
shadowData.m_predictionSampleCount = count;
|
||||
|
||||
m_deviceBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetFilteringSampleCount(ShadowId id, uint16_t count)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetFilteringSampleCount().");
|
||||
|
||||
@@ -48,15 +48,14 @@ namespace AZ::Render
|
||||
void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override;
|
||||
void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override;
|
||||
void SetShadowBias(ShadowId id, float bias) override;
|
||||
void SetPcfMethod(ShadowId id, PcfMethod method);
|
||||
void SetEsmExponent(ShadowId id, float exponent);
|
||||
void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override;
|
||||
void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) override;
|
||||
void SetPredictionSampleCount(ShadowId id, uint16_t count) override;
|
||||
void SetFilteringSampleCount(ShadowId id, uint16_t count) override;
|
||||
void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override;
|
||||
const ProjectedShadowDescriptor& GetShadowProperties(ShadowId id) override;
|
||||
|
||||
void SetEsmExponent(ShadowId id, float exponent);
|
||||
|
||||
private:
|
||||
|
||||
// GPU data stored in m_projectedShadows.
|
||||
@@ -64,8 +63,7 @@ namespace AZ::Render
|
||||
{
|
||||
Matrix4x4 m_depthBiasMatrix = Matrix4x4::CreateIdentity();
|
||||
uint32_t m_shadowmapArraySlice = 0; // array slice who has shadowmap in the atlas.
|
||||
uint16_t m_shadowFilterMethod = 0; // filtering method of shadows.
|
||||
PcfMethod m_pcfMethod = PcfMethod::BoundarySearch; // method for performing Pcf (uint16_t)
|
||||
uint32_t m_shadowFilterMethod = 0; // filtering method of shadows.
|
||||
float m_boundaryScale = 0.f; // the half of boundary of lit/shadowed areas. (in degrees)
|
||||
uint32_t m_predictionSampleCount = 0; // sample count to judge whether it is on the shadow boundary or not.
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
|
||||
+11
-14
@@ -36,11 +36,8 @@ namespace AZ
|
||||
|
||||
void TransformServiceFeatureProcessor::Activate()
|
||||
{
|
||||
m_sceneSrg = GetParentScene()->GetShaderResourceGroup();
|
||||
|
||||
m_objectToWorldBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldBuffer"});
|
||||
m_objectToWorldInverseTransposeBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldInverseTransposeBuffer"});
|
||||
m_objectToWorldHistoryBufferIndex = m_sceneSrg->FindShaderInputBufferIndex(Name{"m_objectToWorldHistoryBuffer"});
|
||||
m_updateSceneSrgHandler = RPI::Scene::PrepareSceneSrgEvent::Handler([this](RPI::ShaderResourceGroup *sceneSrg) { this->UpdateSceneSrg(sceneSrg); });
|
||||
GetParentScene()->ConnectEvent(m_updateSceneSrgHandler);
|
||||
|
||||
m_deviceBufferNeedsUpdate = true;
|
||||
m_objectToWorldTransforms.reserve(BufferReserveCount);
|
||||
@@ -62,9 +59,14 @@ namespace AZ
|
||||
|
||||
m_firstAvailableTransformIndex = NoAvailableTransformIndices;
|
||||
|
||||
m_objectToWorldBufferIndex.Reset();
|
||||
m_objectToWorldInverseTransposeBufferIndex.Reset();
|
||||
m_objectToWorldHistoryBufferIndex.Reset();
|
||||
|
||||
m_isWriteable = false;
|
||||
|
||||
RPI::SceneNotificationBus::Handler::BusDisconnect();
|
||||
m_updateSceneSrgHandler.Disconnect();
|
||||
}
|
||||
|
||||
void TransformServiceFeatureProcessor::PrepareBuffers()
|
||||
@@ -131,16 +133,11 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void TransformServiceFeatureProcessor::Render([[maybe_unused]] const FeatureProcessor::RenderPacket& packet)
|
||||
void TransformServiceFeatureProcessor::UpdateSceneSrg(RPI::ShaderResourceGroup *sceneSrg)
|
||||
{
|
||||
AZ_ATOM_PROFILE_FUNCTION("RPI", "TransformServiceFeatureProcessor: Render");
|
||||
AZ_UNUSED(packet);
|
||||
|
||||
AZ_Assert(!m_isWriteable, "Must be called between OnBeginPrepareRender() and OnEndPrepareRender()");
|
||||
|
||||
m_sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
|
||||
m_sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
|
||||
m_sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
|
||||
sceneSrg->SetBufferView(m_objectToWorldBufferIndex, m_objectToWorldBuffer->GetBufferView());
|
||||
sceneSrg->SetBufferView(m_objectToWorldInverseTransposeBufferIndex, m_objectToWorldInverseTransposeBuffer->GetBufferView());
|
||||
sceneSrg->SetBufferView(m_objectToWorldHistoryBufferIndex, m_objectToWorldHistoryBuffer->GetBufferView());
|
||||
}
|
||||
|
||||
void TransformServiceFeatureProcessor::OnBeginPrepareRender()
|
||||
|
||||
@@ -39,6 +39,7 @@ set(FILES
|
||||
Include/Atom/Feature/ParamMacros/StartParamCopySettingsTo.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamFunctions.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamFunctionsOverride.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamFunctionsOverrideImpl.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamMembers.inl
|
||||
Include/Atom/Feature/ParamMacros/StartParamSerializeContext.inl
|
||||
|
||||
@@ -113,7 +113,9 @@ if __name__ == '__main__':
|
||||
lut_intervals, lut_values = generate_lut_values(image_spec, image_buffer)
|
||||
|
||||
write_3DL(args.o, image_spec.height, lut_intervals, lut_values)
|
||||
write_azasset(args.o, image_spec.height, lut_intervals, lut_values)
|
||||
|
||||
# write_azasset(file_path, lut_intervals, lut_values, azasset_json=AZASSET_LUT)
|
||||
write_azasset(args.o, lut_intervals, lut_values)
|
||||
|
||||
# example from command line
|
||||
# python % DCCSI_COLORGRADING_SCRIPTS %\lut_helper.py - -i C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\linear_32_LUT.exr - -op pre - grading - -shaper Log2 - 48nits - -o C: \Depot\o3de\Gems\Atom\Feature\Common\Tools\ColorGrading\Resources\LUTs\base_Log2-48nits_32_LUT.exr
|
||||
|
||||
@@ -31,11 +31,8 @@ if ColorGrading.initialize.start():
|
||||
sys.exit(1)
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
from ColorGrading import AZASSET_LUT
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
def find_first_line(alist):
|
||||
for lno, line in enumerate(alist):
|
||||
|
||||
+32770
-32773
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,13 @@ TITLE O3DE Color Grading CMD
|
||||
:: Use obvious color to prevent confusion (Grey with Yellow Text)
|
||||
COLOR 8E
|
||||
|
||||
echo.
|
||||
echo _____________________________________________________________________
|
||||
echo.
|
||||
echo ~ O3DE Color Grading Python CMD ...
|
||||
echo _____________________________________________________________________
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
PUSHD %~dp0
|
||||
@@ -27,16 +34,17 @@ SETLOCAL ENABLEDELAYEDEXPANSION
|
||||
IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat
|
||||
|
||||
:: Initialize env
|
||||
echo
|
||||
echo ... calling Env_Core.bat
|
||||
CALL %~dp0\Env_Core.bat
|
||||
CALL %~dp0\Env_Python.bat
|
||||
CALL %~dp0\Env_Tools.bat
|
||||
|
||||
echo.
|
||||
echo _____________________________________________________________________
|
||||
echo.
|
||||
echo ~ O3DE Color Grading Python CMD ...
|
||||
echo _____________________________________________________________________
|
||||
echo.
|
||||
echo
|
||||
echo ... calling Env_Python.bat
|
||||
CALL %~dp0\Env_Python.bat
|
||||
|
||||
echo
|
||||
echo ... calling Env_Tools.bat
|
||||
CALL %~dp0\Env_Tools.bat
|
||||
|
||||
:: Change to root dir
|
||||
CD /D ..
|
||||
|
||||
@@ -93,9 +93,6 @@ popd
|
||||
set DCCSIG_PATH=%O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface
|
||||
echo DCCSIG_PATH = %DCCSIG_PATH%
|
||||
|
||||
:: Change to DCCsi root dir
|
||||
CD /D %DCCSIG_PATH%
|
||||
|
||||
:: per-dcc sdk path
|
||||
set DCCSI_SDK_PATH=%DCCSIG_PATH%\SDK
|
||||
echo DCCSI_SDK_PATH = %DCCSI_SDK_PATH%
|
||||
|
||||
@@ -26,7 +26,7 @@ SET DCCSI_GDEBUG=True
|
||||
SET DCCSI_DEV_MODE=True
|
||||
|
||||
:: set the your user name here for windows path
|
||||
SET TAG_USERNAME=< not set >
|
||||
SET TAG_USERNAME=NOT_SET
|
||||
SET DCCSI_PY_REV=rev1
|
||||
SET DCCSI_PY_PLATFORM=windows
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ ly_add_target(
|
||||
FILES_CMAKE
|
||||
atom_rhi_public_files.cmake
|
||||
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
${pal_source_dir}/platform_private_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
@@ -55,9 +56,6 @@ ly_add_target(
|
||||
Gem::Atom_RHI.Reflect
|
||||
PUBLIC
|
||||
${RENDERDOC_DEPENDENCY}
|
||||
COMPILE_DEFINITIONS
|
||||
PUBLIC
|
||||
${RENDERDOC_DEFINE}
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
|
||||
@@ -50,24 +50,21 @@ namespace AZ
|
||||
class RayTracingPipelineState;
|
||||
class RayTracingShaderTable;
|
||||
|
||||
/* Priority of a Factory. The lower the number the higher the priority.
|
||||
* Used when there's multiple factories available and the user hasn't define
|
||||
* a priority.
|
||||
*/
|
||||
//! Priority of a Factory. The lower the number the higher the priority.
|
||||
//! Used when there's multiple factories available and the user hasn't define
|
||||
//! a priority.
|
||||
using APIPriority = uint32_t;
|
||||
static const APIPriority APITopPriority = 1;
|
||||
static const APIPriority APILowPriority = 10;
|
||||
static const APIPriority APIMiddlePriority = (APILowPriority - APITopPriority) / 2;
|
||||
|
||||
/**
|
||||
* The factory is an interface for creating RHI data structures. The platform system should
|
||||
* register itself with the factory by calling Register, and unregister on shutdown with
|
||||
* Unregister.
|
||||
*
|
||||
* A call to Get will return the active instance. In the event that it's unclear whether
|
||||
* a platform instance exists, you must call IsReady to determine whether it's safe to
|
||||
* call Get. Calling Get without a registered platform will result in an assert.
|
||||
*/
|
||||
//! The factory is an interface for creating RHI data structures. The platform system should
|
||||
//! register itself with the factory by calling Register, and unregister on shutdown with
|
||||
//! Unregister.
|
||||
//!
|
||||
//! A call to Get will return the active instance. In the event that it's unclear whether
|
||||
//! a platform instance exists, you must call IsReady to determine whether it's safe to
|
||||
//! call Get. Calling Get without a registered platform will result in an assert.
|
||||
class Factory
|
||||
{
|
||||
public:
|
||||
@@ -79,78 +76,78 @@ namespace AZ
|
||||
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
|
||||
AZ_DISABLE_COPY_MOVE(Factory);
|
||||
|
||||
/// Returns the component service name CRC used by the platform RHI system component.
|
||||
//! Returns the component service name CRC used by the platform RHI system component.
|
||||
static uint32_t GetComponentService();
|
||||
|
||||
/// Returns the component service name CRC used by the Factory manager component.
|
||||
//! Returns the component service name CRC used by the Factory manager component.
|
||||
static uint32_t GetManagerComponentService();
|
||||
|
||||
/// Returns the component service name CRC used by the platform RHI system component.
|
||||
//! Returns the component service name CRC used by the platform RHI system component.
|
||||
static uint32_t GetPlatformService();
|
||||
|
||||
/// Registers the global factory instance.
|
||||
//! Registers the global factory instance.
|
||||
static void Register(Factory* instance);
|
||||
|
||||
/// Unregisters the global factory instance.
|
||||
//! Unregisters the global factory instance.
|
||||
static void Unregister(Factory* instance);
|
||||
|
||||
/// Returns whether the factory is initialized and active in this module.
|
||||
//! Returns whether the factory is initialized and active in this module.
|
||||
static bool IsReady();
|
||||
|
||||
/// Access the global factory instance.
|
||||
//! Access the global factory instance.
|
||||
static Factory& Get();
|
||||
|
||||
#if defined(USE_RENDERDOC)
|
||||
/// Access the RenderDoc API pointer if available.
|
||||
/// The availability of the render doc API at runtime depends on the following:
|
||||
/// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
|
||||
/// - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
|
||||
/// - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
|
||||
//! Access the RenderDoc API pointer if available.
|
||||
//! The availability of the render doc API at runtime depends on the following:
|
||||
//! - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
|
||||
//! - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
|
||||
//! - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
|
||||
static RENDERDOC_API_1_1_2* GetRenderDocAPI();
|
||||
#endif
|
||||
|
||||
//! Returns true if RenderDoc dll is loaded
|
||||
static bool IsRenderDocModuleLoaded();
|
||||
|
||||
/// Returns the name of the Factory.
|
||||
//! Returns true if Pix dll is loaded
|
||||
static bool IsPixModuleLoaded();
|
||||
|
||||
//! Returns the name of the Factory.
|
||||
virtual Name GetName() = 0;
|
||||
|
||||
/// Returns the APIType of the factory.
|
||||
//! Returns the APIType of the factory.
|
||||
virtual APIType GetType() = 0;
|
||||
|
||||
/// Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
|
||||
//! Returns the default priority of the factory in case there's no priorities set in the FactoryManager.
|
||||
virtual APIPriority GetDefaultPriority() = 0;
|
||||
|
||||
/**
|
||||
* Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
|
||||
* Returns a number in the range [0..3].
|
||||
* In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
|
||||
* In reality "pc" only supports DX12 & Vulkan.
|
||||
* "ios" supports only Metal.
|
||||
* "mac" supports only Metal.
|
||||
* "android" supports only Vulkan.
|
||||
* So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
|
||||
* hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
|
||||
* REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
|
||||
* For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
|
||||
* Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
|
||||
* See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
|
||||
*/
|
||||
//! Purpose: The API Unique Index will be encoded in the 2 Most Significant Bits of a ShaderVariantAsset ProductSubId (a 32bits integer).
|
||||
//! Returns a number in the range [0..3].
|
||||
//! In theory any given AssetBuilderSdk::PlatformInfo can support several RHI::APITypes.
|
||||
//! In reality "pc" only supports DX12 & Vulkan.
|
||||
//! "ios" supports only Metal.
|
||||
//! "mac" supports only Metal.
|
||||
//! "android" supports only Vulkan.
|
||||
//! So, for all practical purposes, a single PlatformInfo won't support more than 2 ShaderPlatformInterfaces, but for the sake of
|
||||
//! hedging our bets into the future We assume no more than 4 ShaderPlatformInterfaces will ever be supported for any given PlatformInfo.
|
||||
//! REMARK: It is the responsibility of the Factory subclass to return a unique number between 0...3.
|
||||
//! For example DX12 can return 0, while Vulkan should return 1 (Satisfies "pc", "android" and "linux").
|
||||
//! Metal can return 0 because it is the only ShaderPlatformInterface for "ios", "mac" and "appletv".
|
||||
//! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
|
||||
virtual uint32_t GetAPIUniqueIndex() const = 0;
|
||||
|
||||
/**
|
||||
* Collects the set of physical devices on the system and returns a list of them. Physical
|
||||
* devices represent the hardware attached to the system. Physical devices can be grouped
|
||||
* into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
|
||||
* reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
|
||||
* this information.
|
||||
*/
|
||||
//! Collects the set of physical devices on the system and returns a list of them. Physical
|
||||
//! devices represent the hardware attached to the system. Physical devices can be grouped
|
||||
//! into nodes for linked setups (e.g. SLI / Crossfire). They can also represent software
|
||||
//! reference implementations. Check the PhysicalDeviceType on the descriptor to inspect
|
||||
//! this information.
|
||||
virtual PhysicalDeviceList EnumeratePhysicalDevices() = 0;
|
||||
|
||||
/**
|
||||
* Factory Creation Methods:
|
||||
*
|
||||
* Returns the platform-specific derived variant of the RHI type. All instances are created
|
||||
* in an uninitialized state; the operation simply allocates the memory for the appropriate
|
||||
* platform type and returns the pointer.
|
||||
*/
|
||||
//! Factory Creation Methods:
|
||||
//!
|
||||
//! Returns the platform-specific derived variant of the RHI type. All instances are created
|
||||
//! in an uninitialized state; the operation simply allocates the memory for the appropriate
|
||||
//! platform type and returns the pointer.
|
||||
|
||||
virtual Ptr<Buffer> CreateBuffer() = 0;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace AZ
|
||||
VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) override;
|
||||
void DeAllocate(VirtualAddress allocation) override;
|
||||
void GarbageCollect() override;
|
||||
void GarbageCollectForce();
|
||||
void GarbageCollectForce() override;
|
||||
size_t GetAllocationCount() const override;
|
||||
size_t GetAllocatedByteCount() const override;
|
||||
const Descriptor& GetDescriptor() const override;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace AZ
|
||||
/// Returns the hash of the pipeline state descriptor contents.
|
||||
virtual HashValue64 GetHash() const = 0;
|
||||
|
||||
virtual bool operator == (const PipelineStateDescriptor& rhs) const;
|
||||
bool operator == (const PipelineStateDescriptor& rhs) const;
|
||||
|
||||
/// The pipeline layout describing the shader resource bindings.
|
||||
ConstPtr<PipelineLayoutDescriptor> m_pipelineLayoutDescriptor = nullptr;
|
||||
@@ -77,8 +77,7 @@ namespace AZ
|
||||
/// Computes the hash value for this descriptor.
|
||||
HashValue64 GetHash() const override;
|
||||
|
||||
|
||||
virtual bool operator == (const PipelineStateDescriptorForDispatch& rhs) const;
|
||||
bool operator == (const PipelineStateDescriptorForDispatch& rhs) const;
|
||||
|
||||
/// The compute function containing byte code to compile.
|
||||
ConstPtr<ShaderStageFunction> m_computeFunction;
|
||||
@@ -102,7 +101,7 @@ namespace AZ
|
||||
/// Computes the hash value for this descriptor.
|
||||
HashValue64 GetHash() const override;
|
||||
|
||||
virtual bool operator == (const PipelineStateDescriptorForDraw& rhs) const;
|
||||
bool operator == (const PipelineStateDescriptorForDraw& rhs) const;
|
||||
|
||||
/// [Required] The vertex function to compile.
|
||||
ConstPtr<ShaderStageFunction> m_vertexFunction;
|
||||
@@ -135,7 +134,7 @@ namespace AZ
|
||||
//! Computes the hash value for this descriptor.
|
||||
HashValue64 GetHash() const override;
|
||||
|
||||
virtual bool operator == (const PipelineStateDescriptorForRayTracing& rhs) const;
|
||||
bool operator == (const PipelineStateDescriptorForRayTracing& rhs) const;
|
||||
|
||||
// The ray tracing shader byte code
|
||||
ConstPtr<ShaderStageFunction> m_rayTracingFunction;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace AZ
|
||||
VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) override;
|
||||
void DeAllocate(VirtualAddress allocation) override;
|
||||
void GarbageCollect() override;
|
||||
void GarbageCollectForce();
|
||||
void GarbageCollectForce() override;
|
||||
size_t GetAllocationCount() const override;
|
||||
size_t GetAllocatedByteCount() const override;
|
||||
const Descriptor& GetDescriptor() const override;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace AZ
|
||||
ResultCode InitGroup(ShaderResourceGroup& srg);
|
||||
|
||||
//! Returns the descriptor passed at initialization time.
|
||||
const ShaderResourceGroupPoolDescriptor& GetDescriptor() const;
|
||||
const ShaderResourceGroupPoolDescriptor& GetDescriptor() const override;
|
||||
|
||||
//! Returns the SRG layout used when initializing the pool.
|
||||
const ShaderResourceGroupLayout* GetLayout() const;
|
||||
|
||||
@@ -83,11 +83,11 @@ namespace AZ
|
||||
|
||||
#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
|
||||
// On Linux platforms that uses XCB, a resize may occur in the swap chain but the command queue may still
|
||||
// reference the original surface. This flag is a temporary fix to make sure that all the swap chains
|
||||
// have finished their resize events before presenting the command queue.
|
||||
// reference the original surface. This flag is a temporary fix to make sure the swap chain is ready to present
|
||||
// We need to remove this work around with
|
||||
|
||||
// [GFX TODO][GHI - 2678]
|
||||
AZStd::atomic_bool m_resized{ false };
|
||||
AZStd::atomic_bool m_readyToPresent { false };
|
||||
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
|
||||
protected:
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
../Common/Unimplemented/Empty_Unimplemented.cpp
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ::RHI::Platform
|
||||
{
|
||||
bool IsPixDllInjected([[maybe_unused]] const char* dllName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::wstring GetLatestWinPixGpuCapturerPath()
|
||||
{
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user