diff --git a/GigiCompilerLib/Backends/DX12/Backend_DX12.cpp b/GigiCompilerLib/Backends/DX12/Backend_DX12.cpp index cdac965f..f20e304f 100644 --- a/GigiCompilerLib/Backends/DX12/Backend_DX12.cpp +++ b/GigiCompilerLib/Backends/DX12/Backend_DX12.cpp @@ -1069,7 +1069,7 @@ struct BackendDX12 : public BackendBase stringReplacementMap[destinationString] << " = "; } - // Handle SetVariableOperator::BitwiseNot + // Handle operations which require a prefix to the operands if (setVar.op == SetVariableOperator::BitwiseNot) { const Variable& destVar = renderGraph.variables[setVar.destination.variableIndex]; @@ -1082,6 +1082,14 @@ struct BackendDX12 : public BackendBase { stringReplacementMap[destinationString] << "Pow2GE("; } + else if (setVar.op == SetVariableOperator::Minimum) + { + stringReplacementMap[destinationString] << "min("; + } + else if (setVar.op == SetVariableOperator::Maximum) + { + stringReplacementMap[destinationString] << "max("; + } // Write out the first operand if (setVar.AVar.variableIndex != -1) @@ -1120,6 +1128,9 @@ struct BackendDX12 : public BackendBase case SetVariableOperator::Divide: stringReplacementMap[destinationString] << " / "; break; case SetVariableOperator::Modulo: stringReplacementMap[destinationString] << " % "; break; + case SetVariableOperator::Minimum: + case SetVariableOperator::Maximum: stringReplacementMap[destinationString] << ", "; break; + case SetVariableOperator::BitwiseOr: stringReplacementMap[destinationString] << (destVarIsBool ? " || " : " | "); break; case SetVariableOperator::BitwiseAnd: stringReplacementMap[destinationString] << (destVarIsBool ? " && " : " & "); break; case SetVariableOperator::BitwiseXor: stringReplacementMap[destinationString] << " ^ "; break; @@ -1142,6 +1153,11 @@ struct BackendDX12 : public BackendBase { stringReplacementMap[destinationString] << setVar.BLiteral; } + + if (setVar.op == SetVariableOperator::Minimum || setVar.op == SetVariableOperator::Maximum) + { + stringReplacementMap[destinationString] << ")"; + } } // All done @@ -1815,6 +1831,9 @@ void CopyShaderFileDX12(const Shader& shader, const std::unordered_map& stringReplacementMap, const RenderGraph& renderGraph) { - // Gigi "preprocessor" + // Gigi preprocessor size_t offset = 0; while (1) { diff --git a/GigiCompilerLib/SubGraphs.cpp b/GigiCompilerLib/SubGraphs.cpp index 5c0af59b..8e4a6189 100644 --- a/GigiCompilerLib/SubGraphs.cpp +++ b/GigiCompilerLib/SubGraphs.cpp @@ -874,11 +874,51 @@ static bool InlineSubGraph(RenderGraph& parentGraph, RenderGraphNode_Action_SubG // Handle variable replacement // This is when subgraph variables are replaced by parent graph variables { + // Handle "replaceWithValue" - make a constant var with that as the default, and set replaceWithStr to it + { + for (SubGraphVariableSettings& variableSettings : subGraphNode.variableSettings) + { + if (variableSettings.replaceWithValue.empty()) + continue; + + int childVariableIndex = GetVariableIndex(childGraph, variableSettings.name.c_str()); + if (childVariableIndex == -1) + { + ShowErrorMessage("Could not find variable \"%s\" in \"%s\" for node \"%s\".", variableSettings.name.c_str(), childFileName.c_str(), subGraphNode.name.c_str()); + continue; + } + + // make a unique name for the new variable + char variableName[1024]; + int index = 0; + do + { + sprintf_s(variableName, "__literal_%i", index); + index++; + } + while (VariableNameExists(parentGraph, variableName)); + + // make a new variable in the parent graph + Variable newVariable; + newVariable.name = variableName; + newVariable.comment = "Made to replace variable \"" + variableSettings.name + "\" with a constant value in subgraph node \"" + subGraphNode.name + "\""; + newVariable.type = childGraph.variables[childVariableIndex].type; + newVariable.Const = true; + newVariable.dflt = variableSettings.replaceWithValue; + newVariable.transient = true; + parentGraph.variables.push_back(newVariable); + + // tell the subgraph to use this new variable instead + variableSettings.replaceWithStr = variableName; + } + } + // Replace variable references { RenameData renameData; for (const SubGraphVariableSettings& variableSettings : subGraphNode.variableSettings) { + // if no variable replacement to do, skip this if (variableSettings.replaceWithStr.empty() && !variableSettings.isLoopIndex) continue; @@ -1077,10 +1117,25 @@ bool ExpandLoopedSubgraphs(RenderGraph& renderGraph) const RenderGraphNode_Action_SubGraph& subGraph = node.actionSubGraph; - if (subGraph.loopCount > 1) + // Get the loop count + // If a variable is specified, it overrides the literal value given. + int loopCount = subGraph.loopCount; + if (!subGraph.loopCountVariable.name.empty()) + { + for (const Variable& var : renderGraph.variables) + { + if (var.name == subGraph.loopCountVariable.name) + { + sscanf_s(var.dflt.c_str(), "%i", &loopCount); + break; + } + } + } + + if (loopCount > 1) { // Loop over the number of iterations we want - for (int loopIdx = 0; loopIdx < subGraph.loopCount; ++loopIdx) + for (int loopIdx = 0; loopIdx < loopCount; ++loopIdx) { // Copy the original node RenderGraphNode loopNode = node; @@ -1111,7 +1166,7 @@ bool ExpandLoopedSubgraphs(RenderGraph& renderGraph) // If this is the last iteration, other nodes in the parent graph need to have references // to the original subgraph updated to point to the last iteration. - if (loopIdx == subGraph.loopCount-1) + if (loopIdx == loopCount-1) { renameData.m_nodeRenames[oldName] = loopSubGraph.name; } @@ -1304,8 +1359,15 @@ bool InlineSubGraphs(RenderGraph& renderGraph) // detect and report the error of not being able to make progress if (subgraphNodesRemain && !madeProgress) { - ShowErrorMessage("Unable to make progress inlining subgraphs"); - return false; + for (int nodeIndex = 0; nodeIndex < renderGraph.nodes.size(); ++nodeIndex) + { + RenderGraphNode& node = renderGraph.nodes[nodeIndex]; + if (node._index != RenderGraphNode::c_index_actionSubGraph) + continue; + + ShowErrorMessage("Unable to make progress inlining subgraphs. Node \"%s\" could not be inlined, are all of it's inputs plugged in?", node.actionSubGraph.name.c_str()); + return false; + } } } diff --git a/GigiCompilerLib/gigicompiler.cpp b/GigiCompilerLib/gigicompiler.cpp index 1cf6f854..407c7043 100644 --- a/GigiCompilerLib/gigicompiler.cpp +++ b/GigiCompilerLib/gigicompiler.cpp @@ -259,6 +259,21 @@ GigiCompileResult GigiCompile(GigiBuildFlavor buildFlavor, const std::string& js if (PostLoad) PostLoad(renderGraph); + // Shader references need to be resolved first + { + ShaderReferenceFixupVisitor visitor(renderGraph); + if (!Visit(renderGraph, visitor, "renderGraph")) + return GigiCompileResult::ReferenceFixup; + } + + // Process Asserts declarations inside shaders + if (backend == Backend::Interpreter) + { + ShaderAssertsVisitor visitor{ renderGraph }; + if (!Visit(renderGraph, visitor, "renderGraph")) + return GigiCompileResult::ShaderAsserts; + } + // Get data from shaders { ShaderDataVisitor visitor(renderGraph); @@ -273,13 +288,6 @@ GigiCompileResult GigiCompile(GigiBuildFlavor buildFlavor, const std::string& js return GigiCompileResult::Validation; } - // Shader references need to be resolved first - { - ShaderReferenceFixupVisitor visitor(renderGraph); - if (!Visit(renderGraph, visitor, "renderGraph")) - return GigiCompileResult::ReferenceFixup; - } - // resolve the node references from names into indices { ReferenceFixupVisitor visitor(renderGraph); diff --git a/GigiCompilerLib/gigiinterpreter.h b/GigiCompilerLib/gigiinterpreter.h index 2aaf8cd4..422081c3 100644 --- a/GigiCompilerLib/gigiinterpreter.h +++ b/GigiCompilerLib/gigiinterpreter.h @@ -376,6 +376,9 @@ class IGigiInterpreter break; } + case SetVariableOperator::Minimum: dest = std::min(A, B); break; + case SetVariableOperator::Maximum: dest = std::max(A, B); break; + case SetVariableOperator::Noop: dest = A; break; } } @@ -410,6 +413,9 @@ class IGigiInterpreter break; } + case SetVariableOperator::Minimum: dest = std::min(A, B); break; + case SetVariableOperator::Maximum: dest = std::max(A, B); break; + case SetVariableOperator::Noop: dest = A; break; } } diff --git a/GigiEdit/MakeUI.h b/GigiEdit/MakeUI.h index ad69e2c0..e06141cb 100644 --- a/GigiEdit/MakeUI.h +++ b/GigiEdit/MakeUI.h @@ -1483,7 +1483,58 @@ inline UIOverrideResult ShowUIOverride(RenderGraph& renderGraph, uint64_t _FLAGS // Sort the list of variables std::vector vars; for (const Variable& var : renderGraph.variables) + { + if (var.Const) + continue; + vars.push_back(var.name); + } + CaseInsensitiveSort(vars); + + // add a blank to the beginning + vars.insert(vars.begin(), ""); + + // Show a drop down + for (const std::string& label : vars) + { + bool is_selected = value.name == label; + std::string safeLabel = label + "##"; + if (ImGui::Selectable(safeLabel.c_str(), is_selected)) + { + value.name = label; + dirtyFlag = true; + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + + ImGui::EndCombo(); + } + ShowUIToolTip(tooltip); + + ImGui::SameLine(); + if (ArrowButton2("GoToData", ImGuiDir_Right, true, false)) + OnGoToVariable(value.name.c_str()); + ShowUIToolTip("Go to Variable"); + + ImGui::PopID(); + + return UIOverrideResult::Finished; +} + +inline UIOverrideResult ShowUIOverride(RenderGraph& renderGraph, uint64_t _FLAGS, bool& dirtyFlag, const char* label, const char* tooltip, VariableReferenceConstOnly& value, TypePathEntry path, ShowUIOverrideContext showUIOverrideContext) +{ + ImGui::PushID(label); + + if (ImGui::BeginCombo(label, value.name.c_str())) + { + // Sort the list of variables + std::vector vars; + for (const Variable& var : renderGraph.variables) + { + if (!var.Const) + continue; vars.push_back(var.name); + } CaseInsensitiveSort(vars); // add a blank to the beginning @@ -1922,6 +1973,8 @@ struct ShaderTypeCodeGenerator "struct VSInput\n" "{\n" "\tfloat3 position : POSITION;\n" + "\tuint vertexID : SV_VertexID;\n" + "\tuint instanceId : SV_InstanceID;\n" "\t//TODO: fill this out\n" "};\n" "\n" diff --git a/GigiEdit/main.cpp b/GigiEdit/main.cpp index a48df82f..42a491a6 100644 --- a/GigiEdit/main.cpp +++ b/GigiEdit/main.cpp @@ -1676,6 +1676,24 @@ struct Example : name << ")"; break; } + case SetVariableOperator::Minimum: + { + name << "Min("; + name << GetRHS(item.ALiteral, item.ANode, item.AVar, item.AVarIndex); + name << ","; + name << GetRHS(item.BLiteral, item.BNode, item.BVar, item.BVarIndex); + name << ")"; + break; + } + case SetVariableOperator::Maximum: + { + name << "Max("; + name << GetRHS(item.ALiteral, item.ANode, item.AVar, item.AVarIndex); + name << ","; + name << GetRHS(item.BLiteral, item.BNode, item.BVar, item.BVarIndex); + name << ")"; + break; + } case SetVariableOperator::BitwiseOr: { name << GetRHS(item.ALiteral, item.ANode, item.AVar, item.AVarIndex); @@ -1761,6 +1779,7 @@ struct Example : EnsureVariableExists("JitteredViewProjMtx", VariableVisibility::Host, DataFieldType::Float4x4, "1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f"); EnsureVariableExists("InvJitteredViewProjMtx", VariableVisibility::Host, DataFieldType::Float4x4, "1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f"); EnsureVariableExists("CameraPos", VariableVisibility::Host, DataFieldType::Float3, "0.0f, 0.0f, 0.0f"); + EnsureVariableExists("CameraAltitudeAzimuth", VariableVisibility::Host, DataFieldType::Float2, "0.0f, 0.0f"); EnsureVariableExists("CameraChanged", VariableVisibility::Host, DataFieldType::Bool, "false"); EnsureVariableExists("CameraJitter", VariableVisibility::Host, DataFieldType::Float2, "0.5f, 0.5f"); EnsureVariableExists("ShadingRateImageTileSize", VariableVisibility::Host, DataFieldType::Uint, "16"); diff --git a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.cpp b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.cpp index a23e4ca0..70b3677f 100644 --- a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.cpp +++ b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.cpp @@ -402,4 +402,109 @@ void RuntimeTypes::RenderGraphNode_Base::HandleViewableResource(GigiInterpreterP interpreter.m_commandList->CopyResource(resource, uploadBuffer->buffer); } } +} + +std::vector GigiInterpreterPreviewWindowDX12::MarkShaderAssertsForReadback() +{ + std::vector assertsBuffers; + const size_t nodesCount = m_renderGraph.nodes.size(); + for (size_t i = 0; i < nodesCount; ++i) + { + std::vector* viewableResources = nullptr; + RuntimeNodeDataLambda( + m_renderGraph.nodes[i], + [&](auto node, auto* runtimeData) + { + std::string renderGraphText; + + if (runtimeData) + viewableResources = &(runtimeData->m_viewableResources); + } + ); + + if (!viewableResources) + continue; + + for (RuntimeTypes::ViewableResource& res : *viewableResources) + { + std::string_view displayName = res.m_displayName; + const bool isAssertBuf = displayName.find("__GigiAssertUAV") != displayName.npos; + const bool isAfter = displayName.ends_with("(UAV - After)"); + if (isAssertBuf && isAfter) + { + res.m_wantsToBeViewed = true; + res.m_wantsToBeReadBack = true; + + assertsBuffers.push_back(&res); + } + } + } + + return assertsBuffers; +} + +void GigiInterpreterPreviewWindowDX12::CollectShaderAsserts(const std::vector& assertsBuffers) +{ + collectedAsserts.clear(); + + for (const RuntimeTypes::ViewableResource* res : assertsBuffers) + { + if (res->m_resourceReadback) + { + std::vector bytes(res->m_size[0]); + unsigned char* data = nullptr; + res->m_resourceReadback->Map(0, nullptr, reinterpret_cast(&data)); + if (!data) + continue; + + memcpy(bytes.data(), data, res->m_size[0]); + res->m_resourceReadback->Unmap(0, nullptr); + + const uint32_t* assertBufData = reinterpret_cast(bytes.data()); + const uint32_t isFired = assertBufData[0]; + const uint32_t fmtId = assertBufData[1]; + + const std::vector& fmtStrings = m_renderGraph.assertsFormatStrings; + if (fmtId >= fmtStrings.size()) + { + Assert(false, "OOB in asserts format strings array"); + return; + } + + const char* fmt = fmtStrings[fmtId].c_str(); + std::unordered_set& firedAsserts = m_renderGraph.firedAssertsIdentifiers; + const bool isNewAssert = firedAsserts.find(res->m_displayName) == firedAsserts.end(); + + if (isFired && isNewAssert) + { + firedAsserts.insert(res->m_displayName); + + std::string context = res->m_displayName.substr(0, res->m_displayName.find(':')); + + const float* v = reinterpret_cast(bytes.data() + 2 * sizeof(uint32_t)); + + const int fmtSize = std::snprintf(nullptr, 0, fmt, v[0], v[1], v[2], v[3], v[4], v[5]); + if (fmtSize <= 0) + { + Assert(false, "Failed to format the assert message '%s'", fmt); + return; + } + + std::string assertMsg; + assertMsg.resize(fmtSize+1); + std::snprintf(assertMsg.data(), fmtSize+1, fmt, v[0], v[1], v[2], v[3], v[4], v[5]); + + collectedAsserts.push_back({fmtId, fmt, std::move(context), std::move(assertMsg)}); + } + } + } +} + +void GigiInterpreterPreviewWindowDX12::LogCollectedShaderAsserts() const +{ + for (const FiredAssertInfo& a : collectedAsserts) + { + std::string msgHeader = "ASSERT FAILED: [" + a.displayName + "]"; + ShowErrorMessage("%s\nmsg: %s", msgHeader.data(), a.msg.data()); + } } \ No newline at end of file diff --git a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.h b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.h index 11e57a16..110fad70 100644 --- a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.h +++ b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12.h @@ -480,6 +480,18 @@ class GigiInterpreterPreviewWindowDX12 : public IGigiInterpreter return m_profiler.GetProfilingData(); } + struct FiredAssertInfo + { + uint32_t formatStringId; + std::string fmt; + std::string displayName; + std::string msg; + }; + const std::vector& getCollectedShaderAsserts() const { return collectedAsserts; } + std::vector MarkShaderAssertsForReadback(); + void CollectShaderAsserts(const std::vector& assertsBuffers); + void LogCollectedShaderAsserts() const; + public: bool m_showVariablesUI = true; bool m_compileShadersForDebug = false; @@ -648,13 +660,15 @@ class GigiInterpreterPreviewWindowDX12 : public IGigiInterpreter enum class FileWatchOwner { - FileCache, + FileCache = 0, Shaders, TextureCache, ObjCache, FBXCache, PLYCache, GGFile, + + Count }; FileWatcher getFileWatcher() @@ -682,6 +696,8 @@ class GigiInterpreterPreviewWindowDX12 : public IGigiInterpreter bool DrawCall_MakeRootSignature(const RenderGraphNode_Action_DrawCall& node, RuntimeTypes::RenderGraphNode_Action_DrawCall& runtimeData); bool DrawCall_MakeDescriptorTableDesc(std::vector& descs, const RenderGraphNode_Action_DrawCall& node, const Shader& shader, int pinOffset, std::vector& queuedTransitions, const std::unordered_map& importantResourceStates); + std::vector collectedAsserts; + ID3D12Device2* m_device = nullptr; ID3D12CommandQueue* m_commandQueue = nullptr; ID3D12GraphicsCommandList* m_commandList = nullptr; @@ -739,3 +755,18 @@ class GigiInterpreterPreviewWindowDX12 : public IGigiInterpreter D3D12_FEATURE_DATA_D3D12_OPTIONS10 m_dx12_options10 = {}; D3D12_FEATURE_DATA_D3D12_OPTIONS11 m_dx12_options11 = {}; }; + +inline const char* EnumToString(GigiInterpreterPreviewWindowDX12::FileWatchOwner e) +{ + switch (e) + { + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::FileCache: return "FileCache"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::Shaders: return "Shaders"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::TextureCache: return "TextureCache"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::ObjCache: return "ObjCache"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::FBXCache: return "FBXCache"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::PLYCache: return "PLYCache"; + case GigiInterpreterPreviewWindowDX12::FileWatchOwner::GGFile: return "GGFile"; + default: return ""; + } +} diff --git a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12_UI.cpp b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12_UI.cpp index 5c34485f..f5cafc37 100644 --- a/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12_UI.cpp +++ b/GigiViewerDX12/Interpreter/GigiInterpreterPreviewWindowDX12_UI.cpp @@ -572,6 +572,22 @@ static void ShowUI_Count(const RenderGraph& renderGraph, const bool paused, cons // No-op. Shouldn't ever happen } +static std::string VariableUIScope(const Variable& variable) +{ + std::string ret; + + ret = variable.scope; + + if (!variable.UIGroup.empty()) + { + if (!ret.empty()) + ret += "."; + ret += variable.UIGroup + "."; + } + + return ret; +} + void GigiInterpreterPreviewWindowDX12::ShowUI(bool minimalUI, bool paused) { // Minimal UI only shows public variables. @@ -626,25 +642,26 @@ void GigiInterpreterPreviewWindowDX12::ShowUI(bool minimalUI, bool paused) ImGui::PushID(variableGroup.label); // get the list of scopes in this group of variables - std::unordered_set scopes; + std::unordered_set UIScopes; for (const RuntimeVariable& variable : m_runtimeVariables) { if (variable.variable->visibility != variableGroup.visibility) continue; - scopes.insert(variable.variable->scope); + std::string UIScope = VariableUIScope(*variable.variable); + UIScopes.insert(UIScope); } // make an alpha sorted list of scopes - std::vector scopesSorted; - for (const std::string& scope : scopes) - scopesSorted.push_back(scope); - std::sort(scopesSorted.begin(), scopesSorted.end()); + std::vector UIScopesSorted; + for (const std::string& UIScope : UIScopes) + UIScopesSorted.push_back(UIScope); + std::sort(UIScopesSorted.begin(), UIScopesSorted.end()); // show the scopes, one at a time, in alpha order bool visibilityHeaderShown = false; bool visibilityHeaderOpen = true; - for (const std::string& scope : scopesSorted) + for (const std::string& currentUIScope : UIScopesSorted) { // If this visibility header is closed, nothing to do if (!visibilityHeaderOpen) @@ -654,7 +671,7 @@ void GigiInterpreterPreviewWindowDX12::ShowUI(bool minimalUI, bool paused) std::vector runtimeVariablesSorted; for (const RuntimeVariable& variable : m_runtimeVariables) { - if (variable.variable->visibility != variableGroup.visibility || variable.variable->scope != scope) + if (variable.variable->visibility != variableGroup.visibility || VariableUIScope(*variable.variable) != currentUIScope) continue; runtimeVariablesSorted.push_back(&variable); @@ -678,15 +695,15 @@ void GigiInterpreterPreviewWindowDX12::ShowUI(bool minimalUI, bool paused) } // if the scope isn't empty, indent and make a collapsing header - if (!scope.empty()) + if (!currentUIScope.empty()) { - std::string scopeLabel = scope.substr(0, scope.length() - 1); // trim off the dot + std::string scopeLabel = currentUIScope.substr(0, currentUIScope.length() - 1); // trim off the dot if (!ImGui::CollapsingHeader(scopeLabel.c_str())) continue; } // push the scope to make the variable imgui IDs unique - ImGui::PushID(scope.c_str()); + ImGui::PushID(currentUIScope.c_str()); // Show variable labels and value for (const RuntimeVariable* var : runtimeVariablesSorted) diff --git a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_ComputeShader.cpp b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_ComputeShader.cpp index c6ff9651..700a7d54 100644 --- a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_ComputeShader.cpp +++ b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_ComputeShader.cpp @@ -329,7 +329,7 @@ bool GigiInterpreterPreviewWindowDX12::OnNodeAction(const RenderGraphNode_Action if (!desc.m_resource) { std::ostringstream ss; - ss << "Cannot run due to resource not existing:\n" << GetNodeTypeString(resourceNode) << " " << GetNodeName(resourceNode) << " (" << GetNodeOriginalName(resourceNode) << ")"; + ss << "Cannot run due to resource not existing:\n" << GetNodeTypeString(resourceNode) << " \"" << GetNodeName(resourceNode) << "\" (\"" << GetNodeOriginalName(resourceNode) << "\")"; runtimeData.m_renderGraphText = ss.str(); return true; } diff --git a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_CopyResource.cpp b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_CopyResource.cpp index 682ccc6a..0534b8b9 100644 --- a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_CopyResource.cpp +++ b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_CopyResource.cpp @@ -12,6 +12,11 @@ bool GigiInterpreterPreviewWindowDX12::OnNodeAction(const RenderGraphNode_Action if (nodeAction == NodeAction::Execute) { + std::ostringstream ss; + if (IsConditional(node.condition)) + ss << "\nCondition: " << (EvaluateCondition(node.condition) ? "true" : "false"); + runtimeData.m_renderGraphText = ss.str(); + bool executionConditionMet = EvaluateCondition(node.condition); if (!executionConditionMet) return true; diff --git a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_DrawCall.cpp b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_DrawCall.cpp index 97341db2..dd921c91 100644 --- a/GigiViewerDX12/Interpreter/RenderGraphNode_Action_DrawCall.cpp +++ b/GigiViewerDX12/Interpreter/RenderGraphNode_Action_DrawCall.cpp @@ -623,6 +623,14 @@ bool GigiInterpreterPreviewWindowDX12::DrawCall_MakeRootSignature(const RenderGr psoDesc.DepthStencilState.FrontFace.StencilFunc = DepthTestFunctionToD3D12_COMPARISON_FUNC(node.frontFaceStencilFunc); psoDesc.DepthStencilState.BackFace.StencilFunc = DepthTestFunctionToD3D12_COMPARISON_FUNC(node.backFaceStencilFunc); } + if (!textureInfoFormatInfo.isDepth) + { + static bool erroredHere = false; + if (!erroredHere) + m_logFn(LogLevel::Error, "Depth texture \"%s\" is not a valid depth format: %s", resourceNode.resourceTexture.name.c_str(), textureInfoFormatInfo.name); + erroredHere = true; + return SetupPSODescRet::False; + } } } diff --git a/GigiViewerDX12/Interpreter/RenderGraphNode_Resource_Texture.cpp b/GigiViewerDX12/Interpreter/RenderGraphNode_Resource_Texture.cpp index b35b55d6..ebae2f20 100644 --- a/GigiViewerDX12/Interpreter/RenderGraphNode_Resource_Texture.cpp +++ b/GigiViewerDX12/Interpreter/RenderGraphNode_Resource_Texture.cpp @@ -1077,7 +1077,31 @@ bool GigiInterpreterPreviewWindowDX12::OnNodeActionNotImported(const RenderGraph bool hasFileName = !node.loadFileName.empty() && FileNameSafe(node.loadFileName.c_str()); std::string fullLoadFileName = m_tempDirectory + "assets\\" + node.loadFileName; - if (desiredFormat != DXGI_FORMAT_FORCE_UINT && (hasSize || hasFileName) && !runtimeData.m_failed) + if (!(desiredFormat != DXGI_FORMAT_FORCE_UINT && (hasSize || hasFileName) && !runtimeData.m_failed)) + { + std::ostringstream ss; + ss << "Texture can't be created:"; + + if (desiredFormat == DXGI_FORMAT_FORCE_UINT) + { + ss << "\nCould not determine desired format of texture"; + } + + if (!(hasSize || hasFileName)) + { + ss << "\nCould not determine size of texture"; + if (!hasFileName && desiredSize[2] == 0) + ss << "\nThe z component of the texture size is 0, should be > 0."; + } + + if (runtimeData.m_failed) + { + ss << "\nCreation Failed"; + } + + runtimeData.m_renderGraphText = ss.str(); + } + else { std::vector loadedTextures; diff --git a/GigiViewerDX12/ViewerPython.cpp b/GigiViewerDX12/ViewerPython.cpp index ed7956e6..d8b94334 100644 --- a/GigiViewerDX12/ViewerPython.cpp +++ b/GigiViewerDX12/ViewerPython.cpp @@ -696,6 +696,80 @@ static PyObject* Python_GetGPUString(PyObject* self, PyObject* args) return Py_BuildValue("s", g_interface->GetGPUString().c_str()); } +static PyObject* Python_SetShaderAssertsLogging(PyObject* self, PyObject* args) +{ + int value = 1; + if (!PyArg_ParseTuple(args, "p:Python_SetShaderAssertsLogging", &value)) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "()"); + + g_interface->SetShaderAssertsLogging(value == 1); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* Python_GetCollectedShaderAssertsCount(PyObject* self, PyObject* args) +{ + const int count = g_interface->GetCollectedShaderAssertsCount(); + return Py_BuildValue("i", count); +} + +static PyObject* Python_GetShaderAssertFormatStrId(PyObject* self, PyObject* args) +{ + int assertId = 1; + if (!PyArg_ParseTuple(args, "i:Python_GetShaderAssertFormatStrId", &assertId)) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "()"); + + const int count = (int)g_interface->GetCollectedShaderAssertsCount(); + if (assertId >= count) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "(). OOB access (id:%d, asserts count: %d)", assertId, count); + + const int strId = g_interface->GetShaderAssertFormatStrId(assertId); + return Py_BuildValue("i", strId); +} + +static PyObject* Python_GetShaderAssertFormatString(PyObject* self, PyObject* args) +{ + int assertId = 1; + if (!PyArg_ParseTuple(args, "i:Python_GetShaderAssertFormatString", &assertId)) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "()"); + + const int count = (int)g_interface->GetCollectedShaderAssertsCount(); + if (assertId >= count) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "(). OOB access (id:%d, asserts count: %d)", assertId, count); + + const std::string fmt = g_interface->GetShaderAssertFormatString(assertId); + return Py_BuildValue("s", fmt.c_str()); +} + +static PyObject* Python_GetShaderAssertDisplayName(PyObject* self, PyObject* args) +{ + int assertId = 1; + if (!PyArg_ParseTuple(args, "i:Python_GetShaderAssertDisplayName", &assertId)) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "()"); + + const int count = (int)g_interface->GetCollectedShaderAssertsCount(); + if (assertId >= count) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "(). OOB access (id:%d, asserts count: %d)", assertId, count); + + const std::string displayName = g_interface->GetShaderAssertDisplayName(assertId); + return Py_BuildValue("s", displayName.c_str()); +} + +static PyObject* Python_GetShaderAssertMsg(PyObject* self, PyObject* args) +{ + int assertId = 1; + if (!PyArg_ParseTuple(args, "i:Python_GetShaderAssertMsg", &assertId)) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "()"); + + const int count = (int)g_interface->GetCollectedShaderAssertsCount(); + if (assertId >= count) + return PyErr_Format(PyExc_TypeError, "type error in " __FUNCTION__ "(). OOB access (id:%d, asserts count: %d)", assertId, count); + + const std::string msg = g_interface->GetShaderAssertMsg(assertId); + return Py_BuildValue("s", msg.c_str()); +} + // Enum FromString #include "external/df_serialize/_common.h" #define ENUM_BEGIN(_NAME, _DESCRIPTION) \ @@ -831,7 +905,12 @@ void PythonInit(PythonInterface* interface, int argc, char** argv, int firstPyth {"GGEnumLabel", Python_GGEnumLabel, METH_VARARGS, "Gets the string label of an enum defined in the loaded .gg file."}, {"GGEnumCount", Python_GGEnumCount, METH_VARARGS, "Returns the number of enum values for an enum defined in the loaded .gg file."}, {"GetGPUString", Python_GetGPUString, METH_VARARGS, "Returns the name of the gpu and driver version."}, - + {"SetShaderAssertsLogging", Python_SetShaderAssertsLogging, METH_VARARGS, "Toggles auto error logging of the collected shader asserts after a technique execution."}, + {"GetCollectedShaderAssertsCount", Python_GetCollectedShaderAssertsCount, METH_VARARGS, "Returns the number of collected shader asserts. Assert getters works with this collection."}, + {"GetShaderAssertFormatStrId", Python_GetShaderAssertFormatStrId, METH_VARARGS, "Returns the ID of format string of the specified shader assert."}, + {"GetShaderAssertFormatString", Python_GetShaderAssertFormatString, METH_VARARGS, "Returns the format string of the specified shader assert."}, + {"GetShaderAssertDisplayName", Python_GetShaderAssertDisplayName, METH_VARARGS, "Returns the display name of the specified shader assert."}, + {"GetShaderAssertMsg", Python_GetShaderAssertMsg, METH_VARARGS, "Returns the message of the specified assert."}, // Enum FromString and ToString functions #include "external/df_serialize/_common.h" #define ENUM_BEGIN(_NAME, _DESCRIPTION) \ diff --git a/GigiViewerDX12/ViewerPython.h b/GigiViewerDX12/ViewerPython.h index 314d14e4..57a227b8 100644 --- a/GigiViewerDX12/ViewerPython.h +++ b/GigiViewerDX12/ViewerPython.h @@ -69,6 +69,13 @@ class PythonInterface virtual void ForceEnableProfiling(bool forceEnable) = 0; virtual std::vector GetProfilingData() = 0; + virtual void SetShaderAssertsLogging(bool set) = 0; + virtual int GetCollectedShaderAssertsCount() = 0; + virtual int GetShaderAssertFormatStrId(int i) = 0; + virtual std::string GetShaderAssertFormatString(int i) = 0; + virtual std::string GetShaderAssertDisplayName(int i) = 0; + virtual std::string GetShaderAssertMsg(int i) = 0; + virtual void Log(LogLevel level, const char* msg, ...) = 0; virtual void OnExecuteFinished() = 0; diff --git a/GigiViewerDX12/main.cpp b/GigiViewerDX12/main.cpp index def0afbb..27e191d8 100644 --- a/GigiViewerDX12/main.cpp +++ b/GigiViewerDX12/main.cpp @@ -149,12 +149,6 @@ static bool g_imageLinearFilter = true; static bool g_hideUI = false; static bool g_hideResourceNodes = true; // in profiler, and render graph window. To reduce clutter of things that we don't care about. static bool g_onlyShowWrites = true; // Hide SRV, UAV before, etc. Only show the result of writes. -static bool g_hideFileCacheDetails = true; // in internal variables. To reduce clutter of things that we don't care about. -static bool g_hideTrackedFilesDetails = true; // in internal variables. To reduce clutter of things that we don't care about. -static bool g_hideObjectCacheDetails = true; // in internal variables. To reduce clutter of things that we don't care about. -static bool g_hideFBXCacheDetails = true; // in internal variables. To reduce clutter of things that we don't care about. -static bool g_hidePLYCacheDetails = true; // in internal variables. To reduce clutter of things that we don't care about. -static bool g_hideTextureCacheDetails = true; // in internal variables. To reduce clutter of things that we don't care about. static bool g_fullscreen = false; @@ -393,7 +387,6 @@ struct ResourceViewState float systemVarMouseState[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; float systemVarMouseStateLastFrame[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; -private: void StoreLast() { lastType = type; @@ -404,9 +397,8 @@ struct ResourceViewState static ResourceViewState g_resourceView; static GGUserFile_SystemVars g_systemVariables; -static std::vector g_bookmarks; -static std::vector g_importedResourcePresets; -static char g_importedResourcePresetsName[1024] = { 0 }; +static std::vector g_userSnapshots; +static int g_userSnapshotIndex = -1; // Forward declarations of helper functions bool CreateDeviceD3D(HWND hWnd); @@ -433,6 +425,8 @@ int g_executeTechniqueCountRemain = 0; bool g_executeTechnique = true; bool g_techniquePaused = false; +bool g_logCollectedShaderAsserts = true; + std::string g_commandLineLoadGGFileName; std::string g_runPyFileName; @@ -666,59 +660,91 @@ GGUserFile_ImportedResource ImportedResourceDesc_To_GGUserFile_ImportedResource( return outDesc; } -void SaveGGUserFile() +void ScatterSnapshotData(const GGUserFileV2Snapshot& snapshot, bool switchingSnapshots, bool loadCamera, bool loadView, bool loadResources) { - // if saving gguser files is disabled by script, don't do it - if (g_disableGGUserSave) - return; + if (loadCamera) + { + g_systemVariables.camera.cameraPos = snapshot.cameraPos; + g_systemVariables.camera.cameraAltitudeAzimuth = snapshot.cameraAltitudeAzimuth; + g_systemVariables.camera.cameraChanged = true; + } - // If we didn't properly load & compile the render graph, saving the gguser file would corrupt it, so we don't want to do that - if (!g_saveGGUserFile) - return; + if (loadView) + { + g_resourceView.type = (RuntimeTypes::ViewableResource::Type)snapshot.resourceViewType; + g_resourceView.nodeIndex = snapshot.resourceViewNodeIndex; + g_resourceView.resourceIndex = snapshot.resourceViewResourceIndex; + } - // nothing to do if no file name - if (g_renderGraphFileName.empty()) - return; + if (loadResources) + { + std::filesystem::path renderGraphDir = std::filesystem::path(g_renderGraphFileName).remove_filename(); + for (const GGUserFile_ImportedResource& inDesc : snapshot.importedResources) + { + GigiInterpreterPreviewWindowDX12::ImportedResourceDesc desc = GGUserFile_ImportedResource_To_ImportedResourceDesc(inDesc, renderGraphDir); - // make .gguser file name - std::string extension; - size_t extensionStart = g_renderGraphFileName.find_last_of("."); - if (extensionStart != std::string::npos) - extension = g_renderGraphFileName.substr(extensionStart); + if (!switchingSnapshots) + desc.stale = true; - std::string ggUserFileName; - if (extension == ".gg") - ggUserFileName = g_renderGraphFileName + "user"; - else - ggUserFileName = g_renderGraphFileName + ".gguser"; + desc.state = GigiInterpreterPreviewWindowDX12::ImportedResourceState::dirty; + + if (g_interpreter.m_importedResources.count(inDesc.nodeName) > 0) + { + desc.nodeIndex = g_interpreter.m_importedResources[inDesc.nodeName].nodeIndex; + desc.resourceIndex = g_interpreter.m_importedResources[inDesc.nodeName].resourceIndex; + } + + g_interpreter.m_importedResources[inDesc.nodeName] = desc; + } + } +} + +void ScatterSnapshotVariables(const GGUserFileV2Snapshot& snapshot) +{ + for (const auto& savedVariable : snapshot.savedVariables) + { + int rtVarIndex = g_interpreter.GetRuntimeVariableIndex(savedVariable.name.c_str()); + if (rtVarIndex == -1) + continue; + g_interpreter.SetRuntimeVariableFromString(rtVarIndex, savedVariable.value.c_str()); + } +} + +void GatherSnapshotData(GGUserFileV2Snapshot& snapshot) +{ + snapshot.resourceViewType = (int)g_resourceView.type; + snapshot.resourceViewNodeIndex = g_resourceView.nodeIndex; + snapshot.resourceViewResourceIndex = g_resourceView.resourceIndex; + + snapshot.cameraPos = g_systemVariables.camera.cameraPos; + snapshot.cameraAltitudeAzimuth = g_systemVariables.camera.cameraAltitudeAzimuth; - // Fill out the GGUserFile std::filesystem::path renderGraphDir = std::filesystem::path(g_renderGraphFileName).remove_filename(); - GGUserFile ggUserData; - ggUserData.resourceViewType = (int)g_resourceView.type; - ggUserData.resourceViewNodeIndex = g_resourceView.nodeIndex; - ggUserData.resourceViewResourceIndex = g_resourceView.resourceIndex; - ggUserData.syncInterval = g_syncInterval; + snapshot.importedResources.clear(); for (const auto& it : g_interpreter.m_importedResources) - ggUserData.importedResources.push_back(ImportedResourceDesc_To_GGUserFile_ImportedResource(it.first, it.second, renderGraphDir)); + snapshot.importedResources.push_back(ImportedResourceDesc_To_GGUserFile_ImportedResource(it.first, it.second, renderGraphDir)); // sort the names of the imported resources so we can save them in a stable (alphabetical) order - std::sort(ggUserData.importedResources.begin(), ggUserData.importedResources.end(), + std::sort(snapshot.importedResources.begin(), snapshot.importedResources.end(), [](const GGUserFile_ImportedResource& a, const GGUserFile_ImportedResource& b) { return a.nodeName < b.nodeName; } ); - ggUserData.systemVars = g_systemVariables; - ggUserData.bookmarks = g_bookmarks; - ggUserData.importedResourcePresets = g_importedResourcePresets; - // Fill out the variables for (int varIndex = 0; varIndex < g_interpreter.GetRuntimeVariableCount(); ++varIndex) { const auto& rtVar = g_interpreter.GetRuntimeVariable(varIndex); + // don't save const vars + if (rtVar.variable->Const) + continue; + + // don't save transient vars + if (rtVar.variable->transient) + continue; + // don't save system variables if (rtVar.variable->name == g_systemVariables.iResolution_varName || rtVar.variable->name == g_systemVariables.iTime_varName || @@ -739,31 +765,77 @@ void SaveGGUserFile() rtVar.variable->name == g_systemVariables.JitteredViewProjMtx_varName || rtVar.variable->name == g_systemVariables.InvJitteredViewProjMtx_varName || rtVar.variable->name == g_systemVariables.CameraPos_varName || + rtVar.variable->name == g_systemVariables.CameraAltitudeAzimuth_varName || rtVar.variable->name == g_systemVariables.CameraChanged_varName || rtVar.variable->name == g_systemVariables.CameraJitter_varName || rtVar.variable->name == g_systemVariables.WindowSize_varName || rtVar.variable->name == g_systemVariables.ShadingRateImageTileSize_varName) continue; - // don't save const vars, or transient vars - if (rtVar.variable->Const || rtVar.variable->transient) - continue; - GGUserFile_SavedVariable var; var.name = rtVar.variable->name; var.value = g_interpreter.GetRuntimeVariableValueAsString(varIndex); - ggUserData.savedVariables.push_back(var); + snapshot.savedVariables.push_back(var); } +} + +void SaveGGUserFile() +{ + // if saving gguser files is disabled by script, don't do it + if (g_disableGGUserSave) + return; + + // If we didn't properly load & compile the render graph, saving the gguser file would corrupt it, so we don't want to do that + if (!g_saveGGUserFile) + return; + + // nothing to do if no file name + if (g_renderGraphFileName.empty()) + return; + + // make .gguser file name + std::string extension; + size_t extensionStart = g_renderGraphFileName.find_last_of("."); + if (extensionStart != std::string::npos) + extension = g_renderGraphFileName.substr(extensionStart); + + std::string ggUserFileName; + if (extension == ".gg") + ggUserFileName = g_renderGraphFileName + "user"; + else + ggUserFileName = g_renderGraphFileName + ".gguser"; + + // Fill out the GGUserFile + GGUserFileV2 ggUserData; + GatherSnapshotData(ggUserData.snapshot); + ggUserData.syncInterval = g_syncInterval; + ggUserData.systemVars = g_systemVariables; + ggUserData.snapshots = g_userSnapshots; // Save the data WriteToJSONFile(ggUserData, ggUserFileName.c_str()); } -GGUserFile LoadGGUserFile() +// When we have more version we can string these conversions together +bool ConvertGGUserFile(const GGUserFileV1& oldFile, GGUserFileV2& newFile) +{ + newFile.syncInterval = oldFile.syncInterval; + newFile.systemVars = oldFile.systemVars; + + newFile.snapshot.resourceViewType = oldFile.resourceViewType; + newFile.snapshot.resourceViewNodeIndex = oldFile.resourceViewNodeIndex; + newFile.snapshot.resourceViewResourceIndex = oldFile.resourceViewResourceIndex; + newFile.snapshot.importedResources = oldFile.importedResources; + newFile.snapshot.savedVariables = oldFile.savedVariables; + + return true; +} + +GGUserFileV2 LoadGGUserFile() { // nothing to do if no file name if (g_renderGraphFileName.empty()) - return GGUserFile(); + return GGUserFileV2(); // make .gguser file name std::string extension; @@ -778,34 +850,45 @@ GGUserFile LoadGGUserFile() ggUserFileName = g_renderGraphFileName + ".gguser"; // only try to load it if the file exists - GGUserFile ggUserData; + GGUserFileV2 ggUserData; FILE* file = nullptr; fopen_s(&file, ggUserFileName.c_str(), "rb"); + bool loadFailed = false; if (file) { fclose(file); - if (!ReadFromJSONFile(ggUserData, ggUserFileName.c_str())) - ggUserData = GGUserFile(); + GGUserFileVersionOnly ggUserDataVersion; + if (ReadFromJSONFile(ggUserDataVersion, ggUserFileName.c_str())) + { + if (ggUserDataVersion.version == "1.0") + { + GGUserFileV1 ggUserDataOld; + + if (!ReadFromJSONFile(ggUserDataOld, ggUserFileName.c_str()) || !ConvertGGUserFile(ggUserDataOld, ggUserData)) + loadFailed = true; + } + else if (ggUserDataVersion.version == "2.0") + { + if (!ReadFromJSONFile(ggUserData, ggUserFileName.c_str())) + loadFailed = true; + } + else + { + loadFailed = true; + } + } + + if (loadFailed) + ggUserData = GGUserFileV2(); } // restore the saved data - std::filesystem::path renderGraphDir = std::filesystem::path(g_renderGraphFileName).remove_filename(); - g_resourceView.type = (RuntimeTypes::ViewableResource::Type)ggUserData.resourceViewType; - g_resourceView.nodeIndex = ggUserData.resourceViewNodeIndex; - g_resourceView.resourceIndex = ggUserData.resourceViewResourceIndex; - g_syncInterval = ggUserData.syncInterval; g_interpreter.m_importedResources.clear(); - for (const GGUserFile_ImportedResource& inDesc : ggUserData.importedResources) - { - GigiInterpreterPreviewWindowDX12::ImportedResourceDesc desc = GGUserFile_ImportedResource_To_ImportedResourceDesc(inDesc, renderGraphDir); - desc.stale = true; - g_interpreter.m_importedResources[inDesc.nodeName] = desc; - } - + ScatterSnapshotData(ggUserData.snapshot, false, true, true, true); + g_syncInterval = ggUserData.syncInterval; g_systemVariables = ggUserData.systemVars; - g_bookmarks = ggUserData.bookmarks; - g_importedResourcePresets = ggUserData.importedResourcePresets; - g_importedResourcePresetsName[0] = 0; + g_userSnapshots = ggUserData.snapshots; + g_userSnapshotIndex = -1; g_systemVariables.camera.cameraPos = g_systemVariables.camera.startingCameraPos; g_systemVariables.camera.cameraAltitudeAzimuth = g_systemVariables.camera.startingCameraAltitudeAzimuth; @@ -829,7 +912,7 @@ bool LoadGGFile(const char* fileName, bool preserveState) // save the old gg user file, and then load the new one after we change our file name SaveGGUserFile(); g_renderGraphFileName = fileName; - GGUserFile ggUserData = LoadGGUserFile(); + auto ggUserData = LoadGGUserFile(); // clear if we should if (g_renderGraphFileName.empty()) @@ -862,14 +945,7 @@ bool LoadGGFile(const char* fileName, bool preserveState) return false; } - // Load the saved variable values from the GGUser file, now that the render graph is loaded and compiled - for (const auto& savedVariable : ggUserData.savedVariables) - { - int rtVarIndex = g_interpreter.GetRuntimeVariableIndex(savedVariable.name.c_str()); - if (rtVarIndex == -1) - continue; - g_interpreter.SetRuntimeVariableFromString(rtVarIndex, savedVariable.value.c_str()); - } + ScatterSnapshotVariables(ggUserData.snapshot); // Set all const variables to their const value for (const Variable& variable : g_interpreter.GetRenderGraph().variables) @@ -1239,7 +1315,10 @@ void HandleMainMenu() if (ImGui::Button("Open Editor")) { char commandLine[1024]; - sprintf_s(commandLine, "GigiEdit.exe \"%s\"", g_renderGraphFileName.c_str()); + if (g_renderGraphFileName.empty()) + sprintf_s(commandLine, "GigiEdit.exe"); + else + sprintf_s(commandLine, "GigiEdit.exe \"%s\"", g_renderGraphFileName.c_str()); STARTUPINFOA si; ZeroMemory(&si, sizeof(si)); @@ -1628,6 +1707,7 @@ void ShowNodeDropDown(const std::string& label, int nodeType, std::string& value value = labelsStr[selection]; } +// if assignVariable is false, it will assign "value" the value from the variable template bool AssignVariable(const char* name, DataFieldType type, T value) { @@ -1660,7 +1740,7 @@ DirectX::XMMATRIX GetViewMatrix() return DirectX::XMMatrixTranslation(-g_systemVariables.camera.cameraPos[0], -g_systemVariables.camera.cameraPos[1], -g_systemVariables.camera.cameraPos[2]) * rot; } -void UpdateSystemVariables() +void SynchronizeSystemVariables() { auto context = ImGui::GetCurrentContext(); @@ -1695,19 +1775,24 @@ void UpdateSystemVariables() AssignVariable(g_systemVariables.WindowSize_varName.c_str(), DataFieldType::Float2, size); } + // Time AssignVariable(g_systemVariables.iTime_varName.c_str(), DataFieldType::Float, (float)(context->Time - g_startTime)); - if (g_forcedFrameDeltaTime > 0.0f) + // Frame Delta { - AssignVariable(g_systemVariables.iTimeDelta_varName.c_str(), DataFieldType::Float, g_forcedFrameDeltaTime); - AssignVariable(g_systemVariables.iFrameRate_varName.c_str(), DataFieldType::Float, 1.0f / g_forcedFrameDeltaTime); - } - else - { - AssignVariable(g_systemVariables.iTimeDelta_varName.c_str(), DataFieldType::Float, (float)context->IO.DeltaTime); - AssignVariable(g_systemVariables.iFrameRate_varName.c_str(), DataFieldType::Float, (float)context->IO.Framerate); + if (g_forcedFrameDeltaTime > 0.0f) + { + AssignVariable(g_systemVariables.iTimeDelta_varName.c_str(), DataFieldType::Float, g_forcedFrameDeltaTime); + AssignVariable(g_systemVariables.iFrameRate_varName.c_str(), DataFieldType::Float, 1.0f / g_forcedFrameDeltaTime); + } + else + { + AssignVariable(g_systemVariables.iTimeDelta_varName.c_str(), DataFieldType::Float, context->IO.DeltaTime); + AssignVariable(g_systemVariables.iFrameRate_varName.c_str(), DataFieldType::Float, context->IO.Framerate); + } } + // Frame Index AssignVariable(g_systemVariables.iFrame_varName.c_str(), DataFieldType::Int, g_techniqueFrameIndex); // Mouse @@ -1934,40 +2019,48 @@ void UpdateSystemVariables() } } - DirectX::XMMATRIX invProjMtx = DirectX::XMMatrixInverse(nullptr, projMtx); - DirectX::XMMATRIX invJitteredProjMtx = DirectX::XMMatrixInverse(nullptr, jitteredProjMtx); - - DirectX::XMMATRIX viewMtx = GetViewMatrix(); - DirectX::XMMATRIX invViewMtx = DirectX::XMMatrixInverse(nullptr, viewMtx); + { + DirectX::XMMATRIX invProjMtx = DirectX::XMMatrixInverse(nullptr, projMtx); + DirectX::XMMATRIX invJitteredProjMtx = DirectX::XMMatrixInverse(nullptr, jitteredProjMtx); - // Send all the camera info to the appropriate variables + DirectX::XMMATRIX viewMtx = GetViewMatrix(); + DirectX::XMMATRIX invViewMtx = DirectX::XMMatrixInverse(nullptr, viewMtx); - AssignVariable(g_systemVariables.ViewMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(viewMtx)); - AssignVariable(g_systemVariables.InvViewMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invViewMtx)); + DirectX::XMMATRIX viewProjMtx = viewMtx * projMtx; + DirectX::XMMATRIX invViewProjMtx = XMMatrixInverse(nullptr, viewProjMtx); - AssignVariable(g_systemVariables.ProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(projMtx)); - AssignVariable(g_systemVariables.InvProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invProjMtx)); + DirectX::XMMATRIX jitteredViewProjMtx = viewMtx * jitteredProjMtx; + DirectX::XMMATRIX invJitteredViewProjMtx = XMMatrixInverse(nullptr, jitteredViewProjMtx); - AssignVariable(g_systemVariables.JitteredProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(jitteredProjMtx)); - AssignVariable(g_systemVariables.InvJitteredProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invJitteredProjMtx)); + // Camera Matrices + { + AssignVariable(g_systemVariables.ViewMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(viewMtx)); + AssignVariable(g_systemVariables.InvViewMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invViewMtx)); - DirectX::XMMATRIX viewProjMtx = viewMtx * projMtx; - DirectX::XMMATRIX invViewProjMtx = XMMatrixInverse(nullptr, viewProjMtx); + AssignVariable(g_systemVariables.ProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(projMtx)); + AssignVariable(g_systemVariables.InvProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invProjMtx)); - AssignVariable(g_systemVariables.ViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(viewProjMtx)); - AssignVariable(g_systemVariables.InvViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invViewProjMtx)); + AssignVariable(g_systemVariables.JitteredProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(jitteredProjMtx)); + AssignVariable(g_systemVariables.InvJitteredProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invJitteredProjMtx)); - DirectX::XMMATRIX jitteredViewProjMtx = viewMtx * jitteredProjMtx; - DirectX::XMMATRIX invJitteredViewProjMtx = XMMatrixInverse(nullptr, jitteredViewProjMtx); + AssignVariable(g_systemVariables.ViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(viewProjMtx)); + AssignVariable(g_systemVariables.InvViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invViewProjMtx)); - AssignVariable(g_systemVariables.JitteredViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(jitteredViewProjMtx)); - AssignVariable(g_systemVariables.InvJitteredViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invJitteredViewProjMtx)); + AssignVariable(g_systemVariables.JitteredViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(jitteredViewProjMtx)); + AssignVariable(g_systemVariables.InvJitteredViewProjMtx_varName.c_str(), DataFieldType::Float4x4, XMMatrixTranspose(invJitteredViewProjMtx)); + } - AssignVariable(g_systemVariables.CameraPos_varName.c_str(), DataFieldType::Float3, g_systemVariables.camera.cameraPos); + // Camera Position and altitude azimuth + // Variables read/write + AssignVariable(g_systemVariables.CameraPos_varName.c_str(), DataFieldType::Float3, g_systemVariables.camera.cameraPos); + AssignVariable(g_systemVariables.CameraAltitudeAzimuth_varName.c_str(), DataFieldType::Float2, g_systemVariables.camera.cameraAltitudeAzimuth); - AssignVariable(g_systemVariables.CameraJitter_varName.c_str(), DataFieldType::Float2, jitter); + // camera jitter + AssignVariable(g_systemVariables.CameraJitter_varName.c_str(), DataFieldType::Float2, jitter); - AssignVariable(g_systemVariables.ShadingRateImageTileSize_varName.c_str(), DataFieldType::Uint, g_interpreter.GetOptions6().ShadingRateImageTileSize); + // Shading rate image tile size + AssignVariable(g_systemVariables.ShadingRateImageTileSize_varName.c_str(), DataFieldType::Uint, g_interpreter.GetOptions6().ShadingRateImageTileSize); + } } } @@ -2158,10 +2251,7 @@ void ShowInternalVariables() ImGui::EndTable(); } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide File Cache Details", &g_hideFileCacheDetails); - - if (!g_hideFileCacheDetails) + if (ImGui::CollapsingHeader("File Cache")) { //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) static std::vector c_file_cache_details_file_display; @@ -2200,54 +2290,20 @@ void ShowInternalVariables() } } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide Tracked Files Details", &g_hideTrackedFilesDetails); - - if (!g_hideTrackedFilesDetails) + if (ImGui::CollapsingHeader("Tracked Files")) { - //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) - static std::vector c_file_watcher_details_file_display; - static std::vector c_file_watcher_details_file_type; - if (has_elapsed || c_file_watcher_details_file_display.size() == 0) { - c_file_watcher_details_file_display = {}; - c_file_watcher_details_file_type = {}; - for (auto const& ent1 : g_interpreter.getFileWatcher().getTrackedFiles()) { - auto const& key = ent1.first; - auto const& val = ent1.second; - auto const& type_data = val.data; - std::string base_filename = key.substr(key.find_last_of("/\\") + 1); - const char* for_display_name = base_filename.c_str(); - std::string for_display_type_tmp; - //TODO: can't properly display enum values of type GigiInterpreterPreviewWindowDX12::FileWatchOwner, so using it's index value to convert for now - int value_loc = static_cast(type_data); - switch (value_loc) - { - case 0: - for_display_type_tmp = "FileCache"; - break; - case 1: - for_display_type_tmp = "Shaders"; - break; - case 2: - for_display_type_tmp = "TextureCache"; - break; - case 3: - for_display_type_tmp = "ObjCache"; - break; - case 4: - for_display_type_tmp = "FBXCache"; - break; - case 5: - for_display_type_tmp = "PLYCache"; - break; - case 6: - for_display_type_tmp = "GGFile"; - break; - } - const char* for_display_type = for_display_type_tmp.c_str(); - c_file_watcher_details_file_display.push_back(for_display_name); - c_file_watcher_details_file_type.push_back(for_display_type); + static int filterSelected = -1; + if (ImGui::BeginCombo("Type", filterSelected == -1 ? "All" : EnumToString((GigiInterpreterPreviewWindowDX12::FileWatchOwner)filterSelected))) + { + if (ImGui::Selectable("All", filterSelected == -1)) + filterSelected = -1; + + for (int typeIndex = 0; typeIndex < (int)GigiInterpreterPreviewWindowDX12::FileWatchOwner::Count; ++typeIndex) + { + if (ImGui::Selectable(EnumToString((GigiInterpreterPreviewWindowDX12::FileWatchOwner)typeIndex), filterSelected == typeIndex)) + filterSelected = typeIndex; } + ImGui::EndCombo(); } if (ImGui::BeginTable("tracked files details", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) @@ -2258,25 +2314,31 @@ void ShowInternalVariables() ImGui::TableHeadersRow(); ImGui::TableNextRow(); ImGui::TableNextColumn(); - for (int rowCtr = 0; rowCtr < c_file_watcher_val; rowCtr++) { - ImGui::Text("%d", rowCtr + 1); - const char* file_name = c_file_watcher_details_file_display[rowCtr].c_str(); - const char* file_type = c_file_watcher_details_file_type[rowCtr].c_str(); + + int index = 0; + for (auto const& entry : g_interpreter.getFileWatcher().getTrackedFiles()) + { + auto const& key = entry.first; + auto const& val = entry.second; + + if (filterSelected != -1 && (int)val.data != filterSelected) + continue; + + ImGui::Text("%d", index); ImGui::TableNextColumn(); - ImGui::TextUnformatted(file_name); + ImGui::TextUnformatted(key.substr(key.find_last_of("/\\") + 1).c_str()); + ShowToolTip(key.c_str()); ImGui::TableNextColumn(); - ImGui::TextUnformatted(file_type); + ImGui::TextUnformatted(EnumToString(val.data)); ImGui::TableNextRow(); ImGui::TableNextColumn(); + index++; } ImGui::EndTable(); } } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide Object Cache Details", &g_hideObjectCacheDetails); - - if (!g_hideObjectCacheDetails) + if (ImGui::CollapsingHeader("OBJ Cache")) { //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) static std::vector c_obj_cache_details_file_display; @@ -2327,10 +2389,7 @@ void ShowInternalVariables() } } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide FBX Cache Details", &g_hideFBXCacheDetails); - - if (!g_hideFBXCacheDetails) + if (ImGui::CollapsingHeader("FBX Cache")) { //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) static std::vector c_fbx_cache_details_file_display; @@ -2370,10 +2429,7 @@ void ShowInternalVariables() } } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide PLY Cache Details", &g_hidePLYCacheDetails); - - if (!g_hidePLYCacheDetails) + if (ImGui::CollapsingHeader("PLY Cache")) { //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) static std::vector c_ply_cache_details_file_display; @@ -2416,10 +2472,7 @@ void ShowInternalVariables() } } - ImGui::SeparatorText(""); - ImGui::Checkbox("Hide Texture Cache Details", &g_hideTextureCacheDetails); - - if (!g_hideTextureCacheDetails) + if (ImGui::CollapsingHeader("Texture Cache")) { //hold values as they don't change that often to reduce CPU usage when vieweing interpreter states (internal variables) static std::vector c_texture_cache_details_file_display; @@ -2530,6 +2583,7 @@ void ShowSystemVariables() ImGui::SeparatorText("Camera Variables"); ShowVariableDropDown("CameraPos", DataFieldType::Float3, g_systemVariables.CameraPos_varName); + ShowVariableDropDown("CameraAltitudeAzimuth", DataFieldType::Float2, g_systemVariables.CameraAltitudeAzimuth_varName); ShowVariableDropDown("Camera Changed", DataFieldType::Bool, g_systemVariables.CameraChanged_varName); ShowVariableDropDown("View Matrix", DataFieldType::Float4x4, g_systemVariables.ViewMtx_varName); @@ -2624,7 +2678,7 @@ void ShowShaders() std::sort(scopesSorted.begin(), scopesSorted.end()); // for each scope - for const std::string& scope: scopesSorted) + for (const std::string& scope: scopesSorted) { // get a sorted list of shaders in this scope std::vector sortedShaders; @@ -2780,101 +2834,6 @@ void ShowImportedResources() return; } - // Show imported resource preset drop down - { - std::vector presets; - for (const GGUserFile_ImportedResourcePreset& preset : g_importedResourcePresets) - presets.push_back(preset.name.c_str()); - - std::sort(presets.begin(), presets.end(), [](const char* A, const char* B) { return strcmp(A, B) < 0; }); - presets.insert(presets.begin(), "Presets"); - - float comboWidth = 0.0f; - for (const char* s : presets) - comboWidth = std::max(comboWidth, ImGui::CalcTextSize(s).x + ImGui::GetStyle().FramePadding.x * 2.0f); - - ImGui::SetNextItemWidth(comboWidth + ImGui::GetTextLineHeightWithSpacing() + 10); - int selectedIndex = 0; - if (ImGui::Combo("##Presets", &selectedIndex, presets.data(), (int)presets.size())) - { - selectedIndex--; - if (selectedIndex >= 0 && selectedIndex < presets.size()) - { - std::filesystem::path renderGraphDir = std::filesystem::path(g_renderGraphFileName).remove_filename(); - - // map the index from the alpha sorted list back to the unsorted list - for (size_t i = 0; i < g_importedResourcePresets.size(); ++i) - { - if (g_importedResourcePresets[i].name == presets[selectedIndex + 1]) - { - selectedIndex = (int)i; - break; - } - } - - // Set the preset name box - strcpy(g_importedResourcePresetsName, g_importedResourcePresets[selectedIndex].name.c_str()); - - // Load the preset - for (const GGUserFile_ImportedResource& preset : g_importedResourcePresets[selectedIndex].importedResources) - { - if (g_interpreter.m_importedResources.count(preset.nodeName) == 0) - continue; - - GigiInterpreterPreviewWindowDX12::ImportedResourceDesc& importedResource = g_interpreter.m_importedResources[preset.nodeName]; - - int nodeIndex = importedResource.nodeIndex; - int resourceIndex = importedResource.resourceIndex; - - importedResource = GGUserFile_ImportedResource_To_ImportedResourceDesc(preset, renderGraphDir); - importedResource.state = GigiInterpreterPreviewWindowDX12::ImportedResourceState::dirty; - - importedResource.nodeIndex = nodeIndex; - importedResource.resourceIndex = resourceIndex; - } - } - } - } - - // Preset name and save button - { - ImGui::InputText("##Preset", g_importedResourcePresetsName, _countof(g_importedResourcePresetsName)); - - ImGui::SameLine(); - if (ImGui::Button("Save")) - { - std::filesystem::path renderGraphDir = std::filesystem::path(g_renderGraphFileName).remove_filename(); - - // Find the index (by name) to over write, or make a new index for it - int index = 0; - while (index < g_importedResourcePresets.size() && _stricmp(g_importedResourcePresets[index].name.c_str(), g_importedResourcePresetsName)) - index++; - if (index == g_importedResourcePresets.size()) - g_importedResourcePresets.resize(index + 1); - GGUserFile_ImportedResourcePreset& preset = g_importedResourcePresets[index]; - - // save the data - preset.name = g_importedResourcePresetsName; - preset.importedResources.clear(); - for (auto& it : g_interpreter.m_importedResources) - preset.importedResources.push_back(ImportedResourceDesc_To_GGUserFile_ImportedResource(it.first, it.second, renderGraphDir)); - } - - ImGui::SameLine(); - if (ImGui::Button("Delete")) - { - g_importedResourcePresets.erase( - std::remove_if(g_importedResourcePresets.begin(), g_importedResourcePresets.end(), - [&](const GGUserFile_ImportedResourcePreset& preset) - { - return preset.name == g_importedResourcePresetsName; - } - ), - g_importedResourcePresets.end() - ); - } - } - // Put the imported resources into alphabetical order struct ImportedResourceInfo { @@ -3455,6 +3414,19 @@ void ShowLog() return; } + if (ImGui::Button("Copy")) + { + std::ostringstream text; + constexpr const char* msgType[3] = { "", "[Warning] ", "[Error] " }; + for (const auto& msg : g_log) + text << msgType[static_cast(msg.level)] << msg.msg.c_str() << "\n"; + + std::string textStr = text.str(); + + SetClipboardDataEx(CF_TEXT, (void*)textStr.c_str(), (DWORD)textStr.length() + 1); + } + + ImGui::SameLine(); if (ImGui::Button("Clear")) g_log.clear(); @@ -5145,68 +5117,143 @@ void ShowResourceView() return; } - if (!g_hideUI || g_bookmarks.size() > 1) // only show the bookmark drop down in hide ui mode if there is more than 1 book mark + // show snapshot drop down, even when UI is hidden, as that user may want to use it. { - // Show the bookmark drop down - { - // make a list of bookmarks for the drop down - std::vector bookmarks; - for (const GGUserFile_Bookmark& bookmark : g_bookmarks) - bookmarks.push_back(bookmark.name.c_str()); + std::vector snapshots; + for (const GGUserFileV2Snapshot& snapshot : g_userSnapshots) + snapshots.push_back(snapshot.name.c_str()); - // sort bookmarks alphabetically - std::sort(bookmarks.begin(), bookmarks.end(), [](const char* A, const char* B) { return strcmp(A, B) < 0; }); - bookmarks.insert(bookmarks.begin(), "Bookmarks"); + std::sort(snapshots.begin(), snapshots.end(), [](const char* A, const char* B) { return strcmp(A, B) < 0; }); - float comboWidth = 0.0f; - for (const char* s : bookmarks) - comboWidth = std::max(comboWidth, ImGui::CalcTextSize(s).x + ImGui::GetStyle().FramePadding.x * 2.0f); + float comboWidth = ImGui::CalcTextSize("Snapshots").x + ImGui::GetStyle().FramePadding.x * 2.0f; + ImGui::SetNextItemWidth(comboWidth + ImGui::GetTextLineHeightWithSpacing() + 10); - ImGui::SetNextItemWidth(comboWidth + ImGui::GetTextLineHeightWithSpacing() + 10); - int selected = 0; - if (ImGui::Combo("##Bookmarks", &selected, bookmarks.data(), (int)bookmarks.size())) + int deleteIndex = -1; + if (ImGui::BeginCombo("##Snapshots", "Snapshots", ImGuiComboFlags_HeightLargest)) + { + if (ImGui::BeginTable("snapshots", 2, ImGuiTableFlags_None)) { - int selectedBookmarkIndex = -1; - for (const GGUserFile_Bookmark& bookmark : g_bookmarks) + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); + + for (int snapShotNameIndex = 0; snapShotNameIndex < snapshots.size(); ++snapShotNameIndex) { - selectedBookmarkIndex++; - if (bookmark.name == bookmarks[selected]) - break; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + const char* snapshotName = snapshots[snapShotNameIndex]; + + ImGui::Text(snapshotName); + + ImGui::TableNextColumn(); + + ImGui::PushID(snapShotNameIndex); + + for (int i = 0; i < g_userSnapshots.size(); ++i) + { + if (!strcmp(g_userSnapshots[i].name.c_str(), snapshotName)) + { + ImGui::Checkbox("Vars", &g_userSnapshots[i].loadVars); + ImGui::SameLine(); + + ImGui::Checkbox("Camera", &g_userSnapshots[i].loadCamera); + ImGui::SameLine(); + + ImGui::Checkbox("Resources", &g_userSnapshots[i].loadResources); + ImGui::SameLine(); + + ImGui::Checkbox("View", &g_userSnapshots[i].loadView); + ImGui::SameLine(); + + break; + } + } + + if (ImGui::Button("Load")) + { + for (int i = 0; i < g_userSnapshots.size(); ++i) + { + if (!strcmp(g_userSnapshots[i].name.c_str(), snapshotName)) + { + if (g_userSnapshots[i].loadView) // make this work with the A/B button + g_resourceView.StoreLast(); + + ScatterSnapshotData(g_userSnapshots[i], true, g_userSnapshots[i].loadCamera, g_userSnapshots[i].loadView, g_userSnapshots[i].loadResources); + + if (g_userSnapshots[i].loadVars) + ScatterSnapshotVariables(g_userSnapshots[i]); + break; + } + } + } + + ImGui::SameLine(); + if (ImGui::Button("Save")) + { + for (int i = 0; i < g_userSnapshots.size(); ++i) + { + if (!strcmp(g_userSnapshots[i].name.c_str(), snapshotName)) + { + GatherSnapshotData(g_userSnapshots[i]); + break; + } + } + } + ImGui::SameLine(); + if (ImGui::Button("Delete")) + deleteIndex = snapShotNameIndex; + + ImGui::PopID(); } - bool found = false; - if (selectedBookmarkIndex >= 0) - for (int nodeIndex : renderGraph.flattenedNodeList) + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + static char newSnapshotName[512] = { 0 }; + ImGui::InputText("##NewSnapshot", newSnapshotName, _countof(newSnapshotName)); + ImGui::SameLine(); + if (ImGui::Button("Save") && newSnapshotName[0] != 0) { - g_interpreter.RuntimeNodeDataLambda( - renderGraph.nodes[nodeIndex], - [&](auto node, auto* runtimeData) + int existingIndex = -1; + for (int i = 0; i < g_userSnapshots.size(); ++i) + { + if (!strcmp(g_userSnapshots[i].name.c_str(), newSnapshotName)) { - int resourceIndex = -1; - for (const RuntimeTypes::ViewableResource& viewableResource : runtimeData->m_viewableResources) + existingIndex = i; + break; + } + } + + if (existingIndex == -1) + { + existingIndex = (int)g_userSnapshots.size(); + g_userSnapshots.resize(existingIndex + 1); + g_userSnapshots[existingIndex].name = newSnapshotName; + } + + GatherSnapshotData(g_userSnapshots[existingIndex]); + + newSnapshotName[0] = 0; + } + + ImGui::TableNextColumn(); + + ImGui::EndTable(); + + ImGui::EndCombo(); + + if (deleteIndex >= 0) + { + g_userSnapshots.erase( + std::remove_if(g_userSnapshots.begin(), g_userSnapshots.end(), + [&](const GGUserFileV2Snapshot& snapshot) { - resourceIndex++; - if (viewableResource.m_displayName == g_bookmarks[selectedBookmarkIndex].viewableResourceDisplayName) - { - found = true; - switch (viewableResource.m_type) - { - case RuntimeTypes::ViewableResource::Type::Texture2D: - case RuntimeTypes::ViewableResource::Type::Texture2DArray: - case RuntimeTypes::ViewableResource::Type::Texture3D: - case RuntimeTypes::ViewableResource::Type::TextureCube: g_resourceView.Texture(node.nodeIndex, resourceIndex, viewableResource.m_type); break; - case RuntimeTypes::ViewableResource::Type::ConstantBuffer: g_resourceView.ConstantBuffer(node.nodeIndex, resourceIndex); break; - case RuntimeTypes::ViewableResource::Type::Buffer: g_resourceView.Buffer(node.nodeIndex, resourceIndex); break; - } - } + return snapshot.name == snapshots[deleteIndex]; } - } + ), + g_userSnapshots.end() ); } - - // if the bookmark selected wasn't found, delete it - if (!found && selectedBookmarkIndex >= 0) - g_bookmarks.erase(g_bookmarks.begin() + selectedBookmarkIndex); } } } @@ -5236,55 +5283,6 @@ void ShowResourceView() res.m_wantsToBeReadBack = true; } - // Let the user edit the bookmark name of this resource - if (!g_hideUI) - { - char bookmarkName[1024]; - bookmarkName[0] = 0; - int existingBookmarkIndex = -1; - for (int bookmarkIndex = 0; bookmarkIndex < g_bookmarks.size(); ++bookmarkIndex) - { - const GGUserFile_Bookmark& bookmark = g_bookmarks[bookmarkIndex]; - - if (bookmark.viewableResourceDisplayName == res.m_displayName) - { - existingBookmarkIndex = bookmarkIndex; - strcpy(bookmarkName, bookmark.name.c_str()); - break; - } - } - - ImGui::SameLine(); - ImGui::SetNextItemWidth(200.0f); - if (ImGui::InputText("Bookmark", bookmarkName, 1024)) - { - // If there is a bookmark name - if (strlen(bookmarkName) > 0) - { - // Add a new bookmark if it doesn't already exist - if (existingBookmarkIndex == -1) - { - GGUserFile_Bookmark newBookmark; - newBookmark.name = bookmarkName; - newBookmark.viewableResourceDisplayName = res.m_displayName; - g_bookmarks.push_back(newBookmark); - } - // else update it - else - { - g_bookmarks[existingBookmarkIndex].name = bookmarkName; - } - } - // else there is not a bookmark name - else - { - // If there is a bookmark, we need to remove it - if (existingBookmarkIndex != -1) - g_bookmarks.erase(g_bookmarks.begin() + existingBookmarkIndex); - } - } - } - if (!g_hideUI) { ImGui::SameLine(); @@ -6863,6 +6861,40 @@ class Python : public PythonInterface return ret; } + void SetShaderAssertsLogging(bool set) override final + { + g_logCollectedShaderAsserts = set; + } + + int GetCollectedShaderAssertsCount() override final + { + return (int)g_interpreter.getCollectedShaderAsserts().size(); + } + + int GetShaderAssertFormatStrId(int i) override final + { + const auto& asserts = g_interpreter.getCollectedShaderAsserts(); + return (int)asserts[i].formatStringId; + } + + std::string GetShaderAssertFormatString(int i) override final + { + const auto& asserts = g_interpreter.getCollectedShaderAsserts(); + return asserts[i].fmt; + } + + std::string GetShaderAssertDisplayName(int i) override final + { + const auto& asserts = g_interpreter.getCollectedShaderAsserts(); + return asserts[i].displayName; + } + + std::string GetShaderAssertMsg(int i) override final + { + const auto& asserts = g_interpreter.getCollectedShaderAsserts(); + return asserts[i].msg; + } + int GGEnumValue(const char* enumName, const char* enumLabel) override final { const RenderGraph& renderGraph = g_interpreter.GetRenderGraph(); @@ -6987,7 +7019,7 @@ Python g_python; void RenderFrame(bool forceExecute) { - UpdateSystemVariables(); + SynchronizeSystemVariables(); // Start the Dear ImGui frame ImGui_ImplDX12_NewFrame(); @@ -7024,6 +7056,8 @@ void RenderFrame(bool forceExecute) g_pd3dCommandList->Reset(frameCtx->CommandAllocator, NULL); + std::vector assertsBuffers = g_interpreter.MarkShaderAssertsForReadback(); + // Run the Gigi technique if we should g_python.Tick(); g_interpreter.Tick(); @@ -7034,6 +7068,10 @@ void RenderFrame(bool forceExecute) g_techniqueFrameIndex++; } + g_interpreter.CollectShaderAsserts(assertsBuffers); + if (g_logCollectedShaderAsserts) + g_interpreter.LogCollectedShaderAsserts(); + D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; diff --git a/MakeCode_UnitTests_DX12.py b/MakeCode_UnitTests_DX12.py index a2c6ec54..5d74a4c3 100644 --- a/MakeCode_UnitTests_DX12.py +++ b/MakeCode_UnitTests_DX12.py @@ -22,6 +22,7 @@ "Data\\binaryTexF32", "Python\\GPUWrite", "Python\\profiling", + "ShaderAssert\\assertsTest", # Viewer Only - These make sure the viewer will make mips of imported textures when asked "Textures\\Mips_Imported_2D", diff --git a/README.md b/README.md index 320cc5a3..3b1a0531 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Created by Alan Wolfe **Contributors:** +Alexey Gladkov + Berk Emre Saribas Chris Lewin diff --git a/RenderGraph/Visitors.h b/RenderGraph/Visitors.h index 017daa31..848ae1f4 100644 --- a/RenderGraph/Visitors.h +++ b/RenderGraph/Visitors.h @@ -594,7 +594,9 @@ struct ReferenceFixupVisitor { ReferenceFixupVisitor(RenderGraph& renderGraph_) : renderGraph(renderGraph_) - { } + { + visitedNode.resize(renderGraph.nodes.size(), false); + } template bool Visit(TDATA& data, const std::string& path) @@ -847,6 +849,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Resource_Buffer& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + if (data.visibility == ResourceVisibility::Internal) return true; @@ -863,6 +869,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_ComputeShader& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + int connectionIndex = -1; Shader& shader = *data.shader.shader; for (NodePinConnection& connection : data.connections) @@ -915,6 +925,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_RayShader& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + // Remember that this render graph uses ray tracing! renderGraph.usesRaytracing = true; @@ -970,6 +984,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_SubGraph& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + for (int connectionIndex = 0; connectionIndex < (int)data.connections.size(); ++connectionIndex) { // set the source pin @@ -997,6 +1015,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_Barrier& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + for (int connectionIndex = 0; connectionIndex < (int)data.connections.size(); ++connectionIndex) { // set the source pin @@ -1024,6 +1046,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_CopyResource& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + Visit(data.source, path + ".source"); Visit(data.dest, path + ".dest"); return true; @@ -1031,6 +1057,10 @@ struct ReferenceFixupVisitor bool Visit(RenderGraphNode_Action_DrawCall& data, const std::string& path) { + if (visitedNode[data.nodeIndex]) + return true; + visitedNode[data.nodeIndex] = true; + int connectionIndex = -1; Shader* vertexShader = data.vertexShader.shader; Shader& pixelShader = *data.pixelShader.shader; @@ -1257,6 +1287,26 @@ struct ReferenceFixupVisitor return false; } + bool Visit(VariableReferenceConstOnly& data, const std::string& path) + { + if (data.name.empty()) + return true; + + for (size_t index = 0; index < renderGraph.variables.size(); ++index) + { + const Variable& variable = renderGraph.variables[index]; + + if (!_stricmp(data.name.c_str(), variable.name.c_str())) + { + data.variableIndex = (int)index; + return true; + } + } + + Assert(data.variableIndex != -1, "Could not find variable %s\nIn %s\n", data.name.c_str(), path.c_str()); + return false; + } + bool Visit(StructReference& data, const std::string& path) { if (data.name.empty()) @@ -1333,6 +1383,7 @@ struct ReferenceFixupVisitor } RenderGraph& renderGraph; + std::vector visitedNode; // Helpers int GetNodeIndexByName(const char* name) @@ -1851,6 +1902,12 @@ struct SanitizeVisitor return true; } + bool Visit(VariableReferenceConstOnly& data, const std::string& path) + { + Sanitize(data.name); + return true; + } + bool Visit(NodePinReference& data, const std::string& path) { Sanitize(data.node); @@ -1946,6 +2003,413 @@ struct SanitizeVisitor RenderGraph& renderGraph; }; +struct ShaderAssertsVisitor +{ + constexpr static std::string_view AssertUavSuffix = "__GigiAssertUAV"; + + ShaderAssertsVisitor(RenderGraph& renderGraph_) + :renderGraph(renderGraph_) + { } + + template + bool Visit(TDATA& data, const std::string& path) + { + return true; + } + + bool Visit(RenderGraphNode& node, const std::string& path) + { + std::vector shadersWithAsserts; + std::string actionNodeName; + + if (node._index == RenderGraphNode::c_index_actionComputeShader) + { + RenderGraphNode_Action_ComputeShader& shaderNode = node.actionComputeShader; + actionNodeName = shaderNode.name; + + if (!ProcessNodeShader(shaderNode.shader.shader, shadersWithAsserts, path)) + return false; + } + + if (node._index == RenderGraphNode::c_index_actionDrawCall) + { + RenderGraphNode_Action_DrawCall& shaderNode = node.actionDrawCall; + actionNodeName = shaderNode.name; + + if (!ProcessNodeShader(shaderNode.amplificationShader.shader, shadersWithAsserts, path)) + return false; + + if (!ProcessNodeShader(shaderNode.meshShader.shader, shadersWithAsserts, path)) + return false; + + if (!ProcessNodeShader(shaderNode.vertexShader.shader, shadersWithAsserts, path)) + return false; + + if (!ProcessNodeShader(shaderNode.pixelShader.shader, shadersWithAsserts, path)) + return false; + } + + if (!shadersWithAsserts.empty()) + { + const size_t currentNodeId = std::distance(renderGraph.nodes.data(), &node); + const StructReference& structRef = InsertAssertUAVStruct(); + + for (Shader* shader : shadersWithAsserts) + { + RenderGraphNode* newUAVBufNode = InsertAssertsUAVNode(*shader, actionNodeName, structRef); + if (!AddResourceReference(renderGraph.nodes[currentNodeId], shader, newUAVBufNode->resourceBuffer)) + return false; + } + } + + return true; + } + + bool ProcessNodeShader(Shader* shader, std::vector& shaderWithAssert, const std::string& path) + { + if (shader) + { + const auto [isValid, hasAsserts] = ProcessShader(*shader, path); + if (!isValid) + return false; + + if (hasAsserts) + shaderWithAssert.push_back(shader); + } + + return true; + } + + struct ShaderProcessResult + { + bool isValid = false; + bool hasAsserts = false; + }; + + struct ShaderParsingResult + { + bool isValid = false; + std::unordered_map uniqueAssertsCalls; + }; + + ShaderProcessResult ProcessShader(Shader& shader, const std::string& path) + { + auto [isValid, uniqueAssertsCalls] = ParseShader(shader, path); + if (!isValid) + return {}; + + const bool hasAsserts = !uniqueAssertsCalls.empty(); + if (hasAsserts) + InsertStringReplacements(shader, uniqueAssertsCalls); + + return { true, hasAsserts }; + } + + ShaderParsingResult ParseShader(Shader& shader, const std::string& path) + { + std::string fileName = (std::filesystem::path(renderGraph.baseDirectory) / shader.fileName).string(); + + std::vector fileContents; + if (!LoadFile(fileName, fileContents)) + { + Assert(false, "Could not load file %s\nIn %s\n", fileName.c_str(), path.c_str()); + return {}; + } + fileContents.push_back(0); + + auto BeginsWith = [](const char* haystack, const char* needle) -> bool + { + size_t needleLen = strlen(needle); + if (_strnicmp(haystack, needle, needleLen) != 0) + return false; + return true; + }; + + auto GetCondition = [](std::string_view& content) + { + const size_t commaPos = content.find_first_of(','); + const bool isLastArg = commaPos == content.npos; + + const size_t argLen = isLastArg + ? content.length() + : commaPos; + + std::string_view res = content.substr(0, argLen); + content = content.substr(argLen); + + return res; + }; + + auto GetFmt = [](std::string_view& content) + { + const size_t firstQuotaPos = content.find_first_of('"'); + + std::string_view res; + if (firstQuotaPos != content.npos) + { + const size_t lastQuotaPos = content.find_first_of('"', firstQuotaPos + 1); + const size_t substrLen = lastQuotaPos != content.npos ? lastQuotaPos - firstQuotaPos + 1 : content.npos; + + std::string_view res = content.substr(firstQuotaPos, substrLen); + content = content.substr(firstQuotaPos + substrLen); + + return res; + } + + return std::string_view{}; + }; + + auto GetFmtArgs = [](const std::string_view content) + { + const size_t commaPos = content.find(','); + if (commaPos != content.npos) + return content.substr(commaPos + 1); + + return std::string_view{}; + }; + + auto CountFmtArgs = [](const std::string_view fmt, const std::string_view args) + { + size_t requestedFmtArgsCount = 0; + for (const char ch : fmt) + if (ch == '%') + ++requestedFmtArgsCount; + + size_t providedFmtArgsCount = 0; + size_t hasChars = 0; + for (const char ch : args) + { + hasChars |= !!iswalnum(ch); + if (ch == ',') + ++providedFmtArgsCount; + } + providedFmtArgsCount += hasChars; + + return std::pair{ requestedFmtArgsCount, providedFmtArgsCount }; + }; + + auto AcquireFormatStringId = [this](const std::string_view fmtStr) + { + std::string str(fmtStr); + + const auto it = fmtStrToId.find(str); + if (it != fmtStrToId.end()) + return it->second; + + const size_t newId = renderGraph.assertsFormatStrings.size(); + renderGraph.assertsFormatStrings.push_back(str); + fmtStrToId.insert({ str, newId }); + + return newId; + }; + + bool hasValidDeclarations = true; + std::unordered_map uniqueAssertsCalls; + + ForEachToken((char*)fileContents.data(), + [&](const std::string& tokenStr, const char* stringStart, const char* cursor) + { + const auto declError = [&](const char* error) + { + ShowErrorMessage("'%s' has an invalid declaration, %s", tokenStr.c_str(), error); + hasValidDeclarations = false; + }; + + std::string_view token(tokenStr); + const std::string_view prefix("/*$(Assert:"); + const std::string_view suffix(")*/"); + + if (!BeginsWith(token.data(), prefix.data())) + return; + + std::string_view arguments = token.substr(prefix.length(), token.length() - prefix.length() - suffix.length()); + if (arguments.empty()) + { + declError("missed arguments"); + return; + } + + const std::string_view condition = GetCondition(arguments); + + if (condition.empty() || condition.find_first_of('"') != condition.npos) + { + declError("invalid condition"); + return; + } + + const std::string_view fmtStr = GetFmt(arguments); + if (!fmtStr.empty() && (fmtStr.back() != '"')) + { + declError("format string misses closing \""); + return; + } + + const std::string_view fmtArgs = !fmtStr.empty() ? GetFmtArgs(arguments) : ""; + const auto [requestedArgsCount, providedArgsCount] = CountFmtArgs(fmtStr, fmtArgs); + if (requestedArgsCount != providedArgsCount) + { + declError("invalid number of the format arguments"); + return; + } + + //store assert token to the function call replacement + { + std::string replValue = "__gigiAssert("; + replValue += condition; + + const std::string formatIdStr = std::to_string(AcquireFormatStringId(fmtStr.empty() ? condition : fmtStr)); + replValue += ", " + formatIdStr; + + if (!fmtStr.empty() && !fmtArgs.empty()) + { + replValue += ", "; + replValue += fmtArgs; + } + + replValue += ");"; + uniqueAssertsCalls.insert({ std::string(token), std::move(replValue) }); + } + }); + + return { hasValidDeclarations, std::move(uniqueAssertsCalls) }; + } + + std::string GetShaderAssertUAVName(const Shader shader) + { + return "__" + shader.name + AssertUavSuffix.data(); + } + + void InsertStringReplacements(Shader& shader, std::unordered_map& uniqueAssertsCalls) + { + for (const auto& [tokenName, tokenReplacement] : uniqueAssertsCalls) + { + TokenReplacement replacement; + replacement.name = tokenName; + replacement.value = tokenReplacement; + shader.tokenReplacements.push_back(std::move(replacement)); + } + + const std::string assertBufName = GetShaderAssertUAVName(shader); + + TokenReplacement replacement; + replacement.name = "/*$(ShaderResources)*/"; + replacement.value = + "\nvoid __gigiAssert(bool condition, uint fmtId," + "\n float v1 = 0, float v2 = 0, float v3 = 0," + "\n float v4 = 0, float v5 = 0, float v6 = 0)" + "\n{" + "\n if (!condition)" + "\n {" + "\n uint wasFired;" + "\n InterlockedExchange(" + assertBufName + "[0].isFired, 1, wasFired); " + "\n if (wasFired)" + "\n return;" + "\n" + "\n Struct_GigiAssert newAssert = (Struct_GigiAssert)0;" + "\n newAssert.isFired = 1;" + "\n newAssert.fmtId = fmtId;" + "\n newAssert.v1 = v1;" + "\n newAssert.v2 = v2;" + "\n newAssert.v3 = v3;" + "\n newAssert.v4 = v4;" + "\n newAssert.v5 = v5;" + "\n newAssert.v6 = v6;" + "\n " + assertBufName + "[0] = newAssert; " + "\n " + "\n }" + "\n}"; + shader.tokenReplacements.push_back(std::move(replacement)); + } + + const StructReference& InsertAssertUAVStruct() + { + if (assertStructRef.structIndex >= 0) + return assertStructRef; + + Struct assertStruct; + assertStruct.name = "GigiAssert"; + + auto makeStructField = [](const char* name, DataFieldType type) + { + StructField newField; + newField.name = name; + newField.type = type; + return newField; + }; + + assertStruct.fields.push_back(makeStructField("isFired", DataFieldType::Uint)); + assertStruct.fields.push_back(makeStructField("fmtId", DataFieldType::Uint)); + assertStruct.fields.push_back(makeStructField("v1", DataFieldType::Float)); + assertStruct.fields.push_back(makeStructField("v2", DataFieldType::Float)); + assertStruct.fields.push_back(makeStructField("v3", DataFieldType::Float)); + assertStruct.fields.push_back(makeStructField("v4", DataFieldType::Float)); + assertStruct.fields.push_back(makeStructField("v5", DataFieldType::Float)); + assertStruct.fields.push_back(makeStructField("v6", DataFieldType::Float)); + + assertStructRef.name = assertStruct.name; + assertStructRef.structIndex = (int)renderGraph.structs.size(); + + renderGraph.structs.push_back(std::move(assertStruct)); + + return assertStructRef; + } + + RenderGraphNode* InsertAssertsUAVNode(const Shader& shader, const std::string& actionNodeName, const StructReference& assertStructRef) + { + BufferFormatDesc format; + format.structureType = assertStructRef; + + BufferCountDesc countDesc; + countDesc.multiply = 1; + + RenderGraphNode newBufferNode; + newBufferNode._index = RenderGraphNode::c_index_resourceBuffer; + newBufferNode.resourceBuffer.visibility = ResourceVisibility::Internal; + newBufferNode.resourceBuffer.format = format; + newBufferNode.resourceBuffer.count = countDesc; + newBufferNode.resourceBuffer.transient = true; + newBufferNode.resourceBuffer.name = actionNodeName + "__GigiAssertUAV_" + shader.name; + newBufferNode.resourceBuffer.originalName = newBufferNode.resourceBuffer.name; + + renderGraph.nodes.push_back(newBufferNode); + + return &renderGraph.nodes.back(); + } + + bool AddResourceReference(RenderGraphNode& node, Shader* shader, RenderGraphNode_Resource_Buffer& resourceBuffer) + { + ShaderResource newResource; + newResource.name = GetShaderAssertUAVName(*shader); + newResource.type = ShaderResourceType::Buffer; + newResource.access = ShaderResourceAccessType::UAV; + newResource.buffer.typeStruct = resourceBuffer.format.structureType; + + NodePinConnection newConnection; + newConnection.srcPin = newResource.name; + newConnection.dstNode = resourceBuffer.name; + newConnection.dstPin = "resource"; + + shader->resources.push_back(std::move(newResource)); + + if (node._index == RenderGraphNode::c_index_actionComputeShader) + node.actionComputeShader.connections.push_back(std::move(newConnection)); + else if (node._index == RenderGraphNode::c_index_actionDrawCall) + node.actionDrawCall.connections.push_back(std::move(newConnection)); + else + { + ShowErrorMessage("Shaders Assert: failed to add node connection: unsupported node type '%d'", node._index); + return false; + } + + return true; + } + + RenderGraph& renderGraph; + + StructReference assertStructRef; + std::unordered_map fmtStrToId; +}; + struct ShaderDataVisitor { ShaderDataVisitor(RenderGraph& renderGraph_) @@ -2455,6 +2919,9 @@ struct ShaderDataVisitor for (const ShaderResource& resource : shader.resources) { + if (resource.name.find(ShaderAssertsVisitor::AssertUavSuffix) != std::string::npos) + continue; + if (fileContents.find(resource.name) == std::string::npos) { bool isLoadedTexture = false; @@ -2529,4 +2996,5 @@ struct ResolveBackendRestrictions } RenderGraph& renderGraph; -}; \ No newline at end of file +}; + diff --git a/Schemas/PreviewWindow/PreviewWindowSchemas.h b/Schemas/PreviewWindow/PreviewWindowSchemas.h index d8594feb..4dfaa024 100644 --- a/Schemas/PreviewWindow/PreviewWindowSchemas.h +++ b/Schemas/PreviewWindow/PreviewWindowSchemas.h @@ -152,6 +152,7 @@ STRUCT_BEGIN(GGUserFile_SystemVars, "") STRUCT_FIELD(std::string, JitteredViewProjMtx_varName, "JitteredViewProjMtx", "ViewProjMtx with jitter.", 0) STRUCT_FIELD(std::string, InvJitteredViewProjMtx_varName, "InvJitteredViewProjMtx", "Inverted ViewProjMtx with jitter.", 0) STRUCT_FIELD(std::string, CameraPos_varName, "CameraPos", "", 0) + STRUCT_FIELD(std::string, CameraAltitudeAzimuth_varName, "CameraAltitudeAzimuth", "", 0) STRUCT_FIELD(std::string, CameraChanged_varName, "CameraChanged", "", 0) STRUCT_FIELD(std::string, CameraJitter_varName, "CameraJitter", "", 0) STRUCT_FIELD(std::string, ShadingRateImageTileSize_varName, "ShadingRateImageTileSize", "", 0) @@ -163,25 +164,42 @@ STRUCT_BEGIN(GGUserFile_SavedVariable, "Saved Variable Values") STRUCT_FIELD(std::string, value, "", "", 0) STRUCT_END() -STRUCT_BEGIN(GGUserFile_Bookmark, "A bookmark for resources to show up in a short list, to be more quickly found.") - STRUCT_FIELD(std::string, name, "", "", 0) - STRUCT_FIELD(std::string, viewableResourceDisplayName, "", "", 0) -STRUCT_END() - -STRUCT_BEGIN(GGUserFile_ImportedResourcePreset, "A preset of imported resource settings") - STRUCT_FIELD(std::string, name, "", "", 0) +STRUCT_BEGIN(GGUserFileV1, "The contents of a .gguser file") + STRUCT_FIELD(std::string, version, "1.0", "The version of the .gguser file", SCHEMA_FLAG_SERIALIZE_DFLT) + STRUCT_FIELD(GGUserFile_SystemVars, systemVars, {}, "", 0) + STRUCT_FIELD(int, resourceViewType, 0, "The type of resource being viewed", 0) + STRUCT_FIELD(int, resourceViewNodeIndex, -1, "The index of the node bieng viewed", 0) + STRUCT_FIELD(int, resourceViewResourceIndex, -1, "The index of that resource within that node being used", 0) + STRUCT_FIELD(int, syncInterval, 1, "IDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.", 0) STRUCT_DYNAMIC_ARRAY(GGUserFile_ImportedResource, importedResources, "", 0) + STRUCT_DYNAMIC_ARRAY(GGUserFile_SavedVariable, savedVariables, "", 0) STRUCT_END() -STRUCT_BEGIN(GGUserFile, "The contents of a .gguser file") - STRUCT_FIELD(std::string, version, "1.0", "The version of the .gguser file", 0) - STRUCT_FIELD(GGUserFile_SystemVars, systemVars, {}, "", 0) +STRUCT_BEGIN(GGUserFileV2Snapshot, "The snapshot of a GGUserFileV2") + STRUCT_FIELD(std::string, name, "", "The snapshot name", 0) STRUCT_FIELD(int, resourceViewType, 0, "The type of resource being viewed", 0) STRUCT_FIELD(int, resourceViewNodeIndex, -1, "The index of the node bieng viewed", 0) STRUCT_FIELD(int, resourceViewResourceIndex, -1, "The index of that resource within that node being used", 0) - STRUCT_FIELD(int, syncInterval, true, "IDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.", 0) + + STRUCT_FIELD(bool, loadVars, true, "Whether variables will be loaded from this snapshot", 0) + STRUCT_FIELD(bool, loadCamera, true, "Whether the camera will be loaded from this snapshot", 0) + STRUCT_FIELD(bool, loadResources, true, "Whether imported resources will be loaded from this snapshot", 0) + STRUCT_FIELD(bool, loadView, true, "Whether the resource viewed will be loaded from this snapshot", 0) + + STRUCT_STATIC_ARRAY(float, cameraPos, 3, { 0.0f COMMA 0.0f COMMA - 10.0f }, "Used by snapshots to capture the camera position", 0) + STRUCT_STATIC_ARRAY(float, cameraAltitudeAzimuth, 2, { 0.0f COMMA 0.0f }, "Used by snapshots to capture the camera orientation", 0) STRUCT_DYNAMIC_ARRAY(GGUserFile_ImportedResource, importedResources, "", 0) STRUCT_DYNAMIC_ARRAY(GGUserFile_SavedVariable, savedVariables, "", 0) - STRUCT_DYNAMIC_ARRAY(GGUserFile_Bookmark, bookmarks, "", 0) - STRUCT_DYNAMIC_ARRAY(GGUserFile_ImportedResourcePreset, importedResourcePresets, "", 0) +STRUCT_END() + +STRUCT_BEGIN(GGUserFileV2, "The contents of a .gguser file") + STRUCT_FIELD(std::string, version, "2.0", "The version of the .gguser file", SCHEMA_FLAG_SERIALIZE_DFLT) + STRUCT_FIELD(int, syncInterval, 1, "IDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.", 0) + STRUCT_FIELD(GGUserFile_SystemVars, systemVars, {}, "", 0) + STRUCT_FIELD(GGUserFileV2Snapshot, snapshot, {}, "", 0) + STRUCT_DYNAMIC_ARRAY(GGUserFileV2Snapshot, snapshots, "", 0) +STRUCT_END() + +STRUCT_BEGIN(GGUserFileVersionOnly, "Only the version of the .gguser file") + STRUCT_FIELD(std::string, version, "1.0", "The version of the .gguser file", SCHEMA_FLAG_SERIALIZE_DFLT) STRUCT_END() diff --git a/Schemas/RenderGraphNodes.h b/Schemas/RenderGraphNodes.h index 23ccc0b3..04b2329d 100644 --- a/Schemas/RenderGraphNodes.h +++ b/Schemas/RenderGraphNodes.h @@ -231,6 +231,7 @@ STRUCT_BEGIN(SubGraphVariableSettings, "Cached data about a subgraph") STRUCT_FIELD(std::string, name, "", "variable name", SCHEMA_FLAG_UI_CONST) STRUCT_FIELD(VariableVisibility, visibility, VariableVisibility::Internal, "Who can see and interact with this variable", 0) STRUCT_FIELD(std::string, replaceWithStr, {}, "If set, the subgraph variable will be deleted and all references will use this parent graph variable instead.", 0) + STRUCT_FIELD(std::string, replaceWithValue, {}, "Replace the variable with a literal value. At gigi compile time it makes an internal private variable of the correct type with this string as the default value.", 0) STRUCT_FIELD(bool, isLoopIndex, false, "If true, this variable will recieve the loop index.", 0) // deprecated in 0.97b @@ -255,7 +256,7 @@ STRUCT_BEGIN(RenderGraphNode_Base, "The base type of all node types") STRUCT_FIELD(std::unordered_map, inputPinIds, {}, "", SCHEMA_FLAG_NO_UI | SCHEMA_FLAG_NO_SERIALIZE) STRUCT_FIELD(std::unordered_map, outputPinIds, {}, "", SCHEMA_FLAG_NO_UI | SCHEMA_FLAG_NO_SERIALIZE) - STRUCT_FIELD(int, nodeIndex, -1, "The index in the list of render graph nodes", SCHEMA_FLAG_NO_SERIALIZE) + STRUCT_FIELD(int, nodeIndex, -1, "The index in the list of render graph nodes. This is filled in after loading by the ReferenceFixupVisitor and is in [0,N) with no gaps.", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_FIELD(std::string, originalName, "", "The name before renames and sanitization", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_END() @@ -447,6 +448,8 @@ STRUCT_INHERIT_BEGIN(RenderGraphNode_Action_SubGraph, RenderGraphNode_ActionBase STRUCT_FIELD(int, loopCount, 1, "Number of times to execute the technique.", 0) + STRUCT_FIELD(VariableReferenceConstOnly, loopCountVariable, {}, "The variable to use for the loopCount. Only const variables supported currently.", 0) + STRUCT_FIELD(int, loopIndex, -1, "When unrolling subgraph loops, the loop index of the node is stored here.", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_END() diff --git a/Schemas/Schemas.h b/Schemas/Schemas.h index bcbe5ff3..c90dca63 100644 --- a/Schemas/Schemas.h +++ b/Schemas/Schemas.h @@ -17,6 +17,7 @@ ENUM_BEGIN(GigiCompileResult, "") ENUM_ITEM(WrongVersion, "") ENUM_ITEM(WrongParams, "") ENUM_ITEM(CantLoadRenderGraph, "") + ENUM_ITEM(ShaderAsserts, "") ENUM_ITEM(ShaderReflection, "") ENUM_ITEM(Validation, "") ENUM_ITEM(ReferenceFixup, "") @@ -118,6 +119,9 @@ ENUM_BEGIN(SetVariableOperator, "") ENUM_ITEM(PowerOf2GE, "The next power of two, greater or equal to the current value") + ENUM_ITEM(Minimum, "min(A,B)") + ENUM_ITEM(Maximum, "max(A,B)") + ENUM_ITEM(BitwiseOr, "A | B") ENUM_ITEM(BitwiseAnd, "A & B") ENUM_ITEM(BitwiseXor, "A ^ B") @@ -195,4 +199,7 @@ STRUCT_BEGIN(RenderGraph, "The root type of the render graph") STRUCT_FIELD(BackendTemplateConfig, templateConfig, {}, "Code generation template config", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_FIELD(bool, generateGraphVizFlag, false, "Set to true if the generating GraphViz. Should be set to true from a command line parameter", SCHEMA_FLAG_NO_SERIALIZE) + + STRUCT_FIELD(std::vector, assertsFormatStrings, {}, "The unique formatting strings of the asserts messages", SCHEMA_FLAG_NO_SERIALIZE) + STRUCT_FIELD(std::unordered_set, firedAssertsIdentifiers, {}, "The identifiers of the fired asserts to ignore them later on", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_END() diff --git a/Schemas/SchemasShaders.h b/Schemas/SchemasShaders.h index c45bb6d4..5a99cb2a 100644 --- a/Schemas/SchemasShaders.h +++ b/Schemas/SchemasShaders.h @@ -106,6 +106,12 @@ STRUCT_BEGIN(VariableReferenceNoConst, "A reference to a variable. No const vari STRUCT_FIELD(int, variableIndex, -1, "Calculated for convenience.", SCHEMA_FLAG_NO_SERIALIZE) STRUCT_END() +STRUCT_BEGIN(VariableReferenceConstOnly, "A reference to a variable. Only const variables allowed.") + STRUCT_FIELD(std::string, name, "", "The name of the variable.", 0) + + STRUCT_FIELD(int, variableIndex, -1, "Calculated for convenience.", SCHEMA_FLAG_NO_SERIALIZE) +STRUCT_END() + STRUCT_BEGIN(StructReference, "A reference to a struct") STRUCT_FIELD(std::string, name, "", "The name of the struct.", 0) @@ -292,6 +298,11 @@ STRUCT_BEGIN(ShaderDefine, "A shader define as part of shader compilation") STRUCT_FIELD(std::string, value, "", "The value of the define.", 0) STRUCT_END() +STRUCT_BEGIN(TokenReplacement, "A shader token replacement") + STRUCT_FIELD(std::string, name, "", "The token string.", 0) + STRUCT_FIELD(std::string, value, "", "The replacement.", 0) +STRUCT_END() + STRUCT_BEGIN(LoadedTextureReference, "Information about a loaded texture referenced by this shader.") STRUCT_FIELD(std::string, token, "", "The token as it appears in the shader.", 0) STRUCT_FIELD(std::string, resourceName, "", "The name of the resource to replace it with.", 0) @@ -331,6 +342,7 @@ STRUCT_BEGIN(Shader, "A declaration of a shader") STRUCT_FIELD(std::string, entryPoint, "", "The shader entrypoint.", 0) STRUCT_DYNAMIC_ARRAY(ShaderDefine, defines, "The defines the shader is compiled with.", SCHEMA_FLAG_UI_COLLAPSABLE | SCHEMA_FLAG_UI_ARRAY_FATITEMS) + STRUCT_DYNAMIC_ARRAY(TokenReplacement, tokenReplacements, "The token replacements specific for the shader.", SCHEMA_FLAG_NO_SERIALIZE) // deprecated in 0.95b // replaced by NumThreads diff --git a/Schemas/SchemasVariables.h b/Schemas/SchemasVariables.h index 2be18eb6..87d1c422 100644 --- a/Schemas/SchemasVariables.h +++ b/Schemas/SchemasVariables.h @@ -32,12 +32,13 @@ STRUCT_BEGIN(Variable, "A variable definition") STRUCT_FIELD(DataFieldType, type, DataFieldType::Count, "The type of the variable", 0) STRUCT_FIELD(bool, Const, false, "If true, the variable is declared const and cannot change at runtime", 0) STRUCT_FIELD(bool, Static, false, "If true, the variable has the same value for all instances of the technique", 0) - STRUCT_FIELD(std::string, dflt, "", "The default value of the variable", 0) + STRUCT_FIELD(std::string, dflt, "", "The default value of the variable. The default memory is zero initialized before this is parsed, so if you don't give it enough initializers, it will use zero for the unlisted fields.", 0) STRUCT_FIELD(VariableVisibility, visibility, VariableVisibility::Internal, "Who can see and interact with this variable", 0) STRUCT_FIELD(std::string, Enum, "", "Integer types can specify an enum, which will then make symbols in both C++ and shader code.", 0) STRUCT_FIELD(BackendRestriction, backends, {}, "This variable can be limited to specific backends", SCHEMA_FLAG_UI_COLLAPSABLE) STRUCT_FIELD(bool, transient, false, "If true, the variable should not be saved between runs of this technique. The Gigi viewer uses this to decide if it should save it in the gguser file or not, for example.", 0) STRUCT_FIELD(VariableUISettings, UISettings, {}, "UI Settings.", 0) + STRUCT_FIELD(std::string, UIGroup, "", "Used to organize variables into folders in the viewer. separate folders with dots. For instance: settings.controls", 0) STRUCT_FIELD(int, enumIndex, -1, "Calculated for convenience.", SCHEMA_FLAG_NO_SERIALIZE) diff --git a/Techniques/Denoising/SVGF/Atrous.gg b/Techniques/Denoising/SVGF/Atrous.gg new file mode 100644 index 00000000..94ddd105 --- /dev/null +++ b/Techniques/Denoising/SVGF/Atrous.gg @@ -0,0 +1,237 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "PhiColor", + "type": "Float", + "dflt": "10.0f" + }, + { + "name": "PhiNormal", + "type": "Float", + "dflt": "128.0f", + "visibility": "User" + }, + { + "name": "LoopIndex", + "type": "Int", + "visibility": "Host" + }, + { + "name": "FeedbackTap", + "type": "Int", + "dflt": "1", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "AtrousCS", + "fileName": "SVGFAtrous.ps.slang", + "entryPoint": "csmain", + "slangOptions": { + "process": true + }, + "resources": [ + { + "name": "gAlbedo", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gLinearZAndNormal", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gHistoryLength", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gIllumination", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "nodes": [ + { + "resourceTexture": { + "name": "Albedo", + "editorPos": [ + -21.0, + 18.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "LinearZAndNormal", + "editorPos": [ + -60.0, + 66.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "HistoryLength", + "editorPos": [ + -28.0, + 114.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "PingPongFbo_0", + "editorPos": [ + -33.0, + 162.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "PingPongFbo_1 ", + "editorPos": [ + -37.0, + 210.0 + ], + "visibility": "Imported" + } + }, + { + "actionComputeShader": { + "name": "Atrous", + "editorPos": [ + 233.0, + 66.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "gIllumination", + "dstNode": "PingPongFbo_0", + "dstPin": "resource" + }, + { + "srcPin": "gAlbedo", + "dstNode": "Albedo", + "dstPin": "resource" + }, + { + "srcPin": "gHistoryLength", + "dstNode": "HistoryLength", + "dstPin": "resource" + }, + { + "srcPin": "gLinearZAndNormal", + "dstNode": "LinearZAndNormal", + "dstPin": "resource" + }, + { + "srcPin": "Output", + "dstNode": "PingPongFbo_1 ", + "dstPin": "resource" + } + ], + "shader": { + "name": "AtrousCS" + }, + "dispatchSize": { + "node": { + "name": "Albedo" + } + } + } + }, + { + "actionSubGraph": { + "name": "Swap", + "editorPos": [ + 677.0, + 114.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "A", + "dstNode": "Atrous", + "dstPin": "gIllumination" + }, + { + "srcPin": "B", + "dstNode": "FeedbackTap", + "dstPin": "source" + } + ], + "fileName": "SwapTextures.gg", + "subGraphData": { + "importedResources": [ + "A", + "B" + ] + } + } + }, + { + "resourceTexture": { + "name": "FilteredPastFbo", + "editorPos": [ + 298.0, + 226.0 + ], + "visibility": "Imported" + } + }, + { + "actionCopyResource": { + "name": "FeedbackTap", + "editorPos": [ + 485.0, + 162.0 + ], + "condition": { + "variable1": "FeedbackTap", + "comparison": "Equals", + "variable2": "LoopIndex" + }, + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "Atrous", + "pin": "Output" + }, + "dest": { + "node": "FilteredPastFbo", + "pin": "resource" + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/Denoising/SVGF/ClearBuffersCS.hlsl b/Techniques/Denoising/SVGF/ClearBuffersCS.hlsl new file mode 100644 index 00000000..024782be --- /dev/null +++ b/Techniques/Denoising/SVGF/ClearBuffersCS.hlsl @@ -0,0 +1,19 @@ +// Unnamed technique, shader ClearBuffersCS +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + LinearZAndNormal[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PrevLinearZAndNormal[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + FilteredPastFbo[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PrevReprojFbo_0[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PrevReprojFbo_1[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PrevReprojFbo_2[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + CurReprojFbo_0[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + CurReprojFbo_1[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + CurReprojFbo_2[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PingPongFbo_0[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + PingPongFbo_1[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); + Final_Fbo[px] = float4(0.0f, 0.0f, 0.0f, 0.0f); +} diff --git a/Techniques/Denoising/SVGF/ColorHelpers.slang b/Techniques/Denoising/SVGF/ColorHelpers.slang new file mode 100644 index 00000000..a7b2c9f8 --- /dev/null +++ b/Techniques/Denoising/SVGF/ColorHelpers.slang @@ -0,0 +1,415 @@ +/*************************************************************************** + # Copyright (c) 2015-24, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ + +/** + * This file contains host/device shared color utility functions. + */ + +/** + * Returns a relative luminance of an input linear RGB color in the ITU-R BT.709 color space + * @param RGBColor linear HDR RGB color in the ITU-R BT.709 color space + */ +float luminance(float3 rgb) +{ + return dot(rgb, float3(0.2126f, 0.7152f, 0.0722f)); +} + +#ifndef HOST_CODE +// TODO: Unify this code with the host-side functions in ColorUtils.h when #175 is solved. +/** + * Transforms an RGB color in Rec.709 to CIE XYZ. + */ +float3 RGBtoXYZ_Rec709(float3 c) +{ + static const float3x3 M = { + // clang-format off + 0.4123907992659595, 0.3575843393838780, 0.1804807884018343, // row 0 + 0.2126390058715104, 0.7151686787677559, 0.0721923153607337, // row 1 + 0.0193308187155918, 0.1191947797946259, 0.9505321522496608, // row 2 + // clang-format off + }; + return mul(M, c); +} + +/** + * Transforms an XYZ color to RGB in Rec.709. + */ +float3 XYZtoRGB_Rec709(float3 c) +{ + static const float3x3 M = { + // clang-format off + 3.240969941904522, -1.537383177570094, -0.4986107602930032, // row 0 + -0.9692436362808803, 1.875967501507721, 0.04155505740717569, // row 1 + 0.05563007969699373, -0.2039769588889765, 1.056971514242878, // row 2 + // clang-format on + }; + return mul(M, c); +} +#endif + +/** + * Converts color from RGB to YCgCo space + * @param RGBColor linear HDR RGB color + */ +inline float3 RGBToYCgCo(float3 rgb) +{ + float Y = dot(rgb, float3(0.25f, 0.50f, 0.25f)); + float Cg = dot(rgb, float3(-0.25f, 0.50f, -0.25f)); + float Co = dot(rgb, float3(0.50f, 0.00f, -0.50f)); + return float3(Y, Cg, Co); +} + +/** + * Converts color from YCgCo to RGB space + * @param YCgCoColor linear HDR YCgCo color + */ +inline float3 YCgCoToRGB(float3 YCgCo) +{ + float tmp = YCgCo.x - YCgCo.y; + float r = tmp + YCgCo.z; + float g = YCgCo.x + YCgCo.y; + float b = tmp - YCgCo.z; + return float3(r, g, b); +} + +/** + * Returns a YUV version of an input linear RGB color in the ITU-R BT.709 color space + * @param RGBColor linear HDR RGB color in the ITU-R BT.709 color space + */ +inline float3 RGBToYUV(float3 rgb) +{ + float3 ret; + ret.x = dot(rgb, float3(0.2126f, 0.7152f, 0.0722f)); + ret.y = dot(rgb, float3(-0.09991f, -0.33609f, 0.436f)); + ret.z = dot(rgb, float3(0.615f, -0.55861f, -0.05639f)); + return ret; +} + +/** + * Returns a RGB version of an input linear YUV color in the ITU-R BT.709 color space + * @param YUVColor linear HDR YUV color in the ITU-R BT.709 color space + */ +inline float3 YUVToRGB(float3 yuv) +{ + float3 ret; + ret.x = dot(yuv, float3(1.0f, 0.0f, 1.28033f)); + ret.y = dot(yuv, float3(1.0f, -0.21482f, -0.38059f)); + ret.z = dot(yuv, float3(1.0f, 2.12798f, 0.0f)); + return ret; +} + +/** + * Returns a linear-space RGB version of an input RGB channel value in the ITU-R BT.709 color space + * @param sRGBColor sRGB input channel value + */ +inline float sRGBToLinear(float srgb) +{ + if (srgb <= 0.04045f) + { + return srgb * (1.0f / 12.92f); + } + else + { + return pow((srgb + 0.055f) * (1.0f / 1.055f), 2.4f); + } +} + +/** + * Returns a linear-space RGB version of an input RGB color in the ITU-R BT.709 color space + * @param sRGBColor sRGB input color + */ +inline float3 sRGBToLinear(float3 srgb) +{ + return float3(sRGBToLinear(srgb.x), sRGBToLinear(srgb.y), sRGBToLinear(srgb.z)); +} + +/** + * Returns a sRGB version of an input linear RGB channel value in the ITU-R BT.709 color space + * @param LinearColor linear input channel value + */ +inline float linearToSRGB(float lin) +{ + if (lin <= 0.0031308f) + { + return lin * 12.92f; + } + else + { + return pow(lin, (1.0f / 2.4f)) * (1.055f) - 0.055f; + } +} + +/** + * Returns a sRGB version of an input linear RGB color in the ITU-R BT.709 color space + * @param LinearColor linear input color + */ +inline float3 linearToSRGB(float3 lin) +{ + return float3(linearToSRGB(lin.x), linearToSRGB(lin.y), linearToSRGB(lin.z)); +} + +/** + * Returns Michelson contrast given minimum and maximum intensities of an image region + * @param iMin minimum intensity of an image region + * @param iMax maximum intensity of an image region + */ +inline float computeMichelsonContrast(float iMin, float iMax) +{ + if (iMin == 0.0f && iMax == 0.0f) + return 0.0f; + else + return (iMax - iMin) / (iMax + iMin); +} + +static const float3 kD65ReferenceIlluminant = float3(0.950428545, 1.000000000, 1.088900371); +static const float3 kInvD65ReferenceIlluminant = float3(1.052156925, 1.000000000, 0.918357670); + +#ifndef HOST_CODE +[BackwardDifferentiable] +#endif +inline float3 linearRGBToXYZ(float3 linColor) +{ + // Source: https://www.image-engineering.de/library/technotes/958-how-to-convert-between-srgb-and-ciexyz + // Assumes D65 standard illuminant. + const float a11 = 10135552.0f / 24577794.0f; + const float a12 = 8788810.0f / 24577794.0f; + const float a13 = 4435075.0f / 24577794.0f; + const float a21 = 2613072.0f / 12288897.0f; + const float a22 = 8788810.0f / 12288897.0f; + const float a23 = 887015.0f / 12288897.0f; + const float a31 = 1425312.0f / 73733382.0f; + const float a32 = 8788810.0f / 73733382.0f; + const float a33 = 70074185.0f / 73733382.0f; + + float3 xyzColor; + xyzColor.r = a11 * linColor.r + a12 * linColor.g + a13 * linColor.b; + xyzColor.g = a21 * linColor.r + a22 * linColor.g + a23 * linColor.b; + xyzColor.b = a31 * linColor.r + a32 * linColor.g + a33 * linColor.b; + + return xyzColor; +} + +#ifndef HOST_CODE +[BackwardDifferentiable] +#endif +inline float3 XYZToLinearRGB(float3 xyzColor) +{ + // Return values in linear RGB, assuming D65 standard illuminant. + const float a11 = 3.241003275f; + const float a12 = -1.537398934f; + const float a13 = -0.498615861f; + const float a21 = -0.969224334f; + const float a22 = 1.875930071f; + const float a23 = 0.041554224f; + const float a31 = 0.055639423f; + const float a32 = -0.204011202f; + const float a33 = 1.057148933f; + + float3 linColor; + linColor.r = a11 * xyzColor.r + a12 * xyzColor.g + a13 * xyzColor.b; + linColor.g = a21 * xyzColor.r + a22 * xyzColor.g + a23 * xyzColor.b; + linColor.b = a31 * xyzColor.r + a32 * xyzColor.g + a33 * xyzColor.b; + + return linColor; +} + +#ifndef HOST_CODE + +[BackwardDifferentiable] +float actualPow(float x, float y) +{ + if (x >= 0.f) + return pow(x, y); + else + return -pow(-x, y); +} + +[BackwardDifferentiable] +float3 actualPow(float3 in, float y) +{ + return float3(actualPow(in.x, y), actualPow(in.y, y), actualPow(in.z, y)); +} + +[BackwardDifferentiable] +inline float3 XYZToOklab(float3 xyzColor) +{ + static const float3x3 M1 = { + 0.8189330101f, + 0.3618667424f, + -0.1288597137f, + 0.0329845436f, + 0.9293118715f, + 0.0361456387f, + 0.0482003018f, + 0.2643662691f, + 0.6338517070f + }; + float3 lms = mul(M1, xyzColor); + lms = actualPow(lms, 1.f / 3.f); + static const float3x3 M2 = { + 0.2104542553f, + 0.7936177850f, + -0.0040720468f, + 1.9779984951f, + -2.4285922050f, + 0.4505937099f, + 0.0259040371f, + 0.7827717662f, + -0.8086757660f + }; + return mul(M2, lms); +} + +[BackwardDifferentiable] +inline float3 OklabToXYZ(float3 oklabColor) +{ + float3x3 M2inv = + float3x3(1.00000000f, 0.39633779f, 0.21580376f, 1.00000001f, -0.10556134f, -0.06385417f, 1.00000005f, -0.08948418f, -1.29148554f); + float3 lms = mul(M2inv, oklabColor); + lms = lms * lms * lms; + float3x3 M1inv = + float3x3(1.22701385f, -0.55779998f, 0.28125615f, -0.04058018f, 1.11225687f, -0.07167668f, -0.07638128f, -0.42148198f, 1.58616322f); + return mul(M1inv, lms); +} + +[BackwardDifferentiable] +inline float3 OklabToHCL(float3 oklabColor) +{ + float L = oklabColor.x; + float a = oklabColor.y; + float b = oklabColor.z; + + float H = atan2(b, a); + float C = sqrt(a * a + b * b); + return float3(H, C, L); +} + +[BackwardDifferentiable] +inline float3 HCLToOklab(float3 hclColor) +{ + float H = hclColor.x; + float C = hclColor.y; + float L = hclColor.z; + + float a = C * cos(H); + float b = C * sin(H); + return float3(L, a, b); +} + +[BackwardDifferentiable] +inline float3 RGBToOklab(float3 lColor) +{ + return XYZToOklab(linearRGBToXYZ(lColor)); +} + +[BackwardDifferentiable] +inline float3 OklabToRGB(float3 lab) +{ + return XYZToLinearRGB(OklabToXYZ(lab)); +} + +#endif + +inline float3 XYZToCIELab(float3 xyzColor, const float3 invReferenceIlluminant = kInvD65ReferenceIlluminant) +{ + // The default illuminant is D65. + float3 tmpColor = xyzColor * invReferenceIlluminant; + + float delta = 6.0f / 29.0f; + float deltaSquare = delta * delta; + float deltaCube = delta * deltaSquare; + float factor = 1.0f / (3.0f * deltaSquare); + float term = 4.0f / 29.0f; + + tmpColor.r = (tmpColor.r > deltaCube ? pow(tmpColor.r, 1.0f / 3.0f) : factor * tmpColor.r + term); + tmpColor.g = (tmpColor.g > deltaCube ? pow(tmpColor.g, 1.0f / 3.0f) : factor * tmpColor.g + term); + tmpColor.b = (tmpColor.b > deltaCube ? pow(tmpColor.b, 1.0f / 3.0f) : factor * tmpColor.b + term); + + float3 labColor; + labColor.r = 116.0f * tmpColor.g - 16.0f; + labColor.g = 500.0f * (tmpColor.r - tmpColor.g); + labColor.b = 200.0f * (tmpColor.g - tmpColor.b); + + return labColor; +} + +inline float3 CIELabToXYZ(float3 labColor, const float3 referenceIlluminant = kD65ReferenceIlluminant) +{ + // The default illuminant is D65. + float Y = (labColor.r + 16.0f) / 116.0f; + float X = labColor.g / 500.0f + Y; + float Z = Y - labColor.b / 200.0f; + + float delta = 6.0f / 29.0f; + float factor = 3.0f * delta * delta; + float term = 4.0f / 29.0f; + X = ((X > delta) ? X * X * X : (X - term) * factor); + Y = ((Y > delta) ? Y * Y * Y : (Y - term) * factor); + Z = ((Z > delta) ? Z * Z * Z : (Z - term) * factor); + + return float3(X, Y, Z) * referenceIlluminant; +} + +inline float3 XYZToYCxCz(float3 xyzColor, const float3 invReferenceIlluminant = kInvD65ReferenceIlluminant) +{ + // The default illuminant is D65. + float3 tmpColor = xyzColor * invReferenceIlluminant; + + float3 ycxczColor; + ycxczColor.x = 116.0f * tmpColor.g - 16.0f; + ycxczColor.y = 500.0f * (tmpColor.r - tmpColor.g); + ycxczColor.z = 200.0f * (tmpColor.g - tmpColor.b); + + return ycxczColor; +} + +inline float3 YCxCzToXYZ(float3 ycxczColor, const float3 referenceIlluminant = kD65ReferenceIlluminant) +{ + // The default illuminant is D65. + float Y = (ycxczColor.r + 16.0f) / 116.0f; + float X = ycxczColor.g / 500.0f + Y; + float Z = Y - ycxczColor.b / 200.0f; + + return float3(X, Y, Z) * referenceIlluminant; +} + +inline float3 linearRGBToCIELab(float3 lColor) +{ + return XYZToCIELab(linearRGBToXYZ(lColor)); +} + +inline float3 YCxCzToLinearRGB(float3 ycxczColor) +{ + return XYZToLinearRGB(YCxCzToXYZ(ycxczColor)); +} + +inline float3 linearRGBToYCxCz(float3 lColor) +{ + return XYZToYCxCz(linearRGBToXYZ(lColor)); +} + diff --git a/Techniques/Denoising/SVGF/LICENSE.md b/Techniques/Denoising/SVGF/LICENSE.md new file mode 100644 index 00000000..af9caafb --- /dev/null +++ b/Techniques/Denoising/SVGF/LICENSE.md @@ -0,0 +1,26 @@ +Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of NVIDIA CORPORATION nor the names of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +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. + +--- + +This software links to the following components which are not licensed under the above license text. +For details on the specific licenses please refer to the provided links. + +- DLSS: https://github.com/NVIDIA/DLSS/blob/main/LICENSE.txt +- RTXGI: https://github.com/NVIDIAGameWorks/RTXGI/blob/main/License.txt +- RTXDI: https://github.com/NVIDIAGameWorks/RTXDI/blob/main/LICENSE.txt +- NRD: https://github.com/NVIDIAGameWorks/RayTracingDenoiser/blob/master/LICENSE.txt diff --git a/Techniques/Denoising/SVGF/MathConstants.slangh b/Techniques/Denoising/SVGF/MathConstants.slangh new file mode 100644 index 00000000..fb9d5aa1 --- /dev/null +++ b/Techniques/Denoising/SVGF/MathConstants.slangh @@ -0,0 +1,130 @@ +/*************************************************************************** + # Copyright (c) 2015-24, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +#pragma once +//#include "Utils/HostDeviceShared.slangh" + +/** + * This file contains useful numeric constants for use on the GPU. + * + * It should be included with #include rather than import, as imported files + * do not export macro definitions. + * + * Note the possible differences between declaring constants using static + * float vs macro definitions. The compiler may treat these differently with + * respect to what precision is used for compile-time constant propagation. + * Slang currently uses fp32 for constant propagation. We get higher + * precision using the pre-evaluated constants below. Ideally, all + * compile-time constants should be evaluated at fp64 or higher precision. + */ + +#ifdef HOST_CODE +// @skallweit: We should use a different way to make math constants available on the host. +#include +#include +#include + +#else + +// clang-format off + +// Constants from +#define M_E 2.71828182845904523536 // e +#define M_LOG2E 1.44269504088896340736 // log2(e) +#define M_LOG10E 0.434294481903251827651 // log10(e) +#define M_LN2 0.693147180559945309417 // ln(2) +#define M_LN10 2.30258509299404568402 // ln(10) +#define M_PI 3.14159265358979323846 // pi +#define M_PI_2 1.57079632679489661923 // pi/2 +#define M_PI_4 0.785398163397448309616 // pi/4 +#define M_1_PI 0.318309886183790671538 // 1/pi +#define M_2_PI 0.636619772367581343076 // 2/pi +#define M_1_SQRTPI 0.564189583547756279280 // 1/sqrt(pi) +#define M_2_SQRTPI 1.12837916709551257390 // 2/sqrt(pi) +#define M_SQRT2 1.41421356237309504880 // sqrt(2) +#define M_SQRT1_2 0.707106781186547524401 // 1/sqrt(2) + +// Numeric limits from +#define UINT32_MAX 4294967295 +#define INT32_MIN -2147483648 +#define INT32_MAX 2147483647 + +// Numeric limits from +#define DBL_DECIMAL_DIG 17 // # of decimal digits of rounding precision +#define DBL_DIG 15 // # of decimal digits of precision +#define DBL_EPSILON 2.2204460492503131e-016 // smallest such that 1.0+DBL_EPSILON != 1.0 +#define DBL_HAS_SUBNORM 1 // type does support subnormal numbers +#define DBL_MANT_DIG 53 // # of bits in mantissa +#define DBL_MAX 1.7976931348623158e+308 // max value +#define DBL_MAX_10_EXP 308 // max decimal exponent +#define DBL_MAX_EXP 1024 // max binary exponent +#define DBL_MIN 2.2250738585072014e-308 // min positive value +#define DBL_MIN_10_EXP (-307) // min decimal exponent +#define DBL_MIN_EXP (-1021) // min binary exponent +#define DBL_RADIX 2 // exponent radix +#define DBL_TRUE_MIN 4.9406564584124654e-324 // min positive value + +#define FLT_DECIMAL_DIG 9 // # of decimal digits of rounding precision +#define FLT_DIG 6 // # of decimal digits of precision +#define FLT_EPSILON 1.192092896e-07F // smallest such that 1.0+FLT_EPSILON != 1.0 +#define FLT_HAS_SUBNORM 1 // type does support subnormal numbers +#define FLT_GUARD 0 +#define FLT_MANT_DIG 24 // # of bits in mantissa +#define FLT_MAX 3.402823466e+38F // max value +#define FLT_MAX_10_EXP 38 // max decimal exponent +#define FLT_MAX_EXP 128 // max binary exponent +#define FLT_MIN 1.175494351e-38F // min normalized positive value +#define FLT_MIN_10_EXP (-37) // min decimal exponent +#define FLT_MIN_EXP (-125) // min binary exponent +#define FLT_NORMALIZE 0 +#define FLT_RADIX 2 // exponent radix +#define FLT_TRUE_MIN 1.401298464e-45F // min positive value + +#endif // !HOST_CODE + +// Additional constants +#define M_2PI 6.28318530717958647693 // 2pi +#define M_4PI 12.5663706143591729539 // 4pi +#define M_4_PI 1.27323954473516268615 // 4/pi +#define M_1_2PI 0.159154943091895335769 // 1/2pi +#define M_1_4PI 0.079577471545947667884 // 1/4pi +#define M_SQRT3 1.732050807568877293527 // sqrt(3) +#define M_SQRTPI 1.77245385090551602730 // sqrt(pi) +#define M_1_SQRT2 0.707106781186547524401 // 1/sqrt(2) + +// Numeric limits for half (IEEE754 binary16) +#define HLF_EPSILON 9.765625e-04F // smallest such that 1.0+HLF_EPSILON != 1.0 +#define HLF_HAS_SUBNORM 1 // type does support subnormal numbers +#define HLF_MANT_DIG 11 +#define HLF_MAX 6.5504e+4F // max value +#define HLF_MAX_EXP 16 // max binary exponent +#define HLF_MIN 6.097555160522461e-05F // min normalized positive value +#define HLF_MIN_EXP (-14) // min binary exponent +#define HLF_RADIX 2 +#define HLF_TRUE_MIN 5.960464477539063e-08F // min positive value + +// clang-format on diff --git a/Techniques/Denoising/SVGF/MathHelpers.slang b/Techniques/Denoising/SVGF/MathHelpers.slang new file mode 100644 index 00000000..3ef0964c --- /dev/null +++ b/Techniques/Denoising/SVGF/MathHelpers.slang @@ -0,0 +1,771 @@ +/*************************************************************************** + # Copyright (c) 2015-24, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ + +/** + * This file contains various math utility helper functions. + * + * Included functionality (in order): + * + * - Sherical coordinates mapping functions + * - Octahedral mapping functions + * - Sampling functions (disk, sphere, triangle etc.) + * - Misc stuff (matrix inversion, bounding cones etc.) + * + */ + +// Include math constants (M_PI etc.). These are for use in this file only, +// as macro definitions are not exported from a Slang module. +#include "MathConstants.slangh" + +/****************************************************************************** + + Spherical coordinates + + Functions for converting Cartesian coordinates to spherical coordinates + using standard mathematical notations. + + The latitude-longitude map uses (phi,theta) as positions in two dimensions. + Its using using other conventions to orient and wrap the map the same way + as in common 3D software (e.g. Autodesk Maya). + +******************************************************************************/ + +/** + * Converts Cartesian coordinates to spherical coordinates (unsigned normalized). + * 'theta' is the polar angle (inclination) between the +z axis and the vector from origin to p, normalized to [0,1]. + * 'phi' is the azimuthal angle from the +x axis in the xy-plane, normalized to [0,1]. + * @param[in] p Cartesian coordinates (x,y,z). + * @return Spherical coordinates (theta,phi). + */ +float2 cartesian_to_spherical_unorm(float3 p) +{ + p = normalize(p); + float2 sph; + sph.x = acos(p.z) * M_1_PI; + sph.y = atan2(-p.y, -p.x) * M_1_2PI + 0.5f; + return sph; +} + +/** + * Converts Cartesian coordinates to spherical coordinates (radians). + * 'theta' is the polar angle (inclination) between the +z axis and the vector from origin to p, in the range [0,pi]. + * 'phi' is the azimuthal angle from the +x axis in the xy-plane, in the range [0,2pi]. + * @param[in] p Cartesian coordinates (x,y,z). + * @return Spherical coordinates (theta,phi). + */ +float2 cartesian_to_spherical_rad(float3 p) +{ + p = normalize(p); + float2 sph; + sph.x = acos(p.z); + sph.y = atan2(-p.y, -p.x) + M_PI; + return sph; +} + +/** + * Converts spherical coordinates (radians) to Cartesian coordinates. + * Inverse of cartesian_to_spherical_rad. + * @param[in] sph Spherical coordinates (theta,phi). + * @return Cartesian coordinates (x,y,z). + */ +float3 spherical_to_cartesian_rad(float2 sph) +{ + float3 p; + p.x = -cos(sph.y - M_PI) * sin(sph.x); + p.y = -sin(sph.y - M_PI) * sin(sph.x); + p.z = cos(sph.x); + return p; +} + +/** + * Convert world space direction to (u,v) coord in latitude-longitude map (unsigned normalized). + * The map is centered around the -z axis and wrapping around in clockwise order (left to right). + * @param[in] dir World space direction (unnormalized). + * @return Position in latitude-longitude map in [0,1] for each component. + */ +float2 world_to_latlong_map(float3 dir) +{ + float3 p = normalize(dir); + float2 uv; + uv.x = atan2(p.x, -p.z) * M_1_2PI + 0.5f; + uv.y = acos(p.y) * M_1_PI; + return uv; +} + +/** + * Convert a coordinate in latitude-longitude map (unsigned normalized) to a world space direction. + * The map is centered around the -z axis and wrapping around in clockwise order (left to right). + * @param[in] latlong Position in latitude-longitude map in [0,1] for each component. + * @return Normalized direction in world space. + */ +float3 latlong_map_to_world(float2 latlong) +{ + float phi = M_PI * (2.f * saturate(latlong.x) - 1.f); + float theta = M_PI * saturate(latlong.y); + float sinTheta = sin(theta); + float cosTheta = cos(theta); + float sinPhi = sin(phi); + float cosPhi = cos(phi); + return float3(sinTheta * sinPhi, cosTheta, -sinTheta * cosPhi); +} + +/****************************************************************************** + + Octahedral mapping + + The center of the map represents the +z axis and its corners -z. + The rotated inner square is the xy-plane projected onto the upper hemi- + sphere, the outer four triangles folds down over the lower hemisphere. + There are versions for equal-area and non-equal area (slightly faster). + + For details refer to: + - Clarberg 2008, "Fast Equal-Area Mapping of the (Hemi)Sphere using SIMD". + - Cigolle et al. 2014, "Survey of Efficient Representations for Independent Unit Vectors". + +******************************************************************************/ + +/** + * Helper function to reflect the folds of the lower hemisphere + * over the diagonals in the octahedral map. + */ +float2 oct_wrap(float2 v) +{ + return (1.f - abs(v.yx)) * select(v.xy >= 0.f, 1.f, -1.f); +} + +/** + * Converts normalized direction to the octahedral map (non-equal area, signed normalized). + * @param[in] n Normalized direction. + * @return Position in octahedral map in [-1,1] for each component. + */ +float2 ndir_to_oct_snorm(float3 n) +{ + // Project the sphere onto the octahedron (|x|+|y|+|z| = 1) and then onto the xy-plane. + float2 p = n.xy * (1.f / (abs(n.x) + abs(n.y) + abs(n.z))); + p = (n.z < 0.f) ? oct_wrap(p) : p; + return p; +} + +/** + * Converts normalized direction to the octahedral map (non-equal area, unsigned normalized). + * @param[in] n Normalized direction. + * @return Position in octahedral map in [0,1] for each component. + */ +float2 ndir_to_oct_unorm(float3 n) +{ + return ndir_to_oct_snorm(n) * 0.5f + 0.5f; +} + +/** + * Converts point in the octahedral map to normalized direction (non-equal area, signed normalized). + * @param[in] p Position in octahedral map in [-1,1] for each component. + * @return Normalized direction. + */ +float3 oct_to_ndir_snorm(float2 p) +{ + float3 n = float3(p.xy, 1.0 - abs(p.x) - abs(p.y)); + n.xy = (n.z < 0.0) ? oct_wrap(n.xy) : n.xy; + return normalize(n); +} + +/** + * Converts point in the octahedral map to normalized direction (non-equal area, unsigned normalized). + * @param[in] p Position in octahedral map in [0,1] for each component. + * @return Normalized direction. + */ +float3 oct_to_ndir_unorm(float2 p) +{ + return oct_to_ndir_snorm(p * 2.f - 1.f); +} + +/** + * Converts normalized direction to the octahedral map (equal-area, unsigned normalized). + * @param[in] n Normalized direction. + * @return Position in octahedral map in [0,1] for each component. + */ +float2 ndir_to_oct_equal_area_unorm(float3 n) +{ + // Use atan2 to avoid explicit div-by-zero check in atan(y/x). + float r = sqrt(1.f - abs(n.z)); + float phi = atan2(abs(n.y), abs(n.x)); + + // Compute p = (u,v) in the first quadrant. + float2 p; + p.y = r * phi * M_2_PI; + p.x = r - p.y; + + // Reflect p over the diagonals, and move to the correct quadrant. + if (n.z < 0.f) + p = 1.f - p.yx; + p *= sign(n.xy); + + return p * 0.5f + 0.5f; +} + +/** + * Converts point in the octahedral map to normalized direction (equal area, unsigned normalized). + * @param[in] p Position in octahedral map in [0,1] for each component. + * @return Normalized direction. + */ +float3 oct_to_ndir_equal_area_unorm(float2 p) +{ + p = p * 2.f - 1.f; + + // Compute radius r without branching. The radius r=0 at +z (center) and at -z (corners). + float d = 1.f - (abs(p.x) + abs(p.y)); + float r = 1.f - abs(d); + + // Compute phi in [0,pi/2] (first quadrant) and sin/cos without branching. + // TODO: Analyze fp32 precision, do we need a small epsilon instead of 0.0 here? + float phi = (r > 0.f) ? ((abs(p.y) - abs(p.x)) / r + 1.f) * M_PI_4 : 0.f; + + // Convert to Cartesian coordinates. Note that sign(x)=0 for x=0, but that's fine here. + float f = r * sqrt(2.f - r * r); + float x = f * sign(p.x) * cos(phi); + float y = f * sign(p.y) * sin(phi); + float z = sign(d) * (1.f - r * r); + + return float3(x, y, z); +} + +/****************************************************************************** + + Sampling functions + +******************************************************************************/ + +/** + * Uniform sampling of the unit disk using polar coordinates. + * @param[in] u Uniform random number in [0,1)^2. + * @return Sampled point on the unit disk. + */ +float2 sample_disk(float2 u) +{ + float2 p; + float r = sqrt(u.x); + float phi = M_2PI * u.y; + p.x = r * cos(phi); + p.y = r * sin(phi); + return p; +} + +/** + * Uniform sampling of direction within a cone + * @param[in] u Uniform random number in [0,1)^2. + * @param[in] cosTheta Cosine of the cone half-angle + * @return Sampled direction within the cone with (0,0,1) axis + */ +float3 sample_cone(float2 u, float cosTheta) +{ + float z = u.x * (1.f - cosTheta) + cosTheta; + float r = sqrt(1.f - z * z); + float phi = M_2PI * u.y; + return float3(r * cos(phi), r * sin(phi), z); +} + +/** + * Uniform sampling of the unit sphere using spherical coordinates. + * @param[in] u Uniform random numbers in [0,1)^2. + * @return Sampled point on the unit sphere. + */ +float3 sample_sphere(float2 u) +{ + float phi = M_2PI * u.y; + float cosTheta = 1.0f - 2.0f * u.x; + float sinTheta = sqrt(max(0.0f, 1.0f - cosTheta * cosTheta)); + return float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); +} + +/** + * Uniform sampling of the unit hemisphere using sphere sampling. + * @param[in] u Uniform random numbers in [0,1)^2. + * @return Sampled point on the unit hemisphere. + */ +float3 sample_hemisphere(float2 u) +{ + float3 w = sample_sphere(u); + w.z = abs(w.z); + return w; +} + +/** + * Uniform sampling of the unit disk using Shirley's concentric mapping. + * @param[in] u Uniform random numbers in [0,1)^2. + * @return Sampled point on the unit disk. + */ +float2 sample_disk_concentric(float2 u) +{ + u = 2.f * u - 1.f; + if (u.x == 0.f && u.y == 0.f) + return u; + float phi, r; + if (abs(u.x) > abs(u.y)) + { + r = u.x; + phi = (u.y / u.x) * M_PI_4; + } + else + { + r = u.y; + phi = M_PI_2 - (u.x / u.y) * M_PI_4; + } + return r * float2(cos(phi), sin(phi)); +} + +/** + * Cosine-weighted sampling of the hemisphere using Shirley's concentric mapping. + * @param[in] u Uniform random numbers in [0,1)^2. + * @param[out] pdf Probability density of the sampled direction (= cos(theta)/pi). + * @return Sampled direction in the local frame (+z axis up). + */ +float3 sample_cosine_hemisphere_concentric(float2 u, out float pdf) +{ + float2 d = sample_disk_concentric(u); + float z = sqrt(max(0.f, 1.f - dot(d, d))); + pdf = z * M_1_PI; + return float3(d, z); +} + +/** + * Cosine-weighted sampling of the hemisphere using a polar coordinates. + * @param[in] u Uniform random numbers in [0,1)^2. + * @param[out] pdf Probability density of the sampled direction (= cos(theta)/pi). + * @return Sampled direction in the local frame (+z axis up). + */ +float3 sample_cosine_hemisphere_polar(float2 u, out float pdf) +{ + float3 p; + float r = sqrt(u.x); + float phi = M_2PI * u.y; + p.x = r * cos(phi); + p.y = r * sin(phi); + p.z = sqrt(1.f - u.x); + pdf = p.z * M_1_PI; + return p; +} + +/** + * Cosine-weighted sampling of the hemisphere using a polar coordinates. + * This overload does not compute the pdf for the generated sample. + * @param[in] u Uniform random numbers in [0,1)^2. + * @return Sampled direction in the local frame (+z axis up). + */ +float3 sample_cosine_hemisphere_polar(float2 u) +{ + float pdf; + return sample_cosine_hemisphere_polar(u, pdf); +} + +/** + * Uniform sampling of a triangle. + * @param[in] u Uniform random numbers in [0,1)^2. + * @return Barycentric coordinates (1-u-v,u,v) of the sampled point. + */ +float3 sample_triangle(float2 u) +{ + float su = sqrt(u.x); + float2 b = float2(1.f - su, u.y * su); + return float3(1.f - b.x - b.y, b.x, b.y); +} + +/** + * Sample from the von-Mises Fisher distribution. + * @param[in] u Uniform random numbers in [0,1)^2. + * @param[in] kappa VMF concentration parameter. + * @return Sampled direction in the local frame (+z axis up). + */ +[PreferRecompute] +float3 sampleVonMisesFisher(float2 u, float kappa) +{ + float sy = max(1.f - u.y, 1e-6f); + float phi = M_2PI * u.x; + float cosTheta = 1.f + log(exp(-2.f * kappa) * (1.f - sy) + sy) / kappa; + float sinTheta = sqrt(1.f - cosTheta * cosTheta); + float3 d = float3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); + return d; +} + +/****************************************************************************** + + Motion vectors + +******************************************************************************/ + +/** + * Calculate screen-space motion vector. + * @param[in] pixelCrd Sample in current frame expressed in pixel coordinates with origin in the top-left corner. + * @param[in] prevPosH Sample in previous frame expressed in homogeneous clip space coordinates. Note that the definition differs between + * D3D12 and Vulkan. + * @param[in] renderTargetDim Render target dimension in pixels. + * @return Motion vector pointing from current to previous position expressed in sceen space [0,1] with origin in the top-left corner. + */ +float2 calcMotionVector(float2 pixelCrd, float4 prevPosH, float2 renderTargetDim) +{ + float2 prevCrd = prevPosH.xy / prevPosH.w; +#ifdef FALCOR_FLIP_Y + prevCrd *= float2(0.5, 0.5); +#else + prevCrd *= float2(0.5, -0.5); +#endif + prevCrd += 0.5f; + float2 normalizedCrd = pixelCrd / renderTargetDim; + return prevCrd - normalizedCrd; +} + +/****************************************************************************** + + Miscellaneous functions + +******************************************************************************/ + +/** + * Inverts a 2x2 matrix. + */ +float2x2 inverse(float2x2 M) +{ + float2x2 inv; + float invdet = 1.0f / determinant(M); + inv[0][0] = M[1][1] * invdet; + inv[1][1] = M[0][0] * invdet; + inv[0][1] = -M[0][1] * invdet; + inv[1][0] = -M[1][0] * invdet; + return inv; +} + +/** + * Inverts a 2x3 matrix. + */ +float2x3 inverse(float2x3 M) +{ + float2x2 N = float2x2(M._m00, M._m01, M._m10, M._m11); + float2x2 Ni = inverse(N); + float2 t = -mul(Ni, float2(M._m02, M._m12)); + float2x3 Mi = float2x3(Ni._m00, Ni._m01, t.x, Ni._m10, Ni._m11, t.y); + return Mi; +} + +/** + * Inverts a 3x3 matrix. + */ +float3x3 inverse(float3x3 M) +{ + float3x3 inv; + float invdet = 1.0f / determinant(M); + inv[0][0] = (M[1][1] * M[2][2] - M[2][1] * M[1][2]) * invdet; + inv[0][1] = (M[0][2] * M[2][1] - M[0][1] * M[2][2]) * invdet; + inv[0][2] = (M[0][1] * M[1][2] - M[0][2] * M[1][1]) * invdet; + inv[1][0] = (M[1][2] * M[2][0] - M[1][0] * M[2][2]) * invdet; + inv[1][1] = (M[0][0] * M[2][2] - M[0][2] * M[2][0]) * invdet; + inv[1][2] = (M[1][0] * M[0][2] - M[0][0] * M[1][2]) * invdet; + inv[2][0] = (M[1][0] * M[2][1] - M[2][0] * M[1][1]) * invdet; + inv[2][1] = (M[2][0] * M[0][1] - M[0][0] * M[2][1]) * invdet; + inv[2][2] = (M[0][0] * M[1][1] - M[1][0] * M[0][1]) * invdet; + return inv; +} + +/** + * Inverts a 4x4 matrix. + */ +float4x4 inverse(float4x4 m) +{ + float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0]; + float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1]; + float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2]; + float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3]; + + float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; + float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; + float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; + float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + + float det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + float idet = 1.0f / det; + + float4x4 ret; + + ret[0][0] = t11 * idet; + ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet; + ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet; + ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet; + + ret[1][0] = t12 * idet; + ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet; + ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet; + ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet; + + ret[2][0] = t13 * idet; + ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet; + ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet; + ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet; + + ret[3][0] = t14 * idet; + ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet; + ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet; + ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet; + + return ret; +} + +/** + * Generate a vector that is orthogonal to the input vector. + * This can be used to invent a tangent frame for meshes that don't have real tangents/bitangents. + * @param[in] u Unit vector. + * @return v Unit vector that is orthogonal to u. + */ +float3 perp_stark(float3 u) +{ + // TODO: Validate this and look at numerical precision etc. Are there better ways to do it? + float3 a = abs(u); + uint uyx = (a.x - a.y) < 0 ? 1 : 0; + uint uzx = (a.x - a.z) < 0 ? 1 : 0; + uint uzy = (a.y - a.z) < 0 ? 1 : 0; + uint xm = uyx & uzx; + uint ym = (1 ^ xm) & uzy; + uint zm = 1 ^ (xm | ym); // 1 ^ (xm & ym) + float3 v = normalize(cross(u, float3(xm, ym, zm))); + return v; +} + +/** + * @brief Generates full OrthoNormalBasis based on the normal, without branches or sqrt. + * + * From https://graphics.pixar.com/library/OrthonormalB/paper.pdf + */ +void branchlessONB(const float3 n, out float3 b1, out float3 b2) +{ + // can't use just `sign` because we need 0 to go into -1/+1, but not 0 + float sign = (n.z >= 0 ? 1 : -1); + const float a = -1.0f / (sign + n.z); + const float b = n.x * n.y * a; + b1 = float3(1.0f + sign * n.x * n.x * a, sign * b, -sign * n.x); + b2 = float3(b, sign + n.y * n.y * a, -n.y); +} + +// clang-format off +[Differentiable] float sqr(float v) { return v * v; } +[Differentiable] float2 sqr(float2 v) { return v * v; } +[Differentiable] float3 sqr(float3 v) { return v * v; } +[Differentiable] float4 sqr(float4 v) { return v * v; } +// clang-format on + +/** + * Error function. + */ +float erf(float x) +{ + // From "Numerical Recipes in C, The Art of Scientific Computing" + // (Second Edition) by Press et al. 1992. Page 221. + // Maxiumum error: 1.2 x 10^-7. + float t = 1.0f / (1.0f + 0.5f * abs(x)); + float p = 0.17087277f; + p = -0.82215223f + p * t; + p = 1.48851587f + p * t; + p = -1.13520398f + p * t; + p = 0.27886807f + p * t; + p = -0.18628806f + p * t; + p = 0.09678418f + p * t; + p = 0.37409196f + p * t; + p = 1.00002368f + p * t; + p = -1.26551223f + p * t; + float tau = t * exp(-x * x + p); + return x >= 0.0f ? 1.0f - tau : tau - 1.0f; +} + +/** + * Inverse error function. + */ +float erfinv(float x) +{ + // From "Approximating the erfinv function" by Mike Giles 2012. + // Maximum error: 7 x 10^-7. + if (x <= -1.0f) + { + return -1.0f / 0.0f; + } + else if (x >= 1.0f) + { + return 1.0f / 0.0f; + } + + float w = -log((1.0f - x) * (1.0f + x)); + float p; + if (w < 5.0f) + { + w = w - 2.5f; + p = 2.81022636e-08f; + p = 3.43273939e-07f + p * w; + p = -3.5233877e-06f + p * w; + p = -4.39150654e-06f + p * w; + p = 0.00021858087f + p * w; + p = -0.00125372503f + p * w; + p = -0.00417768164f + p * w; + p = 0.246640727f + p * w; + p = 1.50140941f + p * w; + } + else + { + w = sqrt(w) - 3.0f; + p = -0.000200214257f; + p = 0.000100950558f + p * w; + p = 0.00134934322f + p * w; + p = -0.00367342844f + p * w; + p = 0.00573950773f + p * w; + p = -0.0076224613f + p * w; + p = 0.00943887047f + p * w; + p = 1.00167406f + p * w; + p = 2.83297682f + p * w; + } + return p * x; +} + +/** + * Logarithm of the Gamma function. + */ +float lgamma(float x_) +{ + // Lanczos approximation from + // "Numerical Recipes in C, The Art of Scientific Computing" + // (Second Edition) by Press et al. 1992. Page 214. + // Maxiumum error: 2 x 10^-10. + const float g = 5.0; + const float coeffs[7] = { + 1.000000000190015, + 76.18009172947146, + -86.50532032941677, + 24.01409824083091, + -1.231739572450155, + 0.1208650973866179e-2, + -0.5395239384953e-5, + }; + + bool reflect = x_ < 0.5f; + float x = reflect ? -x_ : x_ - 1.0f; + float base = x + g + 0.5f; + + float s = 0.0f; + for (int i = 6; i >= 1; --i) + { + s += coeffs[i] / (x + (float)i); + } + s += coeffs[0]; + + float res = ((log(sqrt(2 * M_PI)) + log(s)) - base) + log(base) * (x + 0.5f); + if (reflect) + { + // Apply the Gamma reflection formula (in log-space). + res = log(abs(M_PI / sin(M_PI * x_))) - res; + } + return res; +} + +/** + * Gamma function. + */ +float gamma(float x) +{ + return exp(lgamma(x)); +} + +/** + * Beta function. + */ +float beta(float x, float y) +{ + return gamma(x) * gamma(y) / gamma(x + y); +} + +/** + * Given two vectors, will orthonormalized them, preserving v1 and v2. + * Vector v1 must be already normalized, v2 will be renormalized as part of the adjustment. + * Vector v2 is assumed to be non-zero and already somewhat orthogonal to v1, as this code does not handle v2=0 or v2=v1 + * + * @param[in] v1 A normalized vector to orthogonalize v2 to. + * @param[in,out] v2 Vector to be adjusted to be orthonormal to v2. + */ +void orthogonalizeVectors(const float3 v1, inout float3 v2) +{ + v2 = normalize(v2 - dot(v1, v2) * v1); +} + +/** + * Rotate a 3D vector counterclockwise around the X-axis. + * The rotation angle is positive for a rotation that is counterclockwise when looking along the x-axis towards the origin. + * @param[in] v Original vector. + * @param[in] angle Angle in radians. + * @return Transformed vector. + */ +[BackwardDifferentiable] +float3 rotate_x(const float3 v, const float angle) +{ + float c, s; + sincos(angle, s, c); + return float3(v.x, v.y * c - v.z * s, v.y * s + v.z * c); +} + +/** + * Rotate a 3D vector counterclockwise around the Y-axis. + * The rotation angle is positive for a rotation that is counterclockwise when looking along the y-axis towards the origin. + * @param[in] v Original vector. + * @param[in] angle Angle in radians. + * @return Transformed vector. + */ +[BackwardDifferentiable] +float3 rotate_y(const float3 v, const float angle) +{ + float c, s; + sincos(angle, s, c); + return float3(v.x * c + v.z * s, v.y, -v.x * s + v.z * c); +} + +/** + * Rotate a 3D vector counterclockwise around the Z-axis. + * The rotation angle is positive for a rotation that is counterclockwise when looking along the z-axis towards the origin. + * @param[in] v Original vector. + * @param[in] angle Angle in radians. + * @return Transformed vector. + */ +[BackwardDifferentiable] +float3 rotate_z(const float3 v, const float angle) +{ + float c, s; + sincos(angle, s, c); + return float3(v.x * c - v.y * s, v.x * s + v.y * c, v.z); +} + +/** + * Normalize a 3D vector, but return 0 if the vector is zero. + * @param[in] v Original vector. + * @return Normalized vector, or 0 if the vector is zero. + */ +[Differentiable] +[PreferRecompute] +float3 normalizeSafe(float3 v) +{ + float len = length(v); + return len > 0.f ? v / len : float3(0.f); +} diff --git a/Techniques/Denoising/SVGF/README.txt b/Techniques/Denoising/SVGF/README.txt new file mode 100644 index 00000000..a0d32ac0 --- /dev/null +++ b/Techniques/Denoising/SVGF/README.txt @@ -0,0 +1 @@ +This was adapted to Gigi from https://github.com/NVIDIAGameWorks/Falcor/tree/master/Source/RenderPasses/SVGFPass \ No newline at end of file diff --git a/Techniques/Denoising/SVGF/SVGF.gg b/Techniques/Denoising/SVGF/SVGF.gg new file mode 100644 index 00000000..519f1ad8 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGF.gg @@ -0,0 +1,1343 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "BuffersNeedClear", + "type": "Bool", + "dflt": "true" + }, + { + "name": "Alpha", + "type": "Float", + "dflt": "0.05f", + "visibility": "User" + }, + { + "name": "MomentsAlpha", + "type": "Float", + "dflt": "0.2f", + "visibility": "User" + }, + { + "name": "PhiColor", + "type": "Float", + "dflt": "10.0f", + "visibility": "User" + }, + { + "name": "PhiNormal", + "type": "Float", + "dflt": "128.0f", + "visibility": "User" + }, + { + "name": "FilterIterations", + "comment": "For atrous filtering", + "type": "Int", + "Const": true, + "dflt": "4", + "visibility": "User" + }, + { + "name": "FeedbackTap", + "comment": "When do to the feedback tap in the atrous loop. -1 to use the illumination.", + "type": "Int", + "dflt": "1", + "visibility": "User" + }, + { + "name": "FeedbackTapMax", + "type": "Int" + } + ], + "shaders": [ + { + "name": "ClearBuffersCS", + "fileName": "ClearBuffersCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "LinearZAndNormal", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PrevLinearZAndNormal", + "type": "Texture", + "access": "UAV" + }, + { + "name": "FilteredPastFbo", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PrevReprojFbo_0", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PrevReprojFbo_1", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PrevReprojFbo_2", + "type": "Texture", + "access": "UAV" + }, + { + "name": "CurReprojFbo_0", + "type": "Texture", + "access": "UAV" + }, + { + "name": "CurReprojFbo_1", + "type": "Texture", + "access": "UAV" + }, + { + "name": "CurReprojFbo_2", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PingPongFbo_0", + "type": "Texture", + "access": "UAV" + }, + { + "name": "PingPongFbo_1", + "type": "Texture", + "access": "UAV" + }, + { + "name": "Final_Fbo", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "ComputeLinearZAndNormal", + "fileName": "SVGFPackLinearZAndNormal.ps.slang", + "entryPoint": "csmain", + "slangOptions": { + "process": true + }, + "resources": [ + { + "name": "gLinearZ", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gNormal", + "type": "Texture", + "access": "SRV" + }, + { + "name": "LinearZAndNormalFbo", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "ComputeReprojectionCS", + "fileName": "SVGFReproject.ps.slang", + "entryPoint": "csmain", + "slangOptions": { + "process": true + }, + "resources": [ + { + "name": "gMotion", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gColor", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gEmission", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gAlbedo", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gPositionNormalFwidth", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gLinearZAndNormal", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gPrevLinearZAndNormal", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gPrevIllum", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gPrevMoments", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gPrevHistoryLength", + "type": "Texture", + "access": "SRV" + }, + { + "name": "CurReprojFbo_0", + "type": "Texture", + "access": "UAV" + }, + { + "name": "CurReprojFbo_1", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float2" + } + }, + { + "name": "CurReprojFbo_2", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float" + } + } + ] + }, + { + "name": "ComputeFilteredMomentsCS", + "fileName": "SVGFFilterMoments.ps.slang", + "entryPoint": "csmain", + "slangOptions": { + "process": true + }, + "resources": [ + { + "name": "gLinearZAndNormal", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gIllumination", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gMoments", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gHistoryLength", + "type": "Texture", + "access": "SRV" + }, + { + "name": "PingPongFbo_0", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "FinalModulateCS", + "fileName": "SVGFFinalModulate.ps.slang", + "entryPoint": "csmain", + "slangOptions": { + "process": true + }, + "resources": [ + { + "name": "gEmission", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gAlbedo", + "type": "Texture", + "access": "SRV" + }, + { + "name": "gIllumination", + "type": "Texture", + "access": "SRV" + }, + { + "name": "FinalFbo", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "fileCopies": [ + { + "fileName": "MathHelpers.slang", + "type": "Shader" + }, + { + "fileName": "MathConstants.slangh", + "type": "Shader" + }, + { + "fileName": "ColorHelpers.slang", + "type": "Shader" + }, + { + "fileName": "SVGFCommon.slang", + "type": "Shader" + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "ClearBuffers", + "editorPos": [ + -251.0, + -30.0 + ], + "condition": { + "variable1": "BuffersNeedClear", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "LinearZAndNormal", + "dstNode": "Internal_LinearZAndNormalFbo", + "dstPin": "resource" + }, + { + "srcPin": "FilteredPastFbo", + "dstNode": "Internal_FilteredPastFbo", + "dstPin": "resource" + }, + { + "srcPin": "PrevReprojFbo_0", + "dstNode": "Internal_PrevReprojFbo_0", + "dstPin": "resource" + }, + { + "srcPin": "PrevReprojFbo_1", + "dstNode": "Internal_PrevReprojFbo_1", + "dstPin": "resource" + }, + { + "srcPin": "PrevReprojFbo_2", + "dstNode": "Internal_PrevReprojFbo_2", + "dstPin": "resource" + }, + { + "srcPin": "PrevReprojFbo_1" + }, + { + "srcPin": "PrevReprojFbo_0" + }, + { + "srcPin": "CurReprojFbo_1", + "dstNode": "Internal_CurReprojFbo_1", + "dstPin": "resource" + }, + { + "srcPin": "CurReprojFbo_2", + "dstNode": "Internal_CurReprojFbo_2", + "dstPin": "resource" + }, + { + "srcPin": "CurReprojFbo_0", + "dstNode": "Internal_CurReprojFbo_0", + "dstPin": "resource" + }, + { + "srcPin": "PrevLinearZAndNormal", + "dstNode": "Internal_PrevLinearZAndNormal", + "dstPin": "resource" + }, + { + "srcPin": "PingPongFbo_1", + "dstNode": "Internal_PingPongFbo_1", + "dstPin": "resource" + }, + { + "srcPin": "PingPongFbo_0", + "dstNode": "Internal_PingPongFbo_0", + "dstPin": "resource" + }, + { + "srcPin": "Final_Fbo", + "dstNode": "Internal_FinalFbo", + "dstPin": "resource" + } + ], + "shader": { + "name": "ClearBuffersCS" + }, + "dispatchSize": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_LinearZAndNormalFbo", + "editorPos": [ + -575.0, + -158.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "LinearZ", + "editorPos": [ + -117.0, + -142.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "WorldNormal", + "editorPos": [ + -123.0, + -94.0 + ], + "visibility": "Imported" + } + }, + { + "actionComputeShader": { + "name": "ComputeLinearZAndNormal", + "editorPos": [ + 32.0, + -81.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "gLinearZ", + "dstNode": "LinearZ", + "dstPin": "resource" + }, + { + "srcPin": "gNormal", + "dstNode": "WorldNormal", + "dstPin": "resource" + }, + { + "srcPin": "LinearZAndNormalFbo", + "dstNode": "ClearBuffers", + "dstPin": "LinearZAndNormal" + } + ], + "shader": { + "name": "ComputeLinearZAndNormal" + }, + "dispatchSize": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_CurReprojFbo_0", + "comment": "index 0 is illumination", + "editorPos": [ + -536.0, + 130.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_CurReprojFbo_1", + "comment": "index 1 is moments", + "editorPos": [ + -536.0, + 178.0 + ], + "transient": false, + "format": { + "format": "RG32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_CurReprojFbo_2", + "comment": "index 2 is history length", + "editorPos": [ + -536.0, + 226.0 + ], + "transient": false, + "format": { + "format": "R32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "actionComputeShader": { + "name": "ComputeReprojection", + "editorPos": [ + 357.0, + -110.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "gEmission", + "dstNode": "Emission", + "dstPin": "resource" + }, + { + "srcPin": "gMotion", + "dstNode": "MotionVector", + "dstPin": "resource" + }, + { + "srcPin": "gColor", + "dstNode": "Color", + "dstPin": "resource" + }, + { + "srcPin": "gAlbedo", + "dstNode": "Albedo", + "dstPin": "resource" + }, + { + "srcPin": "gPrevMoments", + "dstNode": "ClearBuffers", + "dstPin": "PrevReprojFbo_1" + }, + { + "srcPin": "gPositionNormalFwidth", + "dstNode": "PosNormalFwidth", + "dstPin": "resource" + }, + { + "srcPin": "gPrevIllum", + "dstNode": "ClearBuffers", + "dstPin": "FilteredPastFbo" + }, + { + "srcPin": "gPrevHistoryLength", + "dstNode": "ClearBuffers", + "dstPin": "PrevReprojFbo_2" + }, + { + "srcPin": "gLinearZAndNormal", + "dstNode": "ComputeLinearZAndNormal", + "dstPin": "LinearZAndNormalFbo" + }, + { + "srcPin": "gPrevLinearZAndNormal", + "dstNode": "ClearBuffers", + "dstPin": "PrevLinearZAndNormal" + }, + { + "srcPin": "CurReprojFbo_2", + "dstNode": "ClearBuffers", + "dstPin": "CurReprojFbo_2" + }, + { + "srcPin": "CurReprojFbo_0", + "dstNode": "ClearBuffers", + "dstPin": "CurReprojFbo_0" + }, + { + "srcPin": "CurReprojFbo_1", + "dstNode": "ClearBuffers", + "dstPin": "CurReprojFbo_1" + } + ], + "shader": { + "name": "ComputeReprojectionCS" + }, + "dispatchSize": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "MotionVector", + "editorPos": [ + 86.0, + -334.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Color", + "editorPos": [ + 91.0, + -286.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Emission", + "editorPos": [ + 91.0, + -238.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Albedo", + "editorPos": [ + 91.0, + -190.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "PosNormalFwidth", + "editorPos": [ + 62.0, + -142.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Internal_FilteredPastFbo", + "editorPos": [ + -536.0, + -62.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PrevReprojFbo_0", + "comment": "index 0 is illumination", + "editorPos": [ + -542.0, + -14.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PrevReprojFbo_1", + "comment": "index 1 is moments", + "editorPos": [ + -542.0, + 34.0 + ], + "transient": false, + "format": { + "format": "RG32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PrevReprojFbo_2", + "comment": "index 2 is history length", + "editorPos": [ + -542.0, + 82.0 + ], + "transient": false, + "format": { + "format": "R32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PrevLinearZAndNormal", + "editorPos": [ + -580.0, + -110.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "actionComputeShader": { + "name": "ComputeFilteredMoments", + "editorPos": [ + 613.0, + 82.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "gIllumination", + "dstNode": "ComputeReprojection", + "dstPin": "CurReprojFbo_0" + }, + { + "srcPin": "gHistoryLength", + "dstNode": "ComputeReprojection", + "dstPin": "CurReprojFbo_2" + }, + { + "srcPin": "gLinearZAndNormal", + "dstNode": "ComputeReprojection", + "dstPin": "gLinearZAndNormal" + }, + { + "srcPin": "gMoments", + "dstNode": "ComputeReprojection", + "dstPin": "CurReprojFbo_1" + }, + { + "srcPin": "PingPongFbo_0", + "dstNode": "ClearBuffers", + "dstPin": "PingPongFbo_0" + } + ], + "shader": { + "name": "ComputeFilteredMomentsCS" + }, + "dispatchSize": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PingPongFbo_0", + "editorPos": [ + -531.0, + 274.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_PingPongFbo_1", + "editorPos": [ + -531.0, + 322.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "actionSubGraph": { + "name": "ComputeAtrousDecomposition", + "editorPos": [ + 933.0, + -20.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Albedo", + "dstNode": "ComputeReprojection", + "dstPin": "gAlbedo" + }, + { + "srcPin": "LinearZAndNormal", + "dstNode": "ComputeFilteredMoments", + "dstPin": "gLinearZAndNormal" + }, + { + "srcPin": "HistoryLength", + "dstNode": "ComputeFilteredMoments", + "dstPin": "gHistoryLength" + }, + { + "srcPin": "PingPongFbo_0", + "dstNode": "ComputeFilteredMoments", + "dstPin": "PingPongFbo_0" + }, + { + "srcPin": "PingPongFbo_1 ", + "dstNode": "PingPongFbo_1_A", + "dstPin": "Pin 0" + }, + { + "srcPin": "FilteredPastFbo", + "dstNode": "ComputeReprojection", + "dstPin": "gPrevIllum" + } + ], + "fileName": "Atrous.gg", + "subGraphData": { + "importedResources": [ + "Albedo", + "LinearZAndNormal", + "HistoryLength", + "PingPongFbo_0", + "PingPongFbo_1 ", + "FilteredPastFbo" + ], + "variables": [ + { + "name": "PhiColor" + }, + { + "name": "PhiNormal", + "visibility": "User" + }, + { + "name": "LoopIndex", + "visibility": "Host" + }, + { + "name": "FeedbackTap", + "visibility": "User" + } + ] + }, + "variableSettings": [ + { + "name": "PhiColor", + "visibility": "User", + "replaceWithStr": "PhiColor" + }, + { + "name": "PhiNormal", + "visibility": "User", + "replaceWithStr": "PhiNormal" + }, + { + "name": "LoopIndex", + "isLoopIndex": true + }, + { + "name": "FeedbackTap", + "visibility": "User", + "replaceWithStr": "FeedbackTap" + } + ], + "loopCountVariable": { + "name": "FilterIterations" + } + } + }, + { + "actionBarrier": { + "name": "PingPongFbo_1_A", + "comment": "Just to route the lines more cleanly", + "editorPos": [ + 667.0, + 242.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "Pin 0", + "dstNode": "ClearBuffers", + "dstPin": "PingPongFbo_1" + }, + { + "srcPin": "Pin 1" + } + ] + } + }, + { + "actionCopyResource": { + "name": "FeedbackTapOuter", + "editorPos": [ + 1201.0, + 130.0 + ], + "condition": { + "variable1": "FeedbackTap", + "comparison": "LT", + "value2": "0" + }, + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "ComputeFilteredMoments", + "pin": "gIllumination" + }, + "dest": { + "node": "ComputeAtrousDecomposition", + "pin": "FilteredPastFbo" + } + } + }, + { + "actionComputeShader": { + "name": "FinalModulate", + "editorPos": [ + 1419.0, + -74.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "gAlbedo", + "dstNode": "ComputeAtrousDecomposition", + "dstPin": "Albedo" + }, + { + "srcPin": "gEmission", + "dstNode": "ComputeReprojection", + "dstPin": "gEmission" + }, + { + "srcPin": "gIllumination", + "dstNode": "ComputeAtrousDecomposition", + "dstPin": "PingPongFbo_0" + }, + { + "srcPin": "FinalFbo", + "dstNode": "Final_Fbo_A", + "dstPin": "Pin 0" + } + ], + "shader": { + "name": "FinalModulateCS" + }, + "dispatchSize": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "resourceTexture": { + "name": "Internal_FinalFbo", + "editorPos": [ + -496.0, + 370.0 + ], + "transient": false, + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "actionBarrier": { + "name": "Final_Fbo_A", + "editorPos": [ + 661.0, + 322.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "Pin 0", + "dstNode": "ClearBuffers", + "dstPin": "Final_Fbo" + }, + { + "srcPin": "Pin 1" + } + ] + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + 1547.0, + 95.0 + ], + "visibility": "Exported", + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "LinearZ" + } + } + } + }, + { + "actionCopyResource": { + "name": "BlitToOutput", + "editorPos": [ + 1685.0, + -17.0 + ], + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "FinalModulate", + "pin": "FinalFbo" + }, + "dest": { + "node": "Output", + "pin": "resource" + } + } + }, + { + "actionSubGraph": { + "name": "SwapReprojFbo_0", + "editorPos": [ + 1301.0, + -206.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "A", + "dstNode": "FeedbackTapOuter", + "dstPin": "source" + }, + { + "srcPin": "B", + "dstNode": "PrevReprojFbo_0_A", + "dstPin": "Pin 0" + } + ], + "fileName": "SwapTextures.gg", + "subGraphData": { + "importedResources": [ + "A", + "B" + ] + } + } + }, + { + "actionBarrier": { + "name": "PrevReprojFbo_0_A", + "editorPos": [ + 661.0, + 418.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "Pin 0", + "dstNode": "ClearBuffers", + "dstPin": "PrevReprojFbo_0" + }, + { + "srcPin": "Pin 1" + } + ] + } + }, + { + "actionSubGraph": { + "name": "SwapReprojFbo_1", + "editorPos": [ + 943.0, + -206.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "A", + "dstNode": "ComputeFilteredMoments", + "dstPin": "gMoments" + }, + { + "srcPin": "B", + "dstNode": "ComputeReprojection", + "dstPin": "gPrevMoments" + } + ], + "fileName": "SwapTextures.gg", + "subGraphData": { + "importedResources": [ + "A", + "B" + ] + } + } + }, + { + "actionSubGraph": { + "name": "SwapReprojFbo_2", + "editorPos": [ + 1125.0, + -206.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "A", + "dstNode": "ComputeAtrousDecomposition", + "dstPin": "HistoryLength" + }, + { + "srcPin": "B", + "dstNode": "ComputeReprojection", + "dstPin": "gPrevHistoryLength" + } + ], + "fileName": "SwapTextures.gg", + "subGraphData": { + "importedResources": [ + "A", + "B" + ] + } + } + }, + { + "actionCopyResource": { + "name": "CopyLinearZAndNormalFbo", + "editorPos": [ + 1509.0, + -206.0 + ], + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "ComputeAtrousDecomposition", + "pin": "LinearZAndNormal" + }, + "dest": { + "node": "ComputeReprojection", + "pin": "gPrevLinearZAndNormal" + } + } + } + ], + "setVars": [ + { + "destination": { + "name": "BuffersNeedClear" + }, + "ALiteral": "false", + "op": "Noop", + "setBefore": false + }, + { + "destination": { + "name": "FeedbackTapMax" + }, + "AVar": { + "name": "FilterIterations" + }, + "op": "Subtract", + "BLiteral": "1" + }, + { + "destination": { + "name": "FeedbackTap" + }, + "AVar": { + "name": "FeedbackTap" + }, + "op": "Minimum", + "BVar": { + "name": "FeedbackTapMax" + } + }, + { + "destination": { + "name": "FeedbackTap" + }, + "AVar": { + "name": "FeedbackTap" + }, + "op": "Maximum", + "BLiteral": "-1" + } + ] +} \ No newline at end of file diff --git a/Techniques/Denoising/SVGF/SVGF.gguser b/Techniques/Denoising/SVGF/SVGF.gguser new file mode 100644 index 00000000..95c94920 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGF.gguser @@ -0,0 +1,172 @@ +{ + "version": "2.0", + "snapshot": { + "resourceViewNodeIndex": 41, + "resourceViewResourceIndex": 2, + "importedResources": [ + { + "nodeName": "Albedo", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.501960813999176, + 1.0, + 0.501960813999176, + 1.0 + ] + } + }, + { + "nodeName": "Color", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 1.0, + 0.501960813999176, + 0.501960813999176, + 1.0 + ] + } + }, + { + "nodeName": "Emission", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": "RGBA32_Float" + } + }, + { + "nodeName": "LinearZ", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.501960813999176, + 1.0, + 1.0, + 1.0 + ], + "format": "R32_Float" + } + }, + { + "nodeName": "MotionVector", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": "RGBA32_Float" + } + }, + { + "nodeName": "PosNormalFwidth", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": "RGBA32_Float" + } + }, + { + "nodeName": "WorldNormal", + "texture": { + "size": [ + 512, + 512, + 1 + ], + "color": [ + 0.0, + 1.0, + 0.0, + 1.0 + ], + "format": "RGBA32_Float" + } + } + ], + "savedVariables": [ + { + "name": "BuffersNeedClear", + "value": "false" + }, + { + "name": "Alpha", + "value": "0.050000" + }, + { + "name": "MomentsAlpha", + "value": "0.200000" + }, + { + "name": "PhiColor", + "value": "10.000000" + }, + { + "name": "PhiNormal", + "value": "128.000000" + }, + { + "name": "FeedbackTap", + "value": "1" + }, + { + "name": "FeedbackTapMax", + "value": "3" + }, + { + "name": "ComputeAtrousDecomposition_Iteration_0_LoopIndex", + "value": "0" + }, + { + "name": "ComputeAtrousDecomposition_Iteration_1_LoopIndex", + "value": "0" + }, + { + "name": "ComputeAtrousDecomposition_Iteration_2_LoopIndex", + "value": "0" + }, + { + "name": "ComputeAtrousDecomposition_Iteration_3_LoopIndex", + "value": "0" + } + ] + } +} \ No newline at end of file diff --git a/Techniques/Denoising/SVGF/SVGFAtrous.ps.slang b/Techniques/Denoising/SVGF/SVGFAtrous.ps.slang new file mode 100644 index 00000000..c8747a37 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFAtrous.ps.slang @@ -0,0 +1,154 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +import MathHelpers; +import ColorHelpers; +import SVGFCommon; + +/*$(ShaderResources)*/ +#define gStepSize (1 << /*$(Variable:LoopIndex)*/) +#define gPhiColor /*$(Variable:PhiColor)*/ +#define gPhiNormal /*$(Variable:PhiNormal)*/ +/* +cbuffer PerImageCB +{ + Texture2D gAlbedo; + Texture2D gHistoryLength; + Texture2D gIllumination; + Texture2D gLinearZAndNormal; + + int gStepSize; + float gPhiColor; + float gPhiNormal; +}; +*/ + +// computes a 3x3 gaussian blur of the variance, centered around +// the current pixel +float computeVarianceCenter(int2 ipos) +{ + float sum = 0.f; + + const float kernel[2][2] = { + { 1.0 / 4.0, 1.0 / 8.0 }, + { 1.0 / 8.0, 1.0 / 16.0 }, + }; + + const int radius = 1; + for (int yy = -radius; yy <= radius; yy++) + { + for (int xx = -radius; xx <= radius; xx++) + { + const int2 p = ipos + int2(xx, yy); + const float k = kernel[abs(xx)][abs(yy)]; + sum += gIllumination.Load(int3(p, 0)).a * k; + } + } + + return sum; +} + +//float4 main(FullScreenPassVsOut vsOut) : SV_TARGET0 +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + const int2 ipos = int2(DTid.xy); + const int2 screenSize = getTextureDims(gAlbedo, 0); + + const float epsVariance = 1e-10; + const float kernelWeights[3] = { 1.0, 2.0 / 3.0, 1.0 / 6.0 }; + + // constant samplers to prevent the compiler from generating code which + // fetches the sampler descriptor from memory for each texture access + const float4 illuminationCenter = gIllumination.Load(int3(ipos, 0)); + const float lIlluminationCenter = luminance(illuminationCenter.rgb); + + // variance, filtered using 3x3 gaussin blur + const float var = computeVarianceCenter(ipos); + + // number of temporally integrated pixels + const float historyLength = gHistoryLength[ipos].x; + + const float2 zCenter = gLinearZAndNormal[ipos].xy; + if (zCenter.x < 0) + { + // not a valid depth => must be envmap => do not filter + Output[ipos] = illuminationCenter; + return; + } + const float3 nCenter = oct_to_ndir_snorm(gLinearZAndNormal[ipos].zw); + + const float phiLIllumination = gPhiColor * sqrt(max(0.0, epsVariance + var.r)); + const float phiDepth = max(zCenter.y, 1e-8) * gStepSize; + + // explicitly store/accumulate center pixel with weight 1 to prevent issues + // with the edge-stopping functions + float sumWIllumination = 1.0; + float4 sumIllumination = illuminationCenter; + + for (int yy = -2; yy <= 2; yy++) + { + for (int xx = -2; xx <= 2; xx++) + { + const int2 p = ipos + int2(xx, yy) * gStepSize; + const bool inside = all(p >= int2(0, 0)) && all(p < screenSize); + + const float kernel = kernelWeights[abs(xx)] * kernelWeights[abs(yy)]; + + if (inside && (xx != 0 || yy != 0)) // skip center pixel, it is already accumulated + { + const float4 illuminationP = gIllumination.Load(int3(p, 0)); + const float lIlluminationP = luminance(illuminationP.rgb); + const float zP = gLinearZAndNormal[p].x; + const float3 nP = oct_to_ndir_snorm(gLinearZAndNormal[p].zw); + + // compute the edge-stopping functions + const float2 w = computeWeight( + zCenter.x, + zP, + phiDepth * length(float2(xx, yy)), + nCenter, + nP, + gPhiNormal, + lIlluminationCenter, + lIlluminationP, + phiLIllumination + ); + + const float wIllumination = w.x * kernel; + + // alpha channel contains the variance, therefore the weights need to be squared, see paper for the formula + sumWIllumination += wIllumination; + sumIllumination += float4(wIllumination.xxx, wIllumination * wIllumination) * illuminationP; + } + } + } + + // renormalization is different for variance, check paper for the formula + float4 filteredIllumination = float4(sumIllumination / float4(sumWIllumination.xxx, sumWIllumination * sumWIllumination)); + + Output[ipos] = filteredIllumination; +} diff --git a/Techniques/Denoising/SVGF/SVGFCommon.slang b/Techniques/Denoising/SVGF/SVGFCommon.slang new file mode 100644 index 00000000..b801b213 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFCommon.slang @@ -0,0 +1,64 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +int2 getTextureDims(Texture2D tex, uint mip) +{ + uint w, h; + tex.GetDimensions(w, h); + return int2(w, h); +} + +float computeWeight( + float depthCenter, + float depthP, + float phiDepth, + float3 normalCenter, + float3 normalP, + float phiNormal, + float luminanceIllumCenter, + float luminanceIllumP, + float phiIllum +) +{ + const float weightNormal = pow(saturate(dot(normalCenter, normalP)), phiNormal); + const float weightZ = (phiDepth == 0) ? 0.0f : abs(depthCenter - depthP) / phiDepth; + const float weightLillum = abs(luminanceIllumCenter - luminanceIllumP) / phiIllum; + + const float weightIllum = exp(0.0 - max(weightLillum, 0.0) - max(weightZ, 0.0)) * weightNormal; + + return weightIllum; +} + +struct FullScreenPassVsOut +{ + float2 texC : TEXCOORD; +#ifndef _VIEWPORT_MASK + float4 posH : SV_POSITION; +#else + float4 posH : POSITION; +#endif +}; diff --git a/Techniques/Denoising/SVGF/SVGFFilterMoments.ps.slang b/Techniques/Denoising/SVGF/SVGFFilterMoments.ps.slang new file mode 100644 index 00000000..54249418 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFFilterMoments.ps.slang @@ -0,0 +1,138 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +import MathHelpers; +import ColorHelpers; +import SVGFCommon; + +/*$(ShaderResources)*/ +#define gPhiColor /*$(Variable:PhiColor)*/ +#define gPhiNormal /*$(Variable:PhiNormal)*/ +/* +cbuffer PerImageCB +{ + Texture2D gIllumination; + Texture2D gMoments; + Texture2D gHistoryLength; + Texture2D gLinearZAndNormal; + + float gPhiColor; + float gPhiNormal; +}; +*/ + +//float4 main(FullScreenPassVsOut vsOut) : SV_TARGET0 +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + const float4 posH = float4(DTid.xy, 0.0f, 0.0f); + int2 ipos = int2(posH.xy); + + float h = gHistoryLength[ipos].x; + int2 screenSize = getTextureDims(gHistoryLength, 0); + + if (h < 4.0) // not enough temporal history available + { + float sumWIllumination = 0.0; + float3 sumIllumination = float3(0.0, 0.0, 0.0); + float2 sumMoments = float2(0.0, 0.0); + + const float4 illuminationCenter = gIllumination[ipos]; + const float lIlluminationCenter = luminance(illuminationCenter.rgb); + + const float2 zCenter = gLinearZAndNormal[ipos].xy; + if (zCenter.x < 0) + { + // current pixel does not a valid depth => must be envmap => do nothing + PingPongFbo_0[ipos] = illuminationCenter; + return; + } + const float3 nCenter = oct_to_ndir_snorm(gLinearZAndNormal[ipos].zw); + const float phiLIllumination = gPhiColor; + const float phiDepth = max(zCenter.y, 1e-8) * 3.0; + + // compute first and second moment spatially. This code also applies cross-bilateral + // filtering on the input illumination. + const int radius = 3; + + for (int yy = -radius; yy <= radius; yy++) + { + for (int xx = -radius; xx <= radius; xx++) + { + const int2 p = ipos + int2(xx, yy); + const bool inside = all(p >= int2(0, 0)) && all(p < screenSize); + const bool samePixel = (xx == 0 && yy == 0); + const float kernel = 1.0; + + if (inside) + { + const float3 illuminationP = gIllumination[p].rgb; + const float2 momentsP = gMoments[p].xy; + const float lIlluminationP = luminance(illuminationP.rgb); + const float zP = gLinearZAndNormal[p].x; + const float3 nP = oct_to_ndir_snorm(gLinearZAndNormal[p].zw); + + const float w = computeWeight( + zCenter.x, + zP, + phiDepth * length(float2(xx, yy)), + nCenter, + nP, + gPhiNormal, + lIlluminationCenter, + lIlluminationP, + phiLIllumination + ); + + sumWIllumination += w; + sumIllumination += illuminationP * w; + sumMoments += momentsP * w; + } + } + } + + // Clamp sum to >0 to avoid NaNs. + sumWIllumination = max(sumWIllumination, 1e-6f); + + sumIllumination /= sumWIllumination; + sumMoments /= sumWIllumination; + + // compute variance using the first and second moments + float variance = sumMoments.g - sumMoments.r * sumMoments.r; + + // give the variance a boost for the first frames + variance *= 4.0 / h; + + PingPongFbo_0[ipos] = float4(sumIllumination, variance.r); + return; + } + else + { + // do nothing, pass data unmodified + PingPongFbo_0[ipos] = gIllumination[ipos]; + return; + } +} diff --git a/Techniques/Denoising/SVGF/SVGFFinalModulate.ps.slang b/Techniques/Denoising/SVGF/SVGFFinalModulate.ps.slang new file mode 100644 index 00000000..5681cea1 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFFinalModulate.ps.slang @@ -0,0 +1,46 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +import SVGFCommon; + +/*$(ShaderResources)*/ +/* +cbuffer PerImageCB +{ + Texture2D gAlbedo; + Texture2D gEmission; + Texture2D gIllumination; +}; +*/ + +//float4 main(FullScreenPassVsOut vsOut) : SV_TARGET0 +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + const int2 ipos = int2(DTid.xy); + + FinalFbo[ipos] = gAlbedo[ipos] * gIllumination[ipos] + gEmission[ipos]; +} diff --git a/Techniques/Denoising/SVGF/SVGFPackLinearZAndNormal.ps.slang b/Techniques/Denoising/SVGF/SVGFPackLinearZAndNormal.ps.slang new file mode 100644 index 00000000..65c47a17 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFPackLinearZAndNormal.ps.slang @@ -0,0 +1,48 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +import MathHelpers; +import SVGFCommon; + +/*$(ShaderResources)*/ +/* +cbuffer PerImageCB +{ + Texture2D gLinearZ; + Texture2D gNormal; +}; +*/ + +//float4 main(FullScreenPassVsOut vsOut) : SV_TARGET0 +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + float2 fragCoord = DTid.xy; + const int2 ipos = int2(fragCoord.xy); + + const float2 nPacked = ndir_to_oct_snorm(gNormal[ipos].xyz); + LinearZAndNormalFbo[ipos] = float4(gLinearZ[ipos].xy, nPacked.x, nPacked.y); +} diff --git a/Techniques/Denoising/SVGF/SVGFReproject.ps.slang b/Techniques/Denoising/SVGF/SVGFReproject.ps.slang new file mode 100644 index 00000000..97398395 --- /dev/null +++ b/Techniques/Denoising/SVGF/SVGFReproject.ps.slang @@ -0,0 +1,255 @@ +/*************************************************************************** + # Copyright (c) 2015-23, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, 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. + **************************************************************************/ +import MathHelpers; +import ColorHelpers; +import SVGFCommon; + +// Workaround for isnan() not working in slang. +bool isNaN(float f) +{ + uint u = asuint(f) & ~0x80000000u; // clear out the sign bit + return (u > 0x7F800000); // greater than Inf is NaN +} + +/*$(ShaderResources)*/ +#define gAlpha /*$(Variable:Alpha)*/ +#define gMomentsAlpha /*$(Variable:MomentsAlpha)*/ +/* +cbuffer PerImageCB +{ + Texture2D gMotion; + Texture2D gPositionNormalFwidth; + Texture2D gColor; + Texture2D gAlbedo; + Texture2D gEmission; + Texture2D gPrevIllum; + Texture2D gPrevMoments; + Texture2D gLinearZAndNormal; + Texture2D gPrevLinearZAndNormal; + Texture2D gPrevHistoryLength; + + float gAlpha; + float gMomentsAlpha; +}; +*/ + +float3 demodulate(float3 c, float3 albedo) +{ + return c / max(albedo, float3(0.001, 0.001, 0.001)); +} + +bool isReprjValid(int2 coord, float Z, float Zprev, float fwidthZ, float3 normal, float3 normalPrev, float fwidthNormal) +{ + const int2 imageDim = getTextureDims(gColor, 0); + + // check whether reprojected pixel is inside of the screen + if (any(coord < int2(1, 1)) || any(coord > imageDim - int2(1, 1))) + return false; + + // check if deviation of depths is acceptable + if (abs(Zprev - Z) / (fwidthZ + 1e-2f) > 10.f) + return false; + + // check normals for compatibility + if (distance(normal, normalPrev) / (fwidthNormal + 1e-2) > 16.0) + return false; + + return true; +} + +bool loadPrevData(float2 posH, out float4 prevIllum, out float2 prevMoments, out float historyLength) +{ + const int2 ipos = int2(posH); + const float2 imageDim = float2(getTextureDims(gColor, 0)); + + const float2 motion = gMotion[ipos].xy; + const float normalFwidth = gPositionNormalFwidth[ipos].y; + + // +0.5 to account for texel center offset + const int2 iposPrev = int2(float2(ipos) + motion.xy * imageDim + float2(0.5, 0.5)); + + float2 depth = gLinearZAndNormal[ipos].xy; + float3 normal = oct_to_ndir_snorm(gLinearZAndNormal[ipos].zw); + + prevIllum = float4(0, 0, 0, 0); + prevMoments = float2(0, 0); + + bool v[4]; + const float2 posPrev = floor(posH.xy) + motion.xy * imageDim; + const int2 offset[4] = { int2(0, 0), int2(1, 0), int2(0, 1), int2(1, 1) }; + + // check for all 4 taps of the bilinear filter for validity + bool valid = false; + for (int sampleIdx = 0; sampleIdx < 4; sampleIdx++) + { + int2 loc = int2(posPrev) + offset[sampleIdx]; + float2 depthPrev = gPrevLinearZAndNormal[loc].xy; + float3 normalPrev = oct_to_ndir_snorm(gPrevLinearZAndNormal[loc].zw); + + v[sampleIdx] = isReprjValid(iposPrev, depth.x, depthPrev.x, depth.y, normal, normalPrev, normalFwidth); + + valid = valid || v[sampleIdx]; + } + + if (valid) + { + float sumw = 0; + float x = frac(posPrev.x); + float y = frac(posPrev.y); + + // bilinear weights + const float w[4] = { (1 - x) * (1 - y), x * (1 - y), (1 - x) * y, x * y }; + + // perform the actual bilinear interpolation + for (int sampleIdx = 0; sampleIdx < 4; sampleIdx++) + { + const int2 loc = int2(posPrev) + offset[sampleIdx]; + if (v[sampleIdx]) + { + prevIllum += w[sampleIdx] * gPrevIllum[loc]; + prevMoments += w[sampleIdx] * gPrevMoments[loc].xy; + sumw += w[sampleIdx]; + } + } + + // redistribute weights in case not all taps were used + valid = (sumw >= 0.01); + prevIllum = valid ? prevIllum / sumw : float4(0, 0, 0, 0); + prevMoments = valid ? prevMoments / sumw : float2(0, 0); + } + + if (!valid) // perform cross-bilateral filter in the hope to find some suitable samples somewhere + { + float nValid = 0.0; + + // this code performs a binary descision for each tap of the cross-bilateral filter + const int radius = 1; + for (int yy = -radius; yy <= radius; yy++) + { + for (int xx = -radius; xx <= radius; xx++) + { + const int2 p = iposPrev + int2(xx, yy); + const float2 depthFilter = gPrevLinearZAndNormal[p].xy; + const float3 normalFilter = oct_to_ndir_snorm(gPrevLinearZAndNormal[p].zw); + + if (isReprjValid(iposPrev, depth.x, depthFilter.x, depth.y, normal, normalFilter, normalFwidth)) + { + prevIllum += gPrevIllum[p]; + prevMoments += gPrevMoments[p].xy; + nValid += 1.0; + } + } + } + if (nValid > 0) + { + valid = true; + prevIllum /= nValid; + prevMoments /= nValid; + } + } + + if (valid) + { + // crude, fixme + historyLength = gPrevHistoryLength[iposPrev].x; + } + else + { + prevIllum = float4(0, 0, 0, 0); + prevMoments = float2(0, 0); + historyLength = 0; + } + + return valid; +} + +// not used currently +float computeVarianceScale(float numSamples, float loopLength, float alpha) +{ + const float aa = (1.0 - alpha) * (1.0 - alpha); + return (1.0 - pow(aa, min(loopLength, numSamples))) / (1.0 - aa); +} + +struct PS_OUT +{ + float4 OutIllumination : SV_TARGET0; + float2 OutMoments : SV_TARGET1; + float OutHistoryLength : SV_TARGET2; +}; + +//PS_OUT main(FullScreenPassVsOut vsOut) +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + const float4 posH = float4(DTid.xy, 0.0f, 0.0f); + const int2 ipos = int2(posH.xy); + + float3 illumination = demodulate(gColor[ipos].rgb - gEmission[ipos].rgb, gAlbedo[ipos].rgb); + // Workaround path tracer bugs. TODO: remove this when we can. + if (isNaN(illumination.x) || isNaN(illumination.y) || isNaN(illumination.z)) + { + illumination = float3(0, 0, 0); + } + + float historyLength; + float4 prevIllumination; + float2 prevMoments; + bool success = loadPrevData(posH.xy, prevIllumination, prevMoments, historyLength); + historyLength = min(32.0f, success ? historyLength + 1.0f : 1.0f); + + // this adjusts the alpha for the case where insufficient history is available. + // It boosts the temporal accumulation to give the samples equal weights in + // the beginning. + const float alpha = success ? max(gAlpha, 1.0 / historyLength) : 1.0; + const float alphaMoments = success ? max(gMomentsAlpha, 1.0 / historyLength) : 1.0; + + // compute first two moments of luminance + float2 moments; + moments.r = luminance(illumination); + moments.g = moments.r * moments.r; + + float2 pm = moments; + + // temporal integration of the moments + moments = lerp(prevMoments, moments, alphaMoments); + + float variance = max(0.f, moments.g - moments.r * moments.r); + + // variance *= computeVarianceScale(16, 16, alpha); + + PS_OUT psOut; + // temporal integration of illumination + psOut.OutIllumination = lerp(prevIllumination, float4(illumination, 0), alpha); + // variance is propagated through the alpha channel + psOut.OutIllumination.a = variance; + psOut.OutMoments = moments; + psOut.OutHistoryLength = historyLength; + + CurReprojFbo_0[DTid.xy] = psOut.OutIllumination; + CurReprojFbo_1[DTid.xy] = psOut.OutMoments; + CurReprojFbo_2[DTid.xy] = psOut.OutHistoryLength; +} diff --git a/Techniques/Denoising/SVGF/SwapTextures.gg b/Techniques/Denoising/SVGF/SwapTextures.gg new file mode 100644 index 00000000..d1a3d753 --- /dev/null +++ b/Techniques/Denoising/SVGF/SwapTextures.gg @@ -0,0 +1,108 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "nodes": [ + { + "resourceTexture": { + "name": "A", + "editorPos": [ + 11.0, + 2.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "B", + "editorPos": [ + 171.0, + -30.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Temp", + "editorPos": [ + 11.0, + 66.0 + ], + "format": { + "node": { + "name": "A" + } + }, + "size": { + "node": { + "name": "A" + } + } + } + }, + { + "actionCopyResource": { + "name": "Temp = A", + "editorPos": [ + 165.0, + 34.0 + ], + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "A", + "pin": "resource" + }, + "dest": { + "node": "Temp", + "pin": "resource" + } + } + }, + { + "actionCopyResource": { + "name": "A = B", + "editorPos": [ + 309.0, + 2.0 + ], + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "B", + "pin": "resource" + }, + "dest": { + "node": "Temp = A", + "pin": "source" + } + } + }, + { + "actionCopyResource": { + "name": "B = Temp", + "editorPos": [ + 453.0, + 34.0 + ], + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "Temp = A", + "pin": "dest" + }, + "dest": { + "node": "A = B", + "pin": "dest" + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/BoxBlur/BoxBlur.gg b/Techniques/PostProcessing/BoxBlur/BoxBlur.gg new file mode 100644 index 00000000..530656cd --- /dev/null +++ b/Techniques/PostProcessing/BoxBlur/BoxBlur.gg @@ -0,0 +1,221 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "Radius", + "comment": "The kernel size is Radius*2+1. Radius 1 is 3x3, Radius 2 is 5x5, etc.", + "type": "Int", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "set to true if input is an sRGB format texture", + "type": "Bool", + "dflt": "false", + "visibility": "User" + }, + { + "name": "Disable", + "type": "Bool", + "dflt": "false", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "BoxBlurCS", + "fileName": "BoxBlurCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Input", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "DoBlurH", + "editorPos": [ + -31.0, + 1.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsFalse" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "Input", + "dstPin": "resource" + }, + { + "srcPin": "Output", + "dstNode": "Temp", + "dstPin": "resource" + } + ], + "shader": { + "name": "BoxBlurCS" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + }, + "defines": [ + { + "name": "BLURH", + "value": "1" + } + ] + } + }, + { + "resourceTexture": { + "name": "Input", + "editorPos": [ + -181.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + 11.0, + 98.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Input" + } + }, + "size": { + "node": { + "name": "Input" + } + } + } + }, + { + "actionCopyResource": { + "name": "DontBlur", + "editorPos": [ + 324.0, + -1.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "DoBlurH", + "pin": "Input" + }, + "dest": { + "node": "DoBlurV", + "pin": "Output" + } + } + }, + { + "actionComputeShader": { + "name": "DoBlurV", + "editorPos": [ + 149.0, + 44.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsFalse" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "DoBlurH", + "dstPin": "Output" + }, + { + "srcPin": "Output", + "dstNode": "Output", + "dstPin": "resource" + } + ], + "shader": { + "name": "BoxBlurCS" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + }, + "defines": [ + { + "name": "BLURH", + "value": "0" + } + ] + } + }, + { + "resourceTexture": { + "name": "Temp", + "editorPos": [ + -181.0, + 50.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Input" + } + }, + "size": { + "node": { + "name": "Input" + } + } + } + } + ], + "setVars": [ + { + "destination": { + "name": "Radius" + }, + "AVar": { + "name": "Radius" + }, + "op": "Maximum", + "BLiteral": "0" + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/BoxBlur/BoxBlur.gguser b/Techniques/PostProcessing/BoxBlur/BoxBlur.gguser new file mode 100644 index 00000000..58a4eba8 --- /dev/null +++ b/Techniques/PostProcessing/BoxBlur/BoxBlur.gguser @@ -0,0 +1,29 @@ +{ + "version": "2.0", + "snapshot": { + "resourceViewNodeIndex": 4, + "resourceViewResourceIndex": 3, + "importedResources": [ + { + "nodeName": "Input", + "texture": { + "fileName": "..\\..\\logo.png" + } + } + ], + "savedVariables": [ + { + "name": "Radius", + "value": "5" + }, + { + "name": "sRGB", + "value": "true" + }, + { + "name": "Disable", + "value": "false" + } + ] + } +} \ No newline at end of file diff --git a/Techniques/PostProcessing/BoxBlur/BoxBlurCS.hlsl b/Techniques/PostProcessing/BoxBlur/BoxBlurCS.hlsl new file mode 100644 index 00000000..8c626a6d --- /dev/null +++ b/Techniques/PostProcessing/BoxBlur/BoxBlurCS.hlsl @@ -0,0 +1,48 @@ +// Unnamed technique, shader GaussBlurCS +/*$(ShaderResources)*/ + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + int2 px = DTid.xy; + int2 maxPx; + Input.GetDimensions(maxPx.x, maxPx.y); + maxPx -= int2(1,1); + + // initialize values + float weight = 0.0f; + float3 color = float3(0.0f, 0.0f, 0.0f); + + // loop horizontally or vertically, as appropriate + for (int index = -/*$(Variable:Radius)*/; index <= /*$(Variable:Radius)*/; ++index) + { + int2 offset = (BLURH) ? int2(index, 0) : int2(0, index); + int2 readPx = clamp(px + offset, int2(0, 0), maxPx); + color += Input[readPx].rgb; + weight += 1.0f; + } + + // normalize blur + color /= weight; + + if (/*$(Variable:sRGB)*/) + color = LinearToSRGB(color); + + Output[px] = float4(color, 1.0f); +} + +/* +Shader Resources: + Texture Input (as SRV) + Texture Output (as UAV) +*/ diff --git a/Techniques/PostProcessing/DFT/DFT.gg b/Techniques/PostProcessing/DFT/DFT.gg new file mode 100644 index 00000000..50b7f019 --- /dev/null +++ b/Techniques/PostProcessing/DFT/DFT.gg @@ -0,0 +1,193 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "ChannelDotProduct", + "comment": "A DFT needs a scalar value. Pixel values are dotted against this vector to turn the vectors into a scalar.", + "type": "Float4", + "dflt": "0.25f, 0.25f, 0.25f, 0.25f", + "visibility": "User" + }, + { + "name": "RemoveDC", + "comment": "DC (0hz) is often a large spike that makes it hard to see the rest of the frequencies. Use this to set DC to zero.", + "type": "Bool", + "dflt": "false", + "visibility": "User" + }, + { + "name": "LogSpaceMagnitude", + "comment": "If true, show magnitude in log space", + "type": "Bool", + "dflt": "true", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "DFTCS", + "fileName": "DFTCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Input", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float2" + } + }, + { + "name": "MaxMagnitude", + "type": "Buffer", + "access": "UAV", + "buffer": { + "type": "Uint" + } + } + ] + }, + { + "name": "NormalizeCS", + "fileName": "NormalizeCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "DFTMagnitude", + "type": "Texture", + "access": "UAV" + }, + { + "name": "MaxMagnitude", + "type": "Buffer", + "access": "SRV", + "buffer": { + "type": "Uint" + } + } + ] + } + ], + "nodes": [ + { + "resourceTexture": { + "name": "Input", + "editorPos": [ + 11.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "DFTMagnitude", + "editorPos": [ + -5.0, + 50.0 + ], + "visibility": "Exported", + "format": { + "format": "R32_Float" + }, + "size": { + "node": { + "name": "Input" + } + } + } + }, + { + "actionComputeShader": { + "name": "DFT", + "editorPos": [ + 149.0, + 2.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "Input", + "dstPin": "resource" + }, + { + "srcPin": "Output", + "dstNode": "DFTMagnitude", + "dstPin": "resource" + }, + { + "srcPin": "MaxMagnitude", + "dstNode": "MaxMagnitude", + "dstPin": "resource" + } + ], + "shader": { + "name": "DFTCS" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + } + } + }, + { + "resourceBuffer": { + "name": "MaxMagnitude", + "editorPos": [ + -22.0, + 114.0 + ], + "format": { + "type": "Uint" + } + } + }, + { + "actionComputeShader": { + "name": "Normalize", + "editorPos": [ + 341.0, + 18.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "DFTMagnitude", + "dstNode": "DFT", + "dstPin": "Output" + }, + { + "srcPin": "MaxMagnitude", + "dstNode": "DFT", + "dstPin": "MaxMagnitude" + } + ], + "shader": { + "name": "NormalizeCS" + }, + "dispatchSize": { + "node": { + "name": "DFTMagnitude" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DFT/DFT.gguser b/Techniques/PostProcessing/DFT/DFT.gguser new file mode 100644 index 00000000..013ecafd --- /dev/null +++ b/Techniques/PostProcessing/DFT/DFT.gguser @@ -0,0 +1,27 @@ +{ + "version": "2.0", + "snapshot": { + "importedResources": [ + { + "nodeName": "Input", + "texture": { + "fileName": "..\\..\\logo.png" + } + } + ], + "savedVariables": [ + { + "name": "ChannelDotProduct", + "value": "0.250000,0.250000,0.250000,0.250000" + }, + { + "name": "RemoveDC", + "value": "false" + }, + { + "name": "LogSpaceMagnitude", + "value": "true" + } + ] + } +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DFT/DFTCS.hlsl b/Techniques/PostProcessing/DFT/DFTCS.hlsl new file mode 100644 index 00000000..fcea78b2 --- /dev/null +++ b/Techniques/PostProcessing/DFT/DFTCS.hlsl @@ -0,0 +1,59 @@ +// Unnamed technique, shader DFTCS +/*$(ShaderResources)*/ + +static const float c_pi = 3.14159265359f; + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + float K = float(px.x); + float L = float(px.y); + + uint2 dims; + Input.GetDimensions(dims.x, dims.y); + + float2 dft = float2(0.0f, 0.0f); + + for (uint y = 0; y < dims.y; y++) + { + float vy = L * float(y) / float(dims.y); + for (uint x = 0; x < dims.x; x++) + { + float vx = K * float(x) / float(dims.x); + + float v = vx + vy; + + float theta = -2.0f * c_pi * v; + + float pixelValue = dot(Input[uint2(x,y)].xyzw, float4(/*$(Variable:ChannelDotProduct)*/)); + + dft.x += cos(theta) * pixelValue; + dft.y += sin(theta) * pixelValue; + } + } + + // 1/N in front of the DFT + dft *= 1.0f / float(dims.x*dims.y); + + // Zero out DC (0hz) if we should + if (/*$(Variable:RemoveDC)*/ && px.x == 0 && px.y == 0) + dft = float2(0.0f, 0.0f); + + // DFT shift + px = (px + uint2(dims.x, dims.y) / 2) % dims; + + // Write out magnitude + float magnitude = length(dft); + Output[px] = magnitude; + + // keep track of maximum magnitude + uint dummy; + InterlockedMax(MaxMagnitude[0], asuint(magnitude), dummy); +} + +/* +Shader Resources: + Texture Input (as SRV) + Texture Output (as UAV) + Buffer MaxMagnitude (as UAV) +*/ diff --git a/Techniques/PostProcessing/DFT/NormalizeCS.hlsl b/Techniques/PostProcessing/DFT/NormalizeCS.hlsl new file mode 100644 index 00000000..c2f98cd7 --- /dev/null +++ b/Techniques/PostProcessing/DFT/NormalizeCS.hlsl @@ -0,0 +1,19 @@ +// Unnamed technique, shader NormalizeCS +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + float maxMagnitude = asfloat(MaxMagnitude[0]); + uint2 px = DTid.xy; + float value = DFTMagnitude[px]; + if (/*$(Variable:LogSpaceMagnitude)*/) + DFTMagnitude[px] = log(1.0f + value * 255.0f); + else + DFTMagnitude[px] = value / maxMagnitude; +} + +/* +Shader Resources: + Texture DFTMagnitude (as UAV) + Buffer MaxMagnitude (as SRV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/BlurFarCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/BlurFarCS.hlsl new file mode 100644 index 00000000..fe62ee3a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/BlurFarCS.hlsl @@ -0,0 +1,71 @@ +// Unnamed technique, shader BlurFarCS +/*$(ShaderResources)*/ + +#include "Common.hlsli" + +#define BLUR_TAP_COUNT /*$(Variable:BlurTapCount)*/ + +// .x : size of the bokeh blur radius in texel space +// .y : rotation in radius to apply to the bokeh shape +// .z : Number of edge of the polygon (number of blades). 0: circle. 4: square, 6: hexagon... +#define KernelSize /*$(Variable:KernelSize)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + uint2 FarFieldColorCoCSize; + FarFieldColorCoC.GetDimensions(FarFieldColorCoCSize.x, FarFieldColorCoCSize.y); + + float2 UVAndScreenPos = (float2(px) + float2(0.5f, 0.5f)) / float2(FarFieldColorCoCSize); + + float4 PixelColor = FarFieldColorCoC[px]; + float PixelCoC = PixelColor.w; + + float3 ResultColor = 0; + float Weight = 0; + + int TAP_COUNT = BLUR_TAP_COUNT; // Higher means less noise and make floodfilling easier after + + // Multiplying by PixelCoC guarantees a smooth evolution of the blur radius + // especially visible on plane (like the floor) where CoC slowly grows with the distance. + // This makes all the difference between a natural bokeh and some noticeable + // in-focus and out-of-focus layer blending + float radius = KernelSize.x * PixelCoC; + + if (PixelCoC > 0) { // Ignore any pixel not belonging to far field + + // Weighted average of the texture samples inside the bokeh pattern + // High radius and low sample count can create "gaps" which are fixed later (floodfill). + for (int u = 0; u < TAP_COUNT; ++u) + { + for (int v = 0; v < TAP_COUNT; ++v) + { + float2 uv = float2(u, v) / (TAP_COUNT - 1); // map to [0, 1] + uv = SquareToPolygonMapping( uv, KernelSize ) / float2(FarFieldColorCoCSize); // map to bokeh shape, then to texel size + uv = UVAndScreenPos.xy + radius * uv; + + float4 tapColor = FarFieldColorCoC.SampleLevel(linearClampSampler, uv, 0); //Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, uv, 0); + + // Weighted by CoC. Gives more influence to taps with a CoC higher than us. + float TapWeight = tapColor.w * saturate(1.0f - (PixelCoC - tapColor.w)); + + ResultColor += tapColor.xyz * TapWeight; + Weight += TapWeight; + } + } + if (Weight > 0) ResultColor /= Weight; + Weight = Weight / TAP_COUNT / TAP_COUNT; + } + + Weight = saturate(Weight * 10); // From CoC 0.1, completely rely on the far field layer and stop lerping with in-focus layer + float4 OutColor = float4(ResultColor, Weight); + + BlurredFarFieldColorAlpha[px] = OutColor; +} + +/* +Shader Resources: + Texture FarFieldColorCoC (as SRV) + Texture BlurredFarFieldColorAlpha (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/Common.hlsli b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/Common.hlsli new file mode 100644 index 00000000..d931bedb --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/Common.hlsli @@ -0,0 +1,84 @@ + +#define PI 3.14159265359f + +struct ViewStruct +{ + float DepthOfFieldFocalLength; + float DepthOfFieldFocalDistance; + float DepthOfFieldFocalRegion; + float DepthOfFieldNearTransitionRegion; + float DepthOfFieldFarTransitionRegion; + float DepthOfFieldScale; +}; + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +// Maps a unit square in [0, 1] to a unit disk in [-1, 1] +// Returns polar coordinates (radius, angle) +// Shirley 97 "A Low Distortion Map Between Disk and Square" +float2 UnitSquareToUnitDiskPolar(float2 uv) +{ + float radius; + float angle; + const float PI_BY_2 = 1.5707963f; // PI / 2 + const float PI_BY_4 = 0.785398f; // PI / 4 + const float EPSILON = 0.000001f; + + // Remap [0, 1] to [-1, 1] centered + float a = (2.0f * uv.x) - 1.0f; + float b = (2.0f * uv.y) - 1.0f; + + // Morph to unit disk + if (abs(a) > abs(b)) + { + // First region (left and right quadrants of the disk) + radius = a; + angle = b / (a + EPSILON) * PI_BY_4; + } + else + { + // Second region (top and bottom quadrants of the disk) + radius = b; + angle = PI_BY_2 - (a / (b + EPSILON) * PI_BY_4); + } + if (radius < 0) + { + radius *= -1.0f; + angle += PI; + } + return float2(radius, angle); +} +// Maps a unit square in [0, 1] to a unit disk in [-1, 1] +// Returns new cartesian coordinates (u,v) +float2 SquareToDiskMapping(float2 uv) { + float2 PolarCoord = UnitSquareToUnitDiskPolar(uv); + return float2(PolarCoord.x * cos(PolarCoord.y), PolarCoord.x * sin(PolarCoord.y)); +} + +// Remap a unit square in [0, 1] to a unit polygon in [-1, 1] +// Returns new cartesian coordinates (u,v) +float2 SquareToPolygonMapping(float2 uv, in float4 KernelSize) { + const float N = KernelSize.z; // Edge count of the polygon. + float2 PolarCoord = UnitSquareToUnitDiskPolar(uv); // (radius, angle) + + if (N >= 3.0f) + { + // Re-scale radius to match a polygon shape + // http://www.crytek.com/download/Sousa_Graphics_Gems_CryENGINE3.pdf + PolarCoord.x *= ( cos(PI / N) / ( cos(PolarCoord.y - (2.0f * PI / N) * floor((N*PolarCoord.y + PI) / 2.0f / PI ) ))); + + // Apply a rotation to the polygon shape. + PolarCoord.y += KernelSize.y; + } + + return float2(PolarCoord.x * cos(PolarCoord.y), PolarCoord.x * sin(PolarCoord.y)); +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/DownscaleTileMap_1_4.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/DownscaleTileMap_1_4.hlsl new file mode 100644 index 00000000..27262823 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/DownscaleTileMap_1_4.hlsl @@ -0,0 +1,22 @@ +// Unnamed technique, shader DownscaleTimeMapCS +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + float CoCs[4]; + + CoCs[0] = Source[px*2+uint2(0,0)]; + CoCs[1] = Source[px*2+uint2(1,0)]; + CoCs[2] = Source[px*2+uint2(0,1)]; + CoCs[3] = Source[px*2+uint2(1,1)]; + + Dest[px] = max( CoCs[0], max( CoCs[1], max( CoCs[2], CoCs[3] ) ) ); +} + +/* +Shader Resources: + Texture Source (as SRV) + Texture Dest (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/FloodFillFarCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/FloodFillFarCS.hlsl new file mode 100644 index 00000000..e8323e07 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/FloodFillFarCS.hlsl @@ -0,0 +1,88 @@ +// Unnamed technique, shader FloodFillFarCS +/*$(ShaderResources)*/ + +#include "Common.hlsli" + +#define FLOODFILL_TAP_COUNT /*$(Variable:FloodFillTapCount)*/ + +// .x : size of the bokeh blur radius in texel space +// .y : rotation in radius to apply to the bokeh shape +// .z : Number of edge of the polygon (number of blades). 0: circle. 4: square, 6: hexagon... +#define KernelSize /*$(Variable:KernelSize)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + uint2 ColorCocSize; + ColorCoc.GetDimensions(ColorCocSize.x, ColorCocSize.y); + + float2 UVAndScreenPos = (float2(px) + float2(0.5f, 0.5f)) / float2(ColorCocSize); + + #if COC_TILEMAP + + // pass through if this is disabled + if (!/*$(Variable:DoNearFieldFloodFill)*/) + { + BlurredFieldColorAlpha[px] = ColorCoc[px]; + return; + } + + #else + + // pass through if this is disabled + if (!/*$(Variable:DoFarFieldFloodFill)*/) + { + BlurredFieldColorAlpha[px] = ColorCoc[px]; + return; + } + + #endif + + float4 PixelColor = ColorCoc[px]; + float PixelCoC = PixelColor.w; + +#if COC_TILEMAP + // Use max CoC tilemap instead of the original pixel CoC for near field + PixelCoC = MaxCoCTileMap[px/4].r; +#endif + + float4 ResultColor = PixelColor; + + float radius = PixelCoC * 1.75f * KernelSize.x / 15.0f; + + int TAP_COUNT = FLOODFILL_TAP_COUNT; // Higher count improves the floodfill + + if (PixelCoC > 0) { // Early out if we're outside the field + + // McIntosh12 http://ivizlab.sfu.ca/papers/cgf2012.pdf + // Keep the maximum of all the samples + for (int u = 0; u < TAP_COUNT; ++u) + { + for (int v = 0; v < TAP_COUNT; ++v) + { + float2 uv = float2(u, v) / (TAP_COUNT - 1); // map to [0, 1] + uv = SquareToPolygonMapping( uv, KernelSize ) / float2(ColorCocSize); // map to bokeh shape, then to texel size + uv = UVAndScreenPos.xy + radius * uv; + + float4 tapColor = ColorCoc.SampleLevel(linearClampSampler, uv, 0);//Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, uv, 0); + ResultColor = max(ResultColor, tapColor); + } + } + } +#if COC_TILEMAP + float4 OutColor = ResultColor; +#else + // do not touch alpha of far field + float4 OutColor = float4(ResultColor.xyz, PixelCoC); +#endif + + BlurredFieldColorAlpha[px] = OutColor; +} + +/* +Shader Resources: + Texture ColorCoc (as SRV) + Texture MaxCoCTileMap (as SRV) + Texture BlurredFieldColorAlpha (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBlurCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBlurCS.hlsl new file mode 100644 index 00000000..069846d0 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBlurCS.hlsl @@ -0,0 +1,61 @@ +// Unnamed technique, shader NearBlur +/*$(ShaderResources)*/ + +#include "Common.hlsli" + +#define BLUR_TAP_COUNT /*$(Variable:BlurTapCount)*/ + +// .x : size of the bokeh blur radius in texel space +// .y : rotation in radius to apply to the bokeh shape +// .z : Number of edge of the polygon (number of blades). 0: circle. 4: square, 6: hexagon... +#define KernelSize /*$(Variable:KernelSize)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + uint2 NearFieldColorCoCBorderSize; + NearFieldColorCoCBorder.GetDimensions(NearFieldColorCoCBorderSize.x, NearFieldColorCoCBorderSize.y); + + float2 UVAndScreenPos = (float2(px) + float2(0.5f, 0.5f)) / float2(NearFieldColorCoCBorderSize); + + float4 PixelColor = NearFieldColorCoCBorder[px];// Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, UVAndScreenPos.xy, 0); + float PixelCoC = NearmaxCoCTilemap_1_8_Halo[px/4];// Texture2DSampleLevel(PostprocessInput1, PostprocessInput1Sampler, UVAndScreenPos.xy, 0); + + float3 ResultColor = 0; + float Weight = 0; + int TAP_COUNT = BLUR_TAP_COUNT; // Higher means less noise and make floodfilling easier after + + float radius = KernelSize.x * 0.7f * PixelCoC; + + if (PixelCoC > 0) { // Early exit based on MaxCoC tilemap + for (int u = 0; u < TAP_COUNT; ++u) + { + for (int v = 0; v < TAP_COUNT; ++v) + { + float2 uv = float2(u, v) / (TAP_COUNT - 1); // map to [0, 1] + uv = SquareToPolygonMapping( uv, KernelSize ) / float2(NearFieldColorCoCBorderSize); // map to bokeh shape, then to texel size + uv = UVAndScreenPos.xy + radius * uv; + + float4 tapColor = NearFieldColorCoCBorder.SampleLevel(linearClampSampler, uv, 0);// Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, uv, 0); + float TapWeight = saturate(tapColor.w * 10.0f); // From CoC 0.1 rely only on the near field and stop lerping with in-focus area + + ResultColor += tapColor.xyz * TapWeight; + Weight += TapWeight; + } + } + + ResultColor /= (Weight + 0.0000001f); + Weight /= (TAP_COUNT * TAP_COUNT); + } + float4 OutColor = float4(ResultColor, Weight); + + NearFieldColorCoCBorderBlurred[px] = OutColor; +} + +/* +Shader Resources: + Texture NearFieldColorCoCBorder (as SRV) + Count NearmaxCoCTilemap_1_8_Halo (as Count) + Texture NearFieldColorCoCBorderBlurred (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBorderCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBorderCS.hlsl new file mode 100644 index 00000000..7b62503e --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearBorderCS.hlsl @@ -0,0 +1,38 @@ +// Unnamed technique, shader NearBorderCS +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + float4 PixelColor = NearFieldColorCoC[px];// Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, tapUV, 0); + + if (PixelColor.w == 0) // Only fill the empty areas around near field + { + PixelColor = 0; + float Weight = 0; + int RADIUS_TAPS = 1; + for (int u = -RADIUS_TAPS; u <= RADIUS_TAPS; ++u) + { + for (int v = -RADIUS_TAPS; v <= RADIUS_TAPS; ++v) + { + float4 tapValue = NearFieldColorCoC[px + int2(u,v)];//Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, tapUV + float2(u,v) * PostprocessInput0Size.zw, 0); + float tapWeight = tapValue.w == 0.0f? 0.0f : 1.0f; + PixelColor += tapWeight * tapValue; + Weight += tapWeight; + } + } + PixelColor /= (Weight + 0.0000001f); + PixelColor.w = 0; + } + + float4 OutColor = PixelColor; + + NearFieldColorCoCBorder[px] = OutColor; +} + +/* +Shader Resources: + Texture NearFieldColorCoC (as SRV) + Texture NearFieldColorCoCBorder (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearHaloCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearHaloCS.hlsl new file mode 100644 index 00000000..6de37ecd --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/NearHaloCS.hlsl @@ -0,0 +1,37 @@ +// Unnamed technique, shader NearHaloCS +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + float PixelColor = NearMaxCocTilemap_1_8[px];//Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, tapUV, 0); + + if (PixelColor == 0) // Only fill the empty areas around near field + { + PixelColor = 0; + float Weight = 0; + int RADIUS_TAPS = 4; // 8x8 taps, but shouldn't be heavy at such low resolution + for (int u = -RADIUS_TAPS; u <= RADIUS_TAPS; ++u) + { + for (int v = -RADIUS_TAPS; v <= RADIUS_TAPS; ++v) + { + float tapValue = NearMaxCocTilemap_1_8[int2(px) + int2(u, v)];//Texture2DSampleLevel(PostprocessInput0, PostprocessInput0Sampler, tapUV + float2(u,v) * PostprocessInput0Size.zw, 0); + float tapWeight = tapValue == 0.0f? 0.0f : 1.0f; + PixelColor += tapWeight * tapValue; + Weight += tapWeight; + } + } + PixelColor /= (Weight + 0.000001f); + } + + float4 OutColor = PixelColor; + + NearMaxCocTilemap_1_8_Halo[px] = OutColor; +} + +/* +Shader Resources: + Texture NearMaxCocTilemap_1_8 (as SRV) + Texture NearMaxCocTilemap_1_8_Halo (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/RecombineCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/RecombineCS.hlsl new file mode 100644 index 00000000..1b2900d3 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/RecombineCS.hlsl @@ -0,0 +1,135 @@ +// Unnamed technique, shader RecombineCS +/*$(ShaderResources)*/ + +#include "Common.hlsli" + +// Blend in-focus / far / near layers on the top of each others +float3 GetCombinedLayerColor(uint2 px, float2 uv, in ViewStruct View) +{ + // Set FadePower to 1.0f in the next line to be physically correct, + // but some in-focus silhouette might become visible at the border of the + // near field, where the gradient smoothly fades alpha to 0. [0 -> 0.5 -> 1] + // Limitation of screen-space effect: we don't have access to the actual color occluded by near field meshes. + // This makes the near-field fading gradient more aggressive [0 -> 1 -> 1] to hide any sharp silhouette. + float FadePower = 2.0f; +#if 1 // Optimized version using early-out to avoid unnecessary texture fetches -> ~25% speed-up in reference scene. + + float4 NearColor = /*$(Variable:DoNearField)*/ ? NearField.SampleLevel(linearClampSampler, uv, 0) : float4(0.0f, 0.0f, 0.0f, 0.0f);// Texture2DSampleLevel(PostprocessInput2, PostprocessInput2Sampler, uv, 0); + + NearColor.w = saturate(NearColor.w * FadePower); + + // Pure near field, early exit + if (NearColor.w == 1.0f) + { + return NearColor.rgb; + } + + float4 FarColor = /*$(Variable:DoFarField)*/ ? FarField.SampleLevel(linearClampSampler, uv, 0) : float4(0.0f, 0.0f, 0.0f, 0.0f);// Texture2DSampleLevel(PostprocessInput1, PostprocessInput1Sampler, uv, 0); + + // Original CoC to guarantee crisp edge of in-focus over far-field + //float2 PixelPosCenter = SvPosition.xy; + //float2 FullResUV = PixelPosCenter * PostprocessInput0Size.zw; + float SceneDepth = Depth[px];// CalcSceneDepth(FullResUV); + + bool isInFocus = (SceneDepth >= View.DepthOfFieldFocalDistance) && + (SceneDepth < View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion); + + if (!isInFocus) { + // Pure far field without any bleeding from near field, early exit + if (FarColor.w == 1.0f && NearColor.w == 0.0f ) + { + return FarColor.rgb; + } + + // Blending only between far and near + if (FarColor.w == 1.0f) { + return float3( NearColor.w * (NearColor.rgb) + (1.0f - NearColor.w) * FarColor.rgb ); + } + } else { + // Pixel was originally in focus, background should never bleed onto it + FarColor.w = 0; + } + + // Worst case: 3 layer merge + float3 FocusColor = Color[px].rgb;// Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, uv).rgb; + + float3 Result = FarColor.w * FarColor.rgb + (1.0f - FarColor.w) * FocusColor; + Result = NearColor.w * (NearColor.rgb) + (1.0f - NearColor.w) * Result; + + return Result; + +#else // Original generic version + + float3 FocusColor = Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, uv).rgb; + float4 FarColor = Texture2DSampleLevel(PostprocessInput1, PostprocessInput1Sampler, uv, 0); + float4 NearColor = Texture2DSampleLevel(PostprocessInput2, PostprocessInput2Sampler, uv, 0); + + // Original CoC to guarantee crisp edge of in-focus over far-field + float2 PixelPosCenter = SvPosition.xy; + float2 FullResUV = PixelPosCenter * PostprocessInput0Size.zw; + float SceneDepth = CalcSceneDepth(FullResUV); + + bool isInFocus = (SceneDepth >= View.DepthOfFieldFocalDistance) && + (SceneDepth < View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion); + if (isInFocus) FarColor.w = 0; + + // Alpha composite far field on the top of the original scene. + float3 Result = FarColor.w * FarColor.rgb + (1.0f - FarColor.w) * FocusColor; + + // Alpha composite on the near field + if (NearColor.w > 0) { + float blendFactor = saturate(NearColor.w * FadePower); + Result = blendFactor * (NearColor.rgb) + (1.0f - blendFactor) * Result; + } + + return Result; +#endif + +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + ViewStruct View = (ViewStruct)0; + View.DepthOfFieldFocalLength = /*$(Variable:FocalLength)*/; + View.DepthOfFieldFocalDistance = /*$(Variable:FocalDistance)*/; + View.DepthOfFieldFocalRegion = /*$(Variable:FocalRegion)*/; + View.DepthOfFieldNearTransitionRegion = /*$(Variable:NearTransitionRegion)*/; + View.DepthOfFieldFarTransitionRegion = /*$(Variable:FarTransitionRegion)*/; + View.DepthOfFieldScale = /*$(Variable:Scale)*/; + uint2 px = DTid.xy; + + uint2 OutputSize; + Output.GetDimensions(OutputSize.x, OutputSize.y); + float2 uv = (float2(px) + float2(0.5f, 0.5f)) / float2(OutputSize); + + /* +#if RECOMBINE_METHOD == 2 // Separate translucency + // SceneColor in full res + float2 PixelPosCenter = SvPosition.xy; + float2 FullResUV = PixelPosCenter * PostprocessInput0Size.zw; + float4 SeparateTranslucency = UpsampleSeparateTranslucency(SvPosition.xy, FullResUV, PostprocessInput3, PostprocessInput3Size.zw); +#endif +*/ + float3 RecombinedLayersColor = GetCombinedLayerColor(px, uv, View); + +/* +#if RECOMBINE_METHOD == 2 + // Separate translucency as premultiplied alpha + RecombinedLayersColor.rgb = RecombinedLayersColor.rgb * SeparateTranslucency.a + SeparateTranslucency.rgb; +#endif +*/ + + if (/*$(Variable:sRGB)*/) + RecombinedLayersColor = LinearToSRGB(RecombinedLayersColor); + + Output[px] = float4(RecombinedLayersColor, 1.0f); +} + +/* +Shader Resources: + Texture Color (as SRV) + Texture FarField (as SRV) + Texture NearField (as SRV) + Texture Depth (as SRV) + Texture Output (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/SetupCS.hlsl b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/SetupCS.hlsl new file mode 100644 index 00000000..ffbfd0aa --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/SetupCS.hlsl @@ -0,0 +1,176 @@ +// Unnamed technique, shader SetupCS +/*$(ShaderResources)*/ + +// An implementation of GatherDOF2018: https://www.adriancourreges.com/blog/2018/12/02/ue4-optimized-post-effects/ + +#include "Common.hlsli" + +// Computed the "Circle Of Confusion" radius for "Depth of Field" +// Formula can be found in many places e.g. http://http.developer.nvidia.com/GPUGems/gpugems_ch23.html +// @param SceneDepth +// @return 0..1 0=in focus, 1:max blurry +float ComputeCircleOfConfusion(float SceneDepth, in ViewStruct View) +{ + // artificial area where all content is in focus (starting at FocalLength, ending at FocalLength+FocalRegion) + if(SceneDepth > View.DepthOfFieldFocalDistance) + { + SceneDepth = View.DepthOfFieldFocalDistance + max(0, SceneDepth - View.DepthOfFieldFocalDistance - View.DepthOfFieldFocalRegion); + } + + // depth of the pixel in unreal units + float D = SceneDepth; + // e.g. Focal length in mm (Camera property e.g. 75mm) + float F = View.DepthOfFieldFocalLength; + // Plane in Focus in unreal units + float P = View.DepthOfFieldFocalDistance; + // Camera property e.g. 0.5f, like aperture + float Aperture = View.DepthOfFieldScale; + + + // convert unreal units (100=1m) to mm + P *= 0.001f / 100.0f; + D *= 0.001f / 100.0f; +/* + float Div = abs(D * (P - F)); + // clamp crazy numbers +// Div = max(0.01f, Div); + float CoCRadiusFactor = Aperture * F * abs(P - D) / Div; + return saturate(CoCRadiusFactor); +*/ + // note: F has almost no effect + float CoCRadius = Aperture * F * (P - D) / (D * (P - F)); + + return saturate(abs(CoCRadius)); +} + +// TODO Taken from BokehDOF. Centralize! +// @return x:layer in front of focal plane, y: layer behind focal plane 1-x-y:layer in focus +float2 ComputeLayerContributions(float Depth, ViewStruct View) +{ + float Front = saturate((View.DepthOfFieldFocalDistance - Depth) / View.DepthOfFieldNearTransitionRegion); + float Back = saturate((Depth - View.DepthOfFieldFocalDistance - View.DepthOfFieldFocalRegion) / max(View.DepthOfFieldFarTransitionRegion, 0.0001f)); + return float2(Front, Back); +} + +// TODO Taken from BokehDOF. Centralize! +float4 CommonDOFSetup(/*in float2 CenterUV*/ in uint2 px, out bool bFrontLayer, out float4 Mask, ViewStruct View) +{ + /* + float2 Offset = PostprocessInput0Size.zw; + + float2 UV[4]; + + // no filtering (2x2 kernel) to get no leaking in Depth of Field + UV[0] = CenterUV + Offset * float2(-0.5f, -0.5f); + UV[1] = CenterUV + Offset * float2( 0.5f, -0.5f); + UV[2] = CenterUV + Offset * float2(-0.5f, 0.5f); + UV[3] = CenterUV + Offset * float2( 0.5f, 0.5f); + */ + uint2 samplePoints[4]; + samplePoints[0] = px*2 + uint2(0,0); + samplePoints[1] = px*2 + uint2(1,0); + samplePoints[2] = px*2 + uint2(0,1); + samplePoints[3] = px*2 + uint2(1,1); + + float4 ColorAndDepth[4]; + float2 Layer[4]; + + for(uint i = 0; i < 4; ++i) + { + // clamping to a small number fixes black dots appearing (denorms?, 0 doesn't fix it) + ColorAndDepth[i].rgb = max(float3(0.0001f, 0.0001f, 0.0001f), Color[samplePoints[i]].rgb /*Texture2DSample(PostprocessInput0, PostprocessInput0Sampler, UV[i]).rgb*/); + ColorAndDepth[i].a = Depth[samplePoints[i]]; + Layer[i] = ComputeLayerContributions(ColorAndDepth[i].a, View); + } + + float2 LayerSum = Layer[0] + Layer[1] + Layer[2] + Layer[3]; + bFrontLayer = LayerSum.x > LayerSum.y; + + Mask = bFrontLayer ? + float4(Layer[0].x, Layer[1].x, Layer[2].x, Layer[3].x) : + float4(Layer[0].y, Layer[1].y, Layer[2].y, Layer[3].y); + + float SumMask = dot(Mask, 1); + + float4 OutColor; + + if(SumMask > 0.001f) + { + OutColor = ( + ColorAndDepth[0] * Mask.x + + ColorAndDepth[1] * Mask.y + + ColorAndDepth[2] * Mask.z + + ColorAndDepth[3] * Mask.w ) / SumMask; + } + else + { + OutColor = ColorAndDepth[0]; + } + return OutColor; +} + + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + // ================================================ + // Our setup code + uint2 px = DTid.xy; + float4 OutColor0 = float4(0.0f, 0.0f, 0.0f, 0.0f); + float4 OutColor1 = float4(0.0f, 0.0f, 0.0f, 0.0f); + float4 OutColor2 = float4(0.0f, 0.0f, 0.0f, 0.0f); + + ViewStruct View = (ViewStruct)0; + View.DepthOfFieldFocalLength = /*$(Variable:FocalLength)*/; + View.DepthOfFieldFocalDistance = /*$(Variable:FocalDistance)*/; + View.DepthOfFieldFocalRegion = /*$(Variable:FocalRegion)*/; + View.DepthOfFieldNearTransitionRegion = /*$(Variable:NearTransitionRegion)*/; + View.DepthOfFieldFarTransitionRegion = /*$(Variable:FarTransitionRegion)*/; + View.DepthOfFieldScale = /*$(Variable:Scale)*/; + // ================================================ + + // unused for this pass + bool bFrontLayer = false; + float4 Mask = float4(0.0f, 0.0f, 0.0f, 0.0f); + + float4 SceneColorAndDepth = CommonDOFSetup(px, bFrontLayer, Mask, View); + + // clamp to avoid artifacts from exceeding fp16 through framebuffer blending of multiple very bright lights + SceneColorAndDepth.rgb = min(float3(256 * 256, 256 * 256, 256 * 256), SceneColorAndDepth.rgb); + + float SceneDepth = SceneColorAndDepth.a; + float CircleOfConfusion = ComputeCircleOfConfusion(SceneDepth, View); + + if (SceneDepth < View.DepthOfFieldFocalDistance) { + // Near + OutColor0 = float4(0, 0, 0, 0); + OutColor1 = float4(SceneColorAndDepth.rgb, CircleOfConfusion); + OutColor2 = CircleOfConfusion; // Separate CoC to build Max TileMap + } + else if (SceneDepth >= View.DepthOfFieldFocalDistance + View.DepthOfFieldFocalRegion) + { + // Far + OutColor0 = float4(SceneColorAndDepth.rgb, CircleOfConfusion); + OutColor1 = float4(0, 0, 0, 0); + OutColor2 = 0.0f; + } + else + { + // In-focus (inside focal region) + OutColor0 = float4(0, 0, 0, 0); + OutColor1 = float4(0, 0, 0, 0); + OutColor2 = 0.0f; + } + + FarFieldColorCoC[px] = OutColor0; + NearFieldColorCoC[px] = OutColor1; + NearMaxCocTilemap[px] = OutColor2; +} + +/* +Shader Resources: + Texture Color (as SRV) + Texture Depth (as SRV) + Texture FarFieldColorCoC (as UAV) + Texture NearFieldColorCoC (as UAV) + Texture NearMaxCocTilemap (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/dof.gg b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/dof.gg new file mode 100644 index 00000000..de4e3cfc --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/dof.gg @@ -0,0 +1,1058 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "FocalDistance", + "comment": "Anything closer than this is considered near field", + "type": "Float", + "dflt": "500.0f", + "visibility": "User" + }, + { + "name": "FocalRegion", + "comment": "The size in world units of the middle range which is in focus", + "type": "Float", + "dflt": "100.0f", + "visibility": "User" + }, + { + "name": "FocalLength", + "comment": "Focal length in mm (Camera property e.g. 75mm)", + "type": "Float", + "dflt": "75.0f", + "visibility": "User" + }, + { + "name": "NearTransitionRegion", + "comment": "Fade distance in world units", + "type": "Float", + "dflt": "50", + "visibility": "User" + }, + { + "name": "FarTransitionRegion", + "comment": "Fade distance in world units", + "type": "Float", + "dflt": "200", + "visibility": "User" + }, + { + "name": "Scale", + "comment": "Camera property e.g. 0.5f, like aperture", + "type": "Float", + "dflt": "0.5f", + "visibility": "User" + }, + { + "name": "DoFarField", + "comment": "Whether or not to do the far field", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "DoFarFieldFloodFill", + "comment": "Whether to do flood fill on the far field", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "DoNearField", + "comment": "Whether or not to do the near field", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "DoNearFieldFloodFill", + "comment": "Whether to do flood fill on the near field", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "KernelSize", + "comment": "x = size of the bokeh blur radius in texel space. y = rotation in radius to apply to the bokeh shape. z = Number of edge of the polygon (number of blades). 0: circle. 4: square, 6: hexagon...", + "type": "Float4", + "dflt": "10.0f, 15.0f, 5.0f, 0.0f", + "visibility": "User" + }, + { + "name": "BlurTapCount", + "comment": "8 for high quality, 6 for low quality. Used in a double for loop, so it's this number squared.", + "type": "Uint", + "dflt": "8", + "visibility": "User" + }, + { + "name": "FloodFillTapCount", + "comment": "4 for high quality, 3 for low quality. Used in a double for loop, so it's this number squared.", + "type": "Uint", + "dflt": "4", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "Set to true if the input texture is an sRGB texture", + "type": "Bool", + "dflt": "true", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "SetupCS", + "fileName": "SetupCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Color", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Depth", + "type": "Texture", + "access": "SRV", + "texture": { + "viewType": "Float" + } + }, + { + "name": "FarFieldColorCoC", + "type": "Texture", + "access": "UAV" + }, + { + "name": "NearFieldColorCoC", + "type": "Texture", + "access": "UAV" + }, + { + "name": "NearMaxCocTilemap", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "BlurFarCS", + "fileName": "BlurFarCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "FarFieldColorCoC", + "type": "Texture", + "access": "SRV" + }, + { + "name": "BlurredFarFieldColorAlpha", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearClampSampler", + "addressMode": "Clamp" + } + ] + }, + { + "name": "FloodFillFarCS", + "fileName": "FloodFillFarCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "MaxCoCTileMap", + "type": "Texture", + "access": "SRV" + }, + { + "name": "ColorCoc", + "type": "Texture", + "access": "SRV" + }, + { + "name": "BlurredFieldColorAlpha", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearClampSampler", + "addressMode": "Clamp" + } + ] + }, + { + "name": "DownscaleTileMapCS", + "fileName": "DownscaleTileMap_1_4.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Source", + "type": "Texture", + "access": "SRV", + "texture": { + "viewType": "Float" + } + }, + { + "name": "Dest", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float" + } + } + ] + }, + { + "name": "NearHaloCS", + "fileName": "NearHaloCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "NearMaxCocTilemap_1_8", + "type": "Texture", + "access": "SRV", + "texture": { + "viewType": "Float" + } + }, + { + "name": "NearMaxCocTilemap_1_8_Halo", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float" + } + } + ] + }, + { + "name": "NearBorderCS", + "fileName": "NearBorderCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "NearFieldColorCoC", + "type": "Texture", + "access": "SRV" + }, + { + "name": "NearFieldColorCoCBorder", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "NearBlur", + "fileName": "NearBlurCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "NearFieldColorCoCBorder", + "type": "Texture", + "access": "SRV" + }, + { + "name": "NearmaxCoCTilemap_1_8_Halo", + "type": "Texture", + "access": "SRV", + "texture": { + "viewType": "Float" + } + }, + { + "name": "NearFieldColorCoCBorderBlurred", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearClampSampler", + "addressMode": "Clamp" + } + ] + }, + { + "name": "RecombineCS", + "fileName": "RecombineCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "NearField", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Color", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Depth", + "type": "Texture", + "access": "SRV", + "texture": { + "viewType": "Float" + } + }, + { + "name": "FarField", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearClampSampler", + "addressMode": "Clamp" + } + ] + } + ], + "fileCopies": [ + { + "fileName": "Common.hlsli", + "type": "Shader" + } + ], + "nodes": [ + { + "resourceTexture": { + "name": "Color", + "editorPos": [ + -165.0, + -62.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "LinearDepth", + "editorPos": [ + -165.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + 1595.0, + 66.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Color" + } + }, + "size": { + "node": { + "name": "Color" + } + } + } + }, + { + "actionComputeShader": { + "name": "Setup", + "editorPos": [ + 5.0, + -58.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "Color", + "dstPin": "resource" + }, + { + "srcPin": "Depth", + "dstNode": "LinearDepth", + "dstPin": "resource" + }, + { + "srcPin": "FarFieldColorCoC", + "dstNode": "FarFieldColorCoC", + "dstPin": "resource" + }, + { + "srcPin": "NearFieldColorCoC", + "dstNode": "NearFieldColorCoC", + "dstPin": "resource" + }, + { + "srcPin": "NearMaxCocTilemap", + "dstNode": "NearMaxCocTilemap", + "dstPin": "resource" + } + ], + "shader": { + "name": "SetupCS" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "resourceTexture": { + "name": "FarFieldColorCoC", + "editorPos": [ + -191.0, + 34.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "resourceTexture": { + "name": "NearFieldColorCoC", + "editorPos": [ + -201.0, + 82.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "resourceTexture": { + "name": "NearMaxCocTilemap", + "editorPos": [ + -204.0, + 130.0 + ], + "format": { + "format": "R8_Unorm" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "BlurFar", + "editorPos": [ + 277.0, + 172.0 + ], + "condition": { + "variable1": "DoFarField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "FarFieldColorCoC", + "dstNode": "Setup", + "dstPin": "FarFieldColorCoC" + }, + { + "srcPin": "BlurredFarFieldColorAlpha", + "dstNode": "BlurredFarFieldColorAlpha", + "dstPin": "resource" + } + ], + "shader": { + "name": "BlurFarCS" + }, + "dispatchSize": { + "node": { + "name": "FarFieldColorCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "BlurredFarFieldColorAlpha", + "editorPos": [ + 27.0, + 290.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "FloodFillFar", + "editorPos": [ + 597.0, + 114.0 + ], + "condition": { + "variable1": "DoFarField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "ColorCoc", + "dstNode": "BlurFar", + "dstPin": "BlurredFarFieldColorAlpha" + }, + { + "srcPin": "MaxCoCTileMap", + "dstNode": "Setup", + "dstPin": "NearMaxCocTilemap" + }, + { + "srcPin": "BlurredFieldColorAlpha", + "dstNode": "FloodFilledBlurredFarFieldColorAlpha", + "dstPin": "resource" + } + ], + "shader": { + "name": "FloodFillFarCS" + }, + "dispatchSize": { + "node": { + "name": "FarFieldColorCoC" + } + }, + "defines": [ + { + "name": "COC_TILEMAP", + "value": "0" + } + ] + } + }, + { + "resourceTexture": { + "name": "FloodFilledBlurredFarFieldColorAlpha", + "editorPos": [ + 268.0, + 274.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "DownscaleTileMap_1_4", + "editorPos": [ + 863.0, + 229.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Source", + "dstNode": "FloodFillFar", + "dstPin": "MaxCoCTileMap" + }, + { + "srcPin": "Dest", + "dstNode": "NearMaxCocTilemap_1_4", + "dstPin": "resource" + } + ], + "shader": { + "name": "DownscaleTileMapCS" + }, + "dispatchSize": { + "node": { + "name": "NearMaxCocTilemap_1_4" + } + } + } + }, + { + "resourceTexture": { + "name": "NearMaxCocTilemap_1_4", + "editorPos": [ + 632.0, + 341.0 + ], + "format": { + "format": "R8_Unorm" + }, + "size": { + "node": { + "name": "NearMaxCocTilemap" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "resourceTexture": { + "name": "NearMaxCocTilemap_1_8", + "editorPos": [ + 856.0, + 341.0 + ], + "format": { + "format": "R8_Unorm" + }, + "size": { + "node": { + "name": "NearMaxCocTilemap_1_4" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "DownscaleTileMap_1_8", + "editorPos": [ + 1077.0, + 229.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Source", + "dstNode": "DownscaleTileMap_1_4", + "dstPin": "Dest" + }, + { + "srcPin": "Dest", + "dstNode": "NearMaxCocTilemap_1_8", + "dstPin": "resource" + } + ], + "shader": { + "name": "DownscaleTileMapCS" + }, + "dispatchSize": { + "node": { + "name": "NearMaxCocTilemap_1_8" + } + } + } + }, + { + "actionComputeShader": { + "name": "NearHalo", + "editorPos": [ + 1317.0, + 226.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "NearMaxCocTilemap_1_8", + "dstNode": "DownscaleTileMap_1_8", + "dstPin": "Dest" + }, + { + "srcPin": "NearMaxCocTilemap_1_8_Halo", + "dstNode": "NearMaxCocTilemap_1_8_Halo", + "dstPin": "resource" + } + ], + "shader": { + "name": "NearHaloCS" + }, + "dispatchSize": { + "node": { + "name": "NearMaxCocTilemap_1_8" + } + } + } + }, + { + "resourceTexture": { + "name": "NearMaxCocTilemap_1_8_Halo", + "editorPos": [ + 1064.0, + 341.0 + ], + "format": { + "node": { + "name": "NearMaxCocTilemap_1_8" + } + }, + "size": { + "node": { + "name": "NearMaxCocTilemap_1_8" + } + } + } + }, + { + "actionComputeShader": { + "name": "NearBorder", + "editorPos": [ + 797.0, + -308.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "NearFieldColorCoCBorder", + "dstNode": "NearFieldColorCoCBorder", + "dstPin": "resource" + }, + { + "srcPin": "NearFieldColorCoCBorder" + }, + { + "srcPin": "NearFieldColorCoC", + "dstNode": "Setup", + "dstPin": "NearFieldColorCoC" + } + ], + "shader": { + "name": "NearBorderCS" + }, + "dispatchSize": { + "node": { + "name": "NearFieldColorCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "NearFieldColorCoCBorder", + "editorPos": [ + 576.0, + -193.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "NearBlur", + "editorPos": [ + 1109.0, + -308.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "NearFieldColorCoCBorderBlurred", + "dstNode": "NearFieldColorCoCBorderBlurred", + "dstPin": "resource" + }, + { + "srcPin": "NearmaxCoCTilemap_1_8_Halo", + "dstNode": "NearHalo", + "dstPin": "NearMaxCocTilemap_1_8_Halo" + }, + { + "srcPin": "NearFieldColorCoCBorderBlurred" + }, + { + "srcPin": "NearFieldColorCoCBorder", + "dstNode": "NearBorder", + "dstPin": "NearFieldColorCoCBorder" + } + ], + "shader": { + "name": "NearBlur" + }, + "dispatchSize": { + "node": { + "name": "NearFieldColorCoCBorder" + } + } + } + }, + { + "resourceTexture": { + "name": "NearFieldColorCoCBorderBlurred", + "editorPos": [ + 789.0, + -193.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "FloodFillNear", + "editorPos": [ + 1434.0, + -289.0 + ], + "condition": { + "variable1": "DoNearField", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "ColorCoc", + "dstNode": "NearBlur", + "dstPin": "NearFieldColorCoCBorderBlurred" + }, + { + "srcPin": "MaxCoCTileMap", + "dstNode": "NearBlur", + "dstPin": "NearmaxCoCTilemap_1_8_Halo" + }, + { + "srcPin": "BlurredFieldColorAlpha", + "dstNode": "FloodFilledBlurredNearFieldColorAlpha", + "dstPin": "resource" + } + ], + "shader": { + "name": "FloodFillFarCS" + }, + "dispatchSize": { + "node": { + "name": "FarFieldColorCoC" + } + }, + "defines": [ + { + "name": "COC_TILEMAP", + "value": "1" + } + ] + } + }, + { + "resourceTexture": { + "name": "FloodFilledBlurredNearFieldColorAlpha", + "editorPos": [ + 1112.0, + -177.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 2, + 2, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "Recombine", + "editorPos": [ + 1781.0, + -87.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "Setup", + "dstPin": "Color" + }, + { + "srcPin": "FarField", + "dstNode": "FloodFillFar", + "dstPin": "BlurredFieldColorAlpha" + }, + { + "srcPin": "NearField", + "dstNode": "FloodFillNear", + "dstPin": "BlurredFieldColorAlpha" + }, + { + "srcPin": "Output", + "dstNode": "Output", + "dstPin": "resource" + }, + { + "srcPin": "Depth", + "dstNode": "Setup", + "dstPin": "Depth" + } + ], + "shader": { + "name": "RecombineCS" + }, + "dispatchSize": { + "node": { + "name": "Output" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/GatherDOF2018/readme.txt b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/readme.txt new file mode 100644 index 00000000..35be8397 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/GatherDOF2018/readme.txt @@ -0,0 +1,3 @@ +Implementation of GatherDOF - the non TAA path +by Adrian Courrèges December 2018 +https://www.adriancourreges.com/blog/2018/12/02/ue4-optimized-post-effects/ \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.gg b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.gg new file mode 100644 index 00000000..0d611f15 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.gg @@ -0,0 +1,147 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "MaxBlurSize", + "comment": "Maximum radius of the CoC", + "type": "Float", + "dflt": "20.0f", + "visibility": "User" + }, + { + "name": "FocalLength", + "comment": "How far from the camera should be in focus", + "type": "Float", + "dflt": "1.0f", + "visibility": "User" + }, + { + "name": "FocusScale", + "comment": "How quickly the CoC scales over distance", + "type": "Float", + "dflt": "100.0f", + "visibility": "User" + }, + { + "name": "RadiusScale", + "comment": "How fast the points spiral out. smaller = nicer. larger = faster.", + "type": "Float", + "dflt": "0.5f", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "Set to true if the input texture is an sRGB texture", + "type": "Bool", + "dflt": "true", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "DOF", + "fileName": "dof.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Color", + "type": "Texture", + "access": "SRV" + }, + { + "name": "LinearDepth", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "DOF", + "editorPos": [ + 13.0, + -21.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "Color", + "dstPin": "resource" + }, + { + "srcPin": "LinearDepth", + "dstNode": "LinearDepth", + "dstPin": "resource" + }, + { + "srcPin": "Output", + "dstNode": "Output", + "dstPin": "resource" + } + ], + "shader": { + "name": "DOF" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "resourceTexture": { + "name": "Color", + "editorPos": [ + -197.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "LinearDepth", + "editorPos": [ + -197.0, + 50.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + -181.0, + 114.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Color" + } + }, + "size": { + "node": { + "name": "Color" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.hlsl b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.hlsl new file mode 100644 index 00000000..65ae2052 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/dof.hlsl @@ -0,0 +1,71 @@ +// Unnamed technique, shader DOF +/*$(ShaderResources)*/ + +// Implementation of "Bokeh depth of field in a single pass" +// https://blog.voxagon.se/2018/05/04/bokeh-depth-of-field-in-single-pass.html + +static const float GOLDEN_ANGLE = 2.39996323; + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +float getBlurSize(float depth, float focusPoint, float focusScale) +{ + float coc = clamp((1.0 / focusPoint - 1.0 / depth)*focusScale, -1.0, 1.0); + return abs(coc) * /*$(Variable:MaxBlurSize)*/; +} + +float3 depthOfField(uint2 texCoord, float focusPoint, float focusScale) +{ + uint2 ColorSize; + Color.GetDimensions(ColorSize.x, ColorSize.y); + + float centerDepth = LinearDepth[texCoord].r; + float centerSize = getBlurSize(centerDepth, focusPoint, focusScale); + float3 color = Color[texCoord].rgb; + float tot = 1.0; + float radius = /*$(Variable:RadiusScale)*/; + for (float ang = 0.0; radius centerDepth) + sampleSize = clamp(sampleSize, 0.0, centerSize*2.0); + float m = smoothstep(radius-0.5, radius+0.5, sampleSize); + color += lerp(color/tot, sampleColor, m); + tot += 1.0; radius += /*$(Variable:RadiusScale)*//radius; + } + + return color /= tot; +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = uint2(DTid.xy); + + float3 output = depthOfField(px, /*$(Variable:FocalLength)*/, /*$(Variable:FocusScale)*/); + + if (/*$(Variable:sRGB)*/) + output = LinearToSRGB(output); + + Output[px] = float4(output, 1.0f); + +} + +/* +Shader Resources: + Texture Color (as SRV) + Texture LinearDepth (as SRV) + Texture output (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/Gustafsson2018/readme.txt b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/readme.txt new file mode 100644 index 00000000..eeeda40b --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/Gustafsson2018/readme.txt @@ -0,0 +1,4 @@ +An implementation of "Bokeh depth of field in a single pass" +by Dennis Gustafsson +May 4, 2018 +https://blog.voxagon.se/2018/05/04/bokeh-depth-of-field-in-single-pass.html \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof.gg b/Techniques/PostProcessing/DepthOfField/IW2007/dof.gg new file mode 100644 index 00000000..c5bab3e6 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof.gg @@ -0,0 +1,502 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "DepthScale", + "comment": "Divides EqNear and EqFar by this amount. Useful for large scenes to not work with very tiny numbers.", + "type": "Float", + "dflt": "1.0", + "visibility": "User" + }, + { + "name": "EqNear", + "comment": "CoC = (EqWorld.x * depth + EqWorld.y)", + "type": "Float2", + "visibility": "User" + }, + { + "name": "EqFar", + "comment": "CoC = (EqFar.x * depth + EqFar.y)", + "type": "Float2", + "visibility": "User" + }, + { + "name": "FarToNearRadiusRatio", + "type": "Float", + "dflt": "1.0", + "visibility": "User" + }, + { + "name": "fadeDistances", + "comment": "Let the unblurred sample to small blur fade happen over distance d0, the small to medium blur over distance d1, and the medium to large blur over distance d2, where d0 + d1 + d2 = 1.", + "type": "Float3", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "Set to true if the input texture is an sRGB texture", + "type": "Bool", + "dflt": "true", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "DownSampleCoC", + "fileName": "dof_downsample_coc.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Color", + "type": "Texture", + "access": "SRV" + }, + { + "name": "LinearDepth", + "type": "Texture", + "access": "SRV" + }, + { + "name": "DownsampledCoC", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearWrapSampler" + } + ] + }, + { + "name": "GaussBlur", + "fileName": "dof_gauss_blur.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "DownsampledCoC", + "type": "Texture", + "access": "SRV" + }, + { + "name": "BlurredDownsampledCoC", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "CalculateNearCoC", + "fileName": "dof_calculate_near_coc.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "shrunkSampler", + "type": "Texture", + "access": "SRV" + }, + { + "name": "blurredSampler", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "BlurNearCoC", + "fileName": "dof_blur_near_coc.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "CalculatedNearCoC", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearClampSampler", + "addressMode": "Clamp" + } + ] + }, + { + "name": "ApplyDOF", + "fileName": "dof_apply_dof.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Color", + "type": "Texture", + "access": "SRV" + }, + { + "name": "LinearDepth", + "type": "Texture", + "access": "SRV" + }, + { + "name": "LargeBlur", + "type": "Texture", + "access": "SRV" + }, + { + "name": "SmallBlur", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ], + "samplers": [ + { + "name": "linearWrapSampler" + } + ] + } + ], + "nodes": [ + { + "resourceTexture": { + "name": "Color", + "editorPos": [ + -36.0, + -4.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "LinearDepth", + "editorPos": [ + -37.0, + 50.0 + ], + "visibility": "Imported" + } + }, + { + "actionComputeShader": { + "name": "DownsampleCoC", + "editorPos": [ + 123.0, + 34.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "Color", + "dstPin": "resource" + }, + { + "srcPin": "LinearDepth", + "dstNode": "LinearDepth", + "dstPin": "resource" + }, + { + "srcPin": "DownsampledCoC", + "dstNode": "DownsampledCoC", + "dstPin": "resource" + } + ], + "shader": { + "name": "DownSampleCoC" + }, + "dispatchSize": { + "node": { + "name": "DownsampledCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "DownsampledCoC", + "editorPos": [ + -36.0, + 162.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 4, + 4, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "GaussBlur", + "editorPos": [ + 341.0, + 89.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "DownsampledCoC", + "dstNode": "DownsampleCoC", + "dstPin": "DownsampledCoC" + }, + { + "srcPin": "BlurredDownsampledCoC", + "dstNode": "BlurredDownsampledCoC", + "dstPin": "resource" + } + ], + "shader": { + "name": "GaussBlur" + }, + "dispatchSize": { + "node": { + "name": "DownsampledCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "BlurredDownsampledCoC", + "editorPos": [ + 129.0, + 162.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 4, + 4, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "CalculateNearCoC", + "editorPos": [ + 613.0, + 89.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "shrunkSampler", + "dstNode": "GaussBlur", + "dstPin": "DownsampledCoC" + }, + { + "srcPin": "blurredSampler", + "dstNode": "GaussBlur", + "dstPin": "BlurredDownsampledCoC" + }, + { + "srcPin": "Output", + "dstNode": "CalculatedNearCoC", + "dstPin": "resource" + } + ], + "shader": { + "name": "CalculateNearCoC" + }, + "dispatchSize": { + "node": { + "name": "DownsampledCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "CalculatedNearCoC", + "editorPos": [ + 366.0, + 204.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 4, + 4, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "BlurNearCoC", + "editorPos": [ + 821.0, + 143.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "CalculatedNearCoC", + "dstNode": "CalculateNearCoC", + "dstPin": "Output" + }, + { + "srcPin": "Output", + "dstNode": "BlurredNearCoC", + "dstPin": "resource" + } + ], + "shader": { + "name": "BlurNearCoC" + }, + "dispatchSize": { + "node": { + "name": "DownsampledCoC" + } + } + } + }, + { + "resourceTexture": { + "name": "BlurredNearCoC", + "editorPos": [ + 646.0, + 204.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "node": { + "name": "Color" + }, + "divide": [ + 4, + 4, + 1 + ] + } + } + }, + { + "actionComputeShader": { + "name": "ApplyDOF", + "editorPos": [ + 1093.0, + 28.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "DownsampleCoC", + "dstPin": "Color" + }, + { + "srcPin": "SmallBlur", + "dstNode": "BlurNearCoC", + "dstPin": "Output" + }, + { + "srcPin": "LargeBlur", + "dstNode": "CalculateNearCoC", + "dstPin": "blurredSampler" + }, + { + "srcPin": "Output", + "dstNode": "Output", + "dstPin": "resource" + }, + { + "srcPin": "LinearDepth", + "dstNode": "DownsampleCoC", + "dstPin": "LinearDepth" + } + ], + "shader": { + "name": "ApplyDOF" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + 891.0, + 242.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Color" + } + }, + "size": { + "node": { + "name": "Color" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof_apply_dof.hlsl b/Techniques/PostProcessing/DepthOfField/IW2007/dof_apply_dof.hlsl new file mode 100644 index 00000000..19bff49a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof_apply_dof.hlsl @@ -0,0 +1,105 @@ +// Unnamed technique, shader ApplyDOF +/*$(ShaderResources)*/ + +#define dofEqFar float3(/*$(Variable:EqFar)*/ / /*$(Variable:DepthScale)*/, /*$(Variable:FarToNearRadiusRatio)*/) + +#define d0 /*$(Variable:fadeDistances)*/.x +#define d1 /*$(Variable:fadeDistances)*/.y +#define d2 /*$(Variable:fadeDistances)*/.z + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +float3 GetSmallBlurSample(uint2 px) +{ + static const float weight = 4.0f / 17.0f; + float3 sum = float3(0.0f, 0.0f, 0.0f); + + uint2 dims; + Color.GetDimensions(dims.x, dims.y); + + // Unblurred sample done by alpha blending + float2 uv = (float2(px) + float2(0.5f, 0.5f) + float2(+0.5f, -1.5f)) / float2(dims); + sum += weight * Color.SampleLevel(linearWrapSampler, uv, 0); + + uv = (float2(px) + float2(0.5f, 0.5f) + float2(-1.5f, -0.5f)) / float2(dims); + sum += weight * Color.SampleLevel(linearWrapSampler, uv, 0); + + uv = (float2(px) + float2(0.5f, 0.5f) + float2(-0.5f, +1.5f)) / float2(dims); + sum += weight * Color.SampleLevel(linearWrapSampler, uv, 0); + + uv = (float2(px) + float2(0.5f, 0.5f) + float2(+1.5f, +0.5f)) / float2(dims); + sum += weight * Color.SampleLevel(linearWrapSampler, uv, 0); + + return sum; +} + +float4 InterpolateDof(float3 small, float3 med, float3 large, float t) +{ + // Efficiently calculate the cross-blend weights for each sample. + // Let the unblurred sample to small blur fade happen over distance + // d0, the small to medium blur over distance d1, and the medium to + // large blur over distance d2, where d0 + d1 + d2 = 1. + // dofLerpScale = float4( -1 / d0, -1 / d1, -1 / d2, 1 / d2 ); + // dofLerpBias = float4( 1, (1 – d2) / d1, 1 / d2, (d2 – 1) / d2 ); + + float4 dofLerpScale = float4( -1.0f / d0, -1.0f / d1, -1.0f / d2, 1.0f / d2 ); + float4 dofLerpBias = float4( 1.0f, (1.0f - d2) / d1, 1.0f / d2, (d2 - 1.0f) / d2 ); + + float4 weights = saturate(t * dofLerpScale + dofLerpBias); + weights.yz = min(weights.yz, 1 - weights.xy); + + // Unblurred sample with weight "weights.x" done by alpha blending + float3 color = weights.y * small + weights.z * med + weights.w * large; + float alpha = dot(weights.yzw, half3(16.0 / 17, 1.0, 1.0)); + return float4(color, alpha); +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + //28-4 + uint2 px = DTid.xy; + float3 small = GetSmallBlurSample(px); + float4 med = SmallBlur[px/4]; + float3 large = LargeBlur[px/4].rgb; + float nearCoc = med.a; + float depth = LinearDepth[px].r; + float coc = 0.0f; + if (depth == 0.0f) + { + coc = nearCoc; // We don't want to blur the sky + } + else + { + // dofEqFar.x and dofEqFar.y specify the linear ramp to convert + // to depth for the distant out-of-focus region. + // dofEqFar.z is the ratio of the far to the near blur radius. + float farCoc = saturate(dofEqFar.x * depth + dofEqFar.y); + coc = max(nearCoc, farCoc * dofEqFar.z); + } + float4 output = InterpolateDof(small, med.rgb, large, coc); + + if (/*$(Variable:sRGB)*/) + output.rgb = LinearToSRGB(output.rgb); + + Output[px] = float4(output.rgb, 1.0f); +} + +/* +Shader Resources: + Texture Color (as SRV) + Texture LinearDepth (as SRV) + Texture LargeBlur (as SRV) + Texture SmallBlur (as SRV) + Texture Output (as UAV) +Shader Samplers: + linearWrapSampler filter: MinMagMipLinear addressmode: Wrap +*/ diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof_blur_near_coc.hlsl b/Techniques/PostProcessing/DepthOfField/IW2007/dof_blur_near_coc.hlsl new file mode 100644 index 00000000..5a53f37d --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof_blur_near_coc.hlsl @@ -0,0 +1,32 @@ +// Unnamed technique, shader BlurNearCoC +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + // 28-3 + uint2 px = DTid.xy; + + uint2 dims; + CalculatedNearCoC.GetDimensions(dims.x, dims.y); + + float4 texCoords = (float2(px) + float2(0.5f, 0.5f)).xxyy + float4(-0.5f, 0.5f, -0.5f, 0.5f); + texCoords /= float4(dims.xxyy); + + float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f); + + color += CalculatedNearCoC.SampleLevel(linearClampSampler, texCoords.xz, 0); + color += CalculatedNearCoC.SampleLevel(linearClampSampler, texCoords.yz, 0); + color += CalculatedNearCoC.SampleLevel(linearClampSampler, texCoords.xw, 0); + color += CalculatedNearCoC.SampleLevel(linearClampSampler, texCoords.yw, 0); + + Output[px] = color / 4.0f; + + // TODO: maybe the input is the full sized color image, even though the output isnt? + // The instructions seem to contradict each other a bit +} + +/* +Shader Resources: + Texture CalculatedNearCoC (as SRV) + Texture Output (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof_calculate_near_coc.hlsl b/Techniques/PostProcessing/DepthOfField/IW2007/dof_calculate_near_coc.hlsl new file mode 100644 index 00000000..be69982d --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof_calculate_near_coc.hlsl @@ -0,0 +1,20 @@ +// Unnamed technique, shader CalculateNearCoC +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + //28-2 + uint2 px = DTid.xy; + float4 shrunk = shrunkSampler[px]; + float4 blurred = blurredSampler[px]; + float3 color = shrunk.rgb; + float coc = 2.0f * max(blurred.a, shrunk.a) - shrunk.a; + Output[px] = float4(color, coc); +} + +/* +Shader Resources: + Texture shrunkSampler (as SRV) + Texture blurredSampler (as SRV) + Texture Output (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof_downsample_coc.hlsl b/Techniques/PostProcessing/DepthOfField/IW2007/dof_downsample_coc.hlsl new file mode 100644 index 00000000..d25f71a3 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof_downsample_coc.hlsl @@ -0,0 +1,83 @@ +// Unnamed technique, shader DownSampleCoC +/*$(ShaderResources)*/ + +#define dofEqWorld (/*$(Variable:EqNear)*/ / /*$(Variable:DepthScale)*/) + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + //28-1 + uint2 px = DTid.xy; + + uint2 dims; + Color.GetDimensions(dims.x, dims.y); + + /* + ___ ___ ___ ___ + | | | | | + |___|___|___|___| + | | | | | ___ + |___|___|___|___| => | | + | | | | | |___| + |___|___|___|___| + | | | | | + |___|___|___|___| + + */ + + // We want to average a 4x4 block of pixels from color. + // We could do 16 reads, but instead, we can do 4 bilinear taps at the center of each 4x4 cell. + // We add 0.5 when converting from integer pixel coordinates to UVs to get to the center of the cell, where the pixel data is. + // We add another 0.5 because we actually want to go the center of the 4x4 block + float2 uv00 = (float2(px * 4 + uint2(0, 0)) + float2(0.5f, 0.5f) + float2(0.5f, 0.5f)) / float2(dims); + float2 uv10 = (float2(px * 4 + uint2(2, 0)) + float2(0.5f, 0.5f) + float2(0.5f, 0.5f)) / float2(dims); + float2 uv01 = (float2(px * 4 + uint2(0, 2)) + float2(0.5f, 0.5f) + float2(0.5f, 0.5f)) / float2(dims); + float2 uv11 = (float2(px * 4 + uint2(2, 2)) + float2(0.5f, 0.5f) + float2(0.5f, 0.5f)) / float2(dims); + + float3 color = Color.SampleLevel(linearWrapSampler, uv00, 0).rgb + Color.SampleLevel(linearWrapSampler, uv10, 0).rgb + Color.SampleLevel(linearWrapSampler, uv01, 0).rgb + Color.SampleLevel(linearWrapSampler, uv11, 0).rgb; + color /= 4.0f; + + // We want to take the minimum CoC value of every depth value in the 4x4 block + float4 depth; + depth[0] = LinearDepth[px * 4 + uint2(0, 0)].r; + depth[1] = LinearDepth[px * 4 + uint2(1, 0)].r; + depth[2] = LinearDepth[px * 4 + uint2(2, 0)].r; + depth[3] = LinearDepth[px * 4 + uint2(3, 0)].r; + float4 sceneCoc = saturate(dofEqWorld.x * depth + dofEqWorld.y); + float4 curCoc = sceneCoc; + float4 coc = curCoc; + + depth[0] = LinearDepth[px * 4 + uint2(0, 1)].r; + depth[1] = LinearDepth[px * 4 + uint2(1, 1)].r; + depth[2] = LinearDepth[px * 4 + uint2(2, 1)].r; + depth[3] = LinearDepth[px * 4 + uint2(3, 1)].r; + sceneCoc = saturate(dofEqWorld.x * depth + dofEqWorld.y); + curCoc = sceneCoc; + coc = max(coc, curCoc); + + depth[0] = LinearDepth[px * 4 + uint2(0, 2)].r; + depth[1] = LinearDepth[px * 4 + uint2(1, 2)].r; + depth[2] = LinearDepth[px * 4 + uint2(2, 2)].r; + depth[3] = LinearDepth[px * 4 + uint2(3, 2)].r; + sceneCoc = saturate(dofEqWorld.x * depth + dofEqWorld.y); + curCoc = sceneCoc; + coc = max(coc, curCoc); + + depth[0] = LinearDepth[px * 4 + uint2(0, 3)].r; + depth[1] = LinearDepth[px * 4 + uint2(1, 3)].r; + depth[2] = LinearDepth[px * 4 + uint2(2, 3)].r; + depth[3] = LinearDepth[px * 4 + uint2(3, 3)].r; + sceneCoc = saturate(dofEqWorld.x * depth + dofEqWorld.y); + curCoc = sceneCoc; + coc = max(coc, curCoc); + + float maxCoc = max(max(coc[0], coc[1]), max(coc[2], coc[3])); + + DownsampledCoC[px] = float4(color, maxCoc); +} + +/* +Shader Resources: + Texture Color (as SRV) + Texture LinearDepth (as SRV) + Texture DownsampledCoC (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/dof_gauss_blur.hlsl b/Techniques/PostProcessing/DepthOfField/IW2007/dof_gauss_blur.hlsl new file mode 100644 index 00000000..19b29f54 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/dof_gauss_blur.hlsl @@ -0,0 +1,39 @@ +// Unnamed technique, shader GaussBlur +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + // unlisted code from article + // Kernel calculated at http://demofox.org/gauss.html + // Sigma 1.0, Support 0.995 + static const int c_kernelSize = 5; + static const float c_kernel[c_kernelSize] = {0.3829f, 0.2417f, 0.0606f, 0.0060f, 0.0002f}; + + int2 px = int2(DTid.xy); + uint2 dims; + DownsampledCoC.GetDimensions(dims.x, dims.y); + + float4 sum = float4(0.0f, 0.0f, 0.0f, 0.0f); + float weight = 0.0f; + for (int iy = -c_kernelSize; iy <= c_kernelSize; ++iy) + { + for (int ix = -c_kernelSize; ix <= c_kernelSize; ++ix) + { + int2 readpx = px + int2(ix, iy); + if (readpx.x >= 0 && readpx.y >= 0 && readpx.x < dims.x && readpx.y < dims.y) + { + //uint2 readpx = uint2(px + int2(ix, iy) + int2(dims)) % dims; + sum += DownsampledCoC[readpx]; + weight += 1.0f; + } + } + } + + BlurredDownsampledCoC[px] = sum / weight; +} + +/* +Shader Resources: + Texture DownsampledCoC (as SRV) + Texture BlurredDownsampledCoC (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/IW2007/readme.txt b/Techniques/PostProcessing/DepthOfField/IW2007/readme.txt new file mode 100644 index 00000000..8692fe23 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/IW2007/readme.txt @@ -0,0 +1,3 @@ +implementation of gpu gems 3 chapter 28: Practical Post-Process Depth of Field +By Earl Hammon, Jr at Infinity Ward +https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-28-practical-post-process-depth-field \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo.gg b/Techniques/PostProcessing/DepthOfField/dof_demo.gg new file mode 100644 index 00000000..dcd15737 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo.gg @@ -0,0 +1,959 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "RenderSize", + "type": "Uint2", + "dflt": "1024, 768", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "Set to true if the input texture is an sRGB texture", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "ToneMapper", + "type": "Int", + "dflt": "ACES", + "visibility": "User", + "Enum": "ToneMappingOperation" + }, + { + "name": "ExposureFStops", + "type": "Float", + "dflt": "0.0f", + "visibility": "User" + }, + { + "name": "DepthNearPlane", + "type": "Float", + "dflt": "0.1f", + "visibility": "User" + }, + { + "name": "CameraPos", + "type": "Float3" + }, + { + "name": "InvViewProjMtx", + "type": "Float4x4" + }, + { + "name": "ViewProjMtx", + "type": "Float4x4" + }, + { + "name": "ViewMtx", + "type": "Float4x4" + }, + { + "name": "SpheresPositionStart", + "comment": "Where the spheres start. In world space.", + "type": "Float3", + "dflt": "-1300.000000,200.000000,-100.000000", + "visibility": "User" + }, + { + "name": "SpheresPositionEnd", + "comment": "Where the spheres end In world space.", + "type": "Float3", + "dflt": "-1300.000000,200.000000,-100.000000", + "visibility": "User" + }, + { + "name": "SphereCount", + "type": "Uint", + "dflt": "5", + "visibility": "User" + }, + { + "name": "SphereRadius", + "type": "Float", + "dflt": "10.0f", + "visibility": "User" + }, + { + "name": "SphereColor", + "type": "Float3", + "dflt": "1.0f, 1.0f, 1.0f", + "visibility": "User", + "UISettings": { + "UIHint": "Color" + } + }, + { + "name": "SphereBrightness", + "type": "Float", + "dflt": "10.0f", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "VS", + "fileName": "dof_demo_vs.hlsl", + "type": "Vertex", + "entryPoint": "vsmain" + }, + { + "name": "PS", + "fileName": "dof_demo_ps.hlsl", + "type": "Pixel", + "entryPoint": "psmain", + "samplers": [ + { + "name": "linearWrapSampler" + } + ] + }, + { + "name": "Tonemap", + "fileName": "dof_demo_tonemap.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "HDR", + "type": "Texture", + "access": "SRV" + }, + { + "name": "SDR", + "type": "Texture", + "access": "UAV" + } + ] + }, + { + "name": "BrightLight", + "fileName": "dof_demo_brightlight.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Color", + "type": "Texture", + "access": "UAV" + }, + { + "name": "LinearDepth", + "type": "Texture", + "access": "UAV", + "texture": { + "viewType": "Float" + } + } + ] + } + ], + "structs": [ + { + "name": "Vertex", + "fields": [ + { + "name": "Position", + "type": "Float3", + "semantic": "Position" + }, + { + "name": "Normal", + "type": "Float3", + "semantic": "Normal" + }, + { + "name": "UV", + "type": "Float2", + "semantic": "UV" + }, + { + "name": "MaterialID", + "type": "Int", + "semantic": "MaterialID" + } + ] + } + ], + "nodes": [ + { + "actionDrawCall": { + "name": "Draw Opaque", + "editorPos": [ + -57.0, + 4.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "vertexShader": { + "name": "VS" + }, + "pixelShader": { + "name": "PS" + }, + "depthTargetClear": true, + "depthTest": "Greater", + "colorTargetSettings": [ + { + "clear": true, + "writeChannels": [ + true, + true, + true, + false + ], + "srcBlend": "SrcAlpha", + "destBlend": "InvSrcAlpha" + }, + { + "clear": true, + "clearColor": [ + 0.0, + 1.0, + 1.0, + 1.0 + ] + }, + {}, + {}, + {}, + {}, + {}, + {} + ], + "defines": [ + { + "name": "OPAQUE_PASS", + "value": "1" + } + ], + "cullMode": "Back", + "frontIsCounterClockwise": false, + "vertexBuffer": { + "node": "VertexBuffer", + "pin": "resource" + }, + "colorTargets": [ + { + "node": "Color", + "pin": "resource" + }, + { + "node": "LinearDepth", + "pin": "resource" + }, + {}, + {}, + {}, + {}, + {}, + {} + ], + "depthTarget": { + "node": "Depth", + "pin": "resource" + } + } + }, + { + "resourceBuffer": { + "name": "VertexBuffer", + "editorPos": [ + -217.0, + 18.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Color", + "editorPos": [ + -213.0, + 130.0 + ], + "format": { + "format": "RGBA32_Float" + }, + "size": { + "variable": { + "name": "RenderSize" + } + } + } + }, + { + "resourceTexture": { + "name": "Depth", + "editorPos": [ + -213.0, + 82.0 + ], + "format": { + "format": "D32_Float" + }, + "size": { + "variable": { + "name": "RenderSize" + } + } + } + }, + { + "resourceTexture": { + "name": "LinearDepth", + "editorPos": [ + -213.0, + 194.0 + ], + "format": { + "format": "R32_Float" + }, + "size": { + "variable": { + "name": "RenderSize" + } + } + } + }, + { + "actionDrawCall": { + "name": "Draw Transparent", + "editorPos": [ + 146.0, + 3.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "vertexShader": { + "name": "VS" + }, + "pixelShader": { + "name": "PS" + }, + "depthWrite": false, + "depthTest": "Greater", + "independentAlpha": true, + "colorTargetSettings": [ + { + "writeChannels": [ + true, + true, + true, + false + ], + "enableBlending": true, + "srcBlend": "SrcAlpha", + "destBlend": "InvSrcAlpha" + }, + { + "clearColor": [ + 0.0, + 1.0, + 1.0, + 1.0 + ], + "writeChannels": [ + false, + false, + false, + false + ] + }, + {}, + {}, + {}, + {}, + {}, + {} + ], + "defines": [ + { + "name": "OPAQUE_PASS", + "value": "0" + } + ], + "cullMode": "Back", + "frontIsCounterClockwise": false, + "vertexBuffer": { + "node": "Draw Opaque", + "pin": "vertexBuffer" + }, + "colorTargets": [ + { + "node": "Draw Opaque", + "pin": "colorTarget0" + }, + { + "node": "Draw Opaque", + "pin": "colorTarget1" + }, + {}, + {}, + {}, + {}, + {}, + {} + ], + "depthTarget": { + "node": "Draw Opaque", + "pin": "depthTarget" + } + } + }, + { + "actionSubGraph": { + "name": "IW2007", + "editorPos": [ + 609.0, + -52.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "BrightLight", + "dstPin": "Color" + }, + { + "srcPin": "LinearDepth", + "dstNode": "BrightLight", + "dstPin": "LinearDepth" + }, + { + "srcPin": "Output" + } + ], + "fileName": "IW2007\\dof.gg", + "subGraphData": { + "importedResources": [ + "Color", + "LinearDepth" + ], + "exportedResources": [ + "Output" + ], + "variables": [ + { + "name": "DepthScale", + "visibility": "User" + }, + { + "name": "EqNear", + "visibility": "User" + }, + { + "name": "EqFar", + "visibility": "User" + }, + { + "name": "FarToNearRadiusRatio", + "visibility": "User" + }, + { + "name": "fadeDistances", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User" + } + ] + }, + "variableSettings": [ + { + "name": "DepthScale", + "visibility": "User" + }, + { + "name": "EqNear", + "visibility": "User" + }, + { + "name": "EqFar", + "visibility": "User" + }, + { + "name": "FarToNearRadiusRatio", + "visibility": "User" + }, + { + "name": "fadeDistances", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User", + "replaceWithStr": "sRGB" + } + ] + } + }, + { + "actionSubGraph": { + "name": "Gustafsson2018", + "editorPos": [ + 608.0, + 98.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "BrightLight", + "dstPin": "Color" + }, + { + "srcPin": "LinearDepth", + "dstNode": "BrightLight", + "dstPin": "LinearDepth" + }, + { + "srcPin": "Output" + } + ], + "fileName": "Gustafsson2018\\dof.gg", + "subGraphData": { + "importedResources": [ + "Color", + "LinearDepth" + ], + "exportedResources": [ + "Output" + ], + "variables": [ + { + "name": "MaxBlurSize", + "visibility": "User" + }, + { + "name": "FocalLength", + "visibility": "User" + }, + { + "name": "FocusScale", + "visibility": "User" + }, + { + "name": "RadiusScale", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User" + } + ] + }, + "variableSettings": [ + { + "name": "MaxBlurSize", + "visibility": "User" + }, + { + "name": "FocalLength", + "visibility": "User" + }, + { + "name": "FocusScale", + "visibility": "User" + }, + { + "name": "RadiusScale", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User", + "replaceWithStr": "sRGB" + } + ] + } + }, + { + "actionComputeShader": { + "name": "IW2007Output", + "editorPos": [ + 757.0, + -14.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "HDR", + "dstNode": "IW2007", + "dstPin": "Output" + }, + { + "srcPin": "SDR", + "dstNode": "SDR1", + "dstPin": "resource" + } + ], + "shader": { + "name": "Tonemap" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "actionComputeShader": { + "name": "Gustafsson2018Output", + "editorPos": [ + 757.0, + 140.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "HDR", + "dstNode": "Gustafsson2018", + "dstPin": "Output" + }, + { + "srcPin": "SDR", + "dstNode": "SDR2", + "dstPin": "resource" + } + ], + "shader": { + "name": "Tonemap" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "resourceTexture": { + "name": "SDR1", + "editorPos": [ + 613.0, + 34.0 + ], + "format": { + "format": "RGBA8_Unorm_sRGB" + }, + "size": { + "node": { + "name": "Color" + } + } + } + }, + { + "resourceTexture": { + "name": "SDR2", + "editorPos": [ + 613.0, + 194.0 + ], + "format": { + "format": "RGBA8_Unorm_sRGB" + }, + "size": { + "node": { + "name": "Color" + } + } + } + }, + { + "actionComputeShader": { + "name": "BrightLight", + "editorPos": [ + 341.0, + 98.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "LinearDepth", + "dstNode": "Draw Transparent", + "dstPin": "colorTarget1" + }, + { + "srcPin": "Color", + "dstNode": "Draw Transparent", + "dstPin": "colorTarget0" + } + ], + "shader": { + "name": "BrightLight" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + }, + { + "actionSubGraph": { + "name": "GatherDOF2018", + "editorPos": [ + 598.0, + 252.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Color", + "dstNode": "BrightLight", + "dstPin": "Color" + }, + { + "srcPin": "LinearDepth", + "dstNode": "BrightLight", + "dstPin": "LinearDepth" + }, + { + "srcPin": "Output" + } + ], + "fileName": "GatherDOF2018\\dof.gg", + "subGraphData": { + "importedResources": [ + "Color", + "LinearDepth" + ], + "exportedResources": [ + "Output" + ], + "variables": [ + { + "name": "FocalDistance", + "visibility": "User" + }, + { + "name": "FocalRegion", + "visibility": "User" + }, + { + "name": "FocalLength", + "visibility": "User" + }, + { + "name": "NearTransitionRegion", + "visibility": "User" + }, + { + "name": "FarTransitionRegion", + "visibility": "User" + }, + { + "name": "Scale", + "visibility": "User" + }, + { + "name": "DoFarField", + "visibility": "User" + }, + { + "name": "DoFarFieldFloodFill", + "visibility": "User" + }, + { + "name": "DoNearField", + "visibility": "User" + }, + { + "name": "DoNearFieldFloodFill", + "visibility": "User" + }, + { + "name": "KernelSize", + "visibility": "User" + }, + { + "name": "BlurTapCount", + "visibility": "User" + }, + { + "name": "FloodFillTapCount", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User" + } + ] + }, + "variableSettings": [ + { + "name": "FocalDistance", + "visibility": "User" + }, + { + "name": "FocalRegion", + "visibility": "User" + }, + { + "name": "FocalLength", + "visibility": "User" + }, + { + "name": "NearTransitionRegion", + "visibility": "User" + }, + { + "name": "FarTransitionRegion", + "visibility": "User" + }, + { + "name": "Scale", + "visibility": "User" + }, + { + "name": "DoFarField", + "visibility": "User" + }, + { + "name": "DoFarFieldFloodFill", + "visibility": "User" + }, + { + "name": "DoNearField", + "visibility": "User" + }, + { + "name": "DoNearFieldFloodFill", + "visibility": "User" + }, + { + "name": "KernelSize", + "visibility": "User" + }, + { + "name": "BlurTapCount", + "visibility": "User" + }, + { + "name": "FloodFillTapCount", + "visibility": "User" + }, + { + "name": "sRGB", + "visibility": "User", + "replaceWithStr": "sRGB" + } + ] + } + }, + { + "resourceTexture": { + "name": "SDR3", + "editorPos": [ + 619.0, + 354.0 + ], + "format": { + "format": "RGBA8_Unorm_sRGB" + }, + "size": { + "node": { + "name": "Color" + } + } + } + }, + { + "actionComputeShader": { + "name": "GatherDOF2018Output", + "editorPos": [ + 763.0, + 300.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "HDR", + "dstNode": "GatherDOF2018", + "dstPin": "Output" + }, + { + "srcPin": "SDR", + "dstNode": "SDR3", + "dstPin": "resource" + } + ], + "shader": { + "name": "Tonemap" + }, + "dispatchSize": { + "node": { + "name": "Color" + } + } + } + } + ], + "enums": [ + { + "name": "ToneMappingOperation", + "items": [ + { + "label": "None" + }, + { + "label": "Reinhard_Simple" + }, + { + "label": "ACES_Luminance" + }, + { + "label": "ACES" + } + ] + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo.gguser b/Techniques/PostProcessing/DepthOfField/dof_demo.gguser new file mode 100644 index 00000000..805bcf44 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo.gguser @@ -0,0 +1,1141 @@ +{ + "version": "2.0", + "systemVars": { + "camera": { + "farPlane": 10000.0, + "flySpeed": 10.0, + "startingCameraPos": [ + 725.8267211914063, + 152.89263916015626, + -64.2867660522461 + ], + "startingCameraAltitudeAzimuth": [ + 0.1963098794221878, + 1.832762360572815 + ] + }, + "ProjMtx_textureName": "Color" + }, + "snapshot": { + "resourceViewNodeIndex": 7, + "resourceViewResourceIndex": 3, + "cameraPos": [ + 725.8267211914063, + 152.89263916015626, + -64.2867660522461 + ], + "cameraAltitudeAzimuth": [ + 0.1963098794221878, + 1.832762360572815 + ], + "importedResources": [ + { + "nodeName": "VertexBuffer", + "isATexture": false, + "buffer": { + "fileName": "..\\..\\OBJAssets\\sponza\\sponza.obj", + "structIndex": 0, + "BLASOpaque": true + } + } + ], + "savedVariables": [ + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpheresPositionStart", + "value": "-1300.000000,200.000000,0.000000" + }, + { + "name": "SpheresPositionEnd", + "value": "1300.000000,200.000000,100.000000" + }, + { + "name": "SphereCount", + "value": "5" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-3.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "0.500000,-300.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "10.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.300000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "75.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "0.500000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + }, + { + "name": "GatherDOF2018_BlurTapCount", + "value": "8" + }, + { + "name": "GatherDOF2018_FloodFillTapCount", + "value": "4" + } + ] + }, + "snapshots": [ + { + "name": "IW2007", + "resourceViewNodeIndex": 6, + "resourceViewResourceIndex": 3, + "loadVars": false, + "loadCamera": false, + "loadResources": false, + "cameraPos": [ + 725.8267211914063, + 152.89263916015626, + -64.2867660522461 + ], + "cameraAltitudeAzimuth": [ + 0.1963098794221878, + 1.832762360572815 + ], + "importedResources": [ + { + "nodeName": "VertexBuffer", + "isATexture": false, + "buffer": { + "fileName": "..\\..\\OBJAssets\\sponza\\sponza.obj", + "structIndex": 0, + "BLASOpaque": true + } + } + ], + "savedVariables": [ + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "true" + }, + { + "name": "IW2007_DepthScale", + "value": "100.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "1.000000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "IW2007_sRGB", + "value": "true" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.500000" + }, + { + "name": "Gustafsson2018_sRGB", + "value": "true" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "true" + }, + { + "name": "IW2007_DepthScale", + "value": "100.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "1.000000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "IW2007_sRGB", + "value": "true" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.500000" + }, + { + "name": "Gustafsson2018_sRGB", + "value": "true" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.500000" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpherePosition", + "value": "-1300.000000,200.000000,-100.000000" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.100000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "75.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "0.500000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_MaxBokehSize", + "value": "10.000000" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + } + ] + }, + { + "name": "Gustafsson2018", + "resourceViewNodeIndex": 7, + "resourceViewResourceIndex": 3, + "loadVars": false, + "loadCamera": false, + "loadResources": false, + "cameraPos": [ + 725.8267211914063, + 152.89263916015626, + -64.2867660522461 + ], + "cameraAltitudeAzimuth": [ + 0.1963098794221878, + 1.832762360572815 + ], + "importedResources": [ + { + "nodeName": "VertexBuffer", + "isATexture": false, + "buffer": { + "fileName": "..\\..\\OBJAssets\\sponza\\sponza.obj", + "structIndex": 0, + "BLASOpaque": true + } + } + ], + "savedVariables": [ + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "true" + }, + { + "name": "IW2007_DepthScale", + "value": "100.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "1.000000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "IW2007_sRGB", + "value": "true" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.500000" + }, + { + "name": "Gustafsson2018_sRGB", + "value": "true" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.500000" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpherePosition", + "value": "-1300.000000,200.000000,-100.000000" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.100000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "75.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "0.500000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_MaxBokehSize", + "value": "10.000000" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + } + ] + }, + { + "name": "GatherDOF2018", + "resourceViewNodeIndex": 12, + "resourceViewResourceIndex": 3, + "loadVars": false, + "loadCamera": false, + "loadResources": false, + "cameraPos": [ + 725.8267211914063, + 152.89263916015626, + -64.2867660522461 + ], + "cameraAltitudeAzimuth": [ + 0.1963098794221878, + 1.832762360572815 + ], + "importedResources": [ + { + "nodeName": "VertexBuffer", + "isATexture": false, + "buffer": { + "fileName": "..\\..\\OBJAssets\\sponza\\sponza.obj", + "structIndex": 0, + "BLASOpaque": true + } + } + ], + "savedVariables": [ + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpherePosition", + "value": "-1300.000000,200.000000,-100.000000" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.100000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "2.000000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_MaxBokehSize", + "value": "10.000000" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpherePosition", + "value": "-1300.000000,200.000000,-100.000000" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.100000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "75.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "0.500000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_MaxBokehSize", + "value": "10.000000" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + }, + { + "name": "RenderSize", + "value": "1024,768" + }, + { + "name": "sRGB", + "value": "false" + }, + { + "name": "ToneMapper", + "value": "0" + }, + { + "name": "ExposureFStops", + "value": "0.000000" + }, + { + "name": "DepthNearPlane", + "value": "0.100000" + }, + { + "name": "SpheresPositionStart", + "value": "-1300.000000,200.000000,0.000000" + }, + { + "name": "SpheresPositionEnd", + "value": "1300.000000,200.000000,100.000000" + }, + { + "name": "SphereCount", + "value": "5" + }, + { + "name": "SphereRadius", + "value": "5.000000" + }, + { + "name": "SphereColor", + "value": "1.000000,1.000000,1.000000" + }, + { + "name": "SphereBrightness", + "value": "2.000000" + }, + { + "name": "IW2007_DepthScale", + "value": "1000.000000" + }, + { + "name": "IW2007_EqNear", + "value": "-2.000000,1700.000000" + }, + { + "name": "IW2007_EqFar", + "value": "1.000000,-500.000000" + }, + { + "name": "IW2007_FarToNearRadiusRatio", + "value": "0.800000" + }, + { + "name": "IW2007_fadeDistances", + "value": "0.000000,0.500000,0.500000" + }, + { + "name": "Gustafsson2018_MaxBlurSize", + "value": "20.000000" + }, + { + "name": "Gustafsson2018_FocalLength", + "value": "500.000000" + }, + { + "name": "Gustafsson2018_FocusScale", + "value": "200.000000" + }, + { + "name": "Gustafsson2018_RadiusScale", + "value": "0.100000" + }, + { + "name": "GatherDOF2018_FocalDistance", + "value": "500.000000" + }, + { + "name": "GatherDOF2018_FocalRegion", + "value": "100.000000" + }, + { + "name": "GatherDOF2018_FocalLength", + "value": "75.000000" + }, + { + "name": "GatherDOF2018_NearTransitionRegion", + "value": "50.000000" + }, + { + "name": "GatherDOF2018_FarTransitionRegion", + "value": "200.000000" + }, + { + "name": "GatherDOF2018_Scale", + "value": "0.500000" + }, + { + "name": "GatherDOF2018_DoFarField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoFarFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearField", + "value": "true" + }, + { + "name": "GatherDOF2018_DoNearFieldFloodFill", + "value": "true" + }, + { + "name": "GatherDOF2018_KernelSize", + "value": "10.000000,15.000000,5.000000,0.000000" + }, + { + "name": "GatherDOF2018_BlurTapCount", + "value": "8" + }, + { + "name": "GatherDOF2018_FloodFillTapCount", + "value": "4" + } + ] + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo_brightlight.hlsl b/Techniques/PostProcessing/DepthOfField/dof_demo_brightlight.hlsl new file mode 100644 index 00000000..c5b305df --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo_brightlight.hlsl @@ -0,0 +1,86 @@ +// Unnamed technique, shader BrightLight +/*$(ShaderResources)*/ + +#define FLT_MAX 3.402823466e+38 + +// returns -1.0 on miss, else returns time to hit +float TestSphereTrace(in float3 rayPos, in float3 rayDir, in float4 sphere, out float3 normal) +{ + //get the vector from the center of this sphere to where the ray begins. + float3 m = rayPos - sphere.xyz; + + //get the dot product of the above vector and the ray's vector + float b = dot(m, rayDir); + + float c = dot(m, m) - sphere.w * sphere.w; + + //exit if r's origin outside s (c > 0) and r pointing away from s (b > 0) + if(c > 0.0 && b > 0.0) + return -1.0f; + + //calculate discriminant + float discr = b * b - c; + + //a negative discriminant corresponds to ray missing sphere + if(discr < 0.0) + return -1.0f; + + //ray now found to intersect sphere, compute smallest t value of intersection + bool fromInside = false; + float dist = -b - sqrt(discr); + if (dist < 0.0f) + { + fromInside = true; + dist = -b + sqrt(discr); + } + + normal = normalize((rayPos+rayDir*dist) - sphere.xyz) * (fromInside ? -1.0f : 1.0f); + + return dist; +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + uint2 dims; + Color.GetDimensions(dims.x, dims.y); + + // Calculate a ray for this pixel + float2 screenPos = float2(px) / float2(dims) * 2.0 - 1.0; + screenPos.y = -screenPos.y; + + float4 world = mul(float4(screenPos, /*$(Variable:DepthNearPlane)*/, 1), /*$(Variable:InvViewProjMtx)*/); + world.xyz /= world.w; + + float3 rayPos = /*$(Variable:CameraPos)*/; + float3 rayDir = normalize(world.xyz - /*$(Variable:CameraPos)*/); + + // Shoot the ray at the spheres and compare hit time against depth buffer + float sphereHitT = FLT_MAX; + for (uint i = 0; i < /*$(Variable:SphereCount)*/; ++i) + { + float percent = (float(i) + 0.5f) / float(/*$(Variable:SphereCount)*/); + float3 spherePosition = lerp(/*$(Variable:SpheresPositionStart)*/, /*$(Variable:SpheresPositionEnd)*/, percent); + + float3 normal; + float hitT = TestSphereTrace(rayPos, rayDir, float4(spherePosition, /*$(Variable:SphereRadius)*/), normal); + if (hitT >= 0.0f) + sphereHitT = min(hitT, sphereHitT); + } + + // If no sphere hit, or none hit before the depth buffer value, nothing to do. + if (LinearDepth[px] < sphereHitT) + return; + + // draw the sphere hit to the color buffer and linear depth buffer + LinearDepth[px] = sphereHitT; + + Color[px] = float4(/*$(Variable:SphereColor)*/*/*$(Variable:SphereBrightness)*/, 1.0f); +} + +/* +Shader Resources: + Texture Color (as UAV) + Texture LinearDepth (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo_ps.hlsl b/Techniques/PostProcessing/DepthOfField/dof_demo_ps.hlsl new file mode 100644 index 00000000..ca2d1a3b --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo_ps.hlsl @@ -0,0 +1,165 @@ +// Unnamed technique, shader PS +/*$(ShaderResources)*/ + +struct PSInput // AKA VSOutput +{ + float4 position : SV_POSITION; + float2 UV : TEXCOORD0; + float3 normal : TEXCOORD1; + int materialID : TEXCOORD2; + float depth : TEXCOORD3; +}; + +struct PSOutput +{ + float4 colorTarget : SV_Target0; + float4 linearDepth : SV_Target1; +}; + +float4 ReadAlbedo(float2 UV, in Texture2D albedo, in Texture2D transparency) +{ + float4 ret; + ret.rgb = albedo.Sample(linearWrapSampler, UV).rgb; + ret.a = transparency.Sample(linearWrapSampler, UV); + return ret; +} + +float4 ReadAlbedo(float2 UV, in Texture2D albedo) +{ + float4 ret; + ret.rgb = albedo.Sample(linearWrapSampler, UV).rgb; + ret.a = 1.0f; + return ret; +} + + +PSOutput psmain(PSInput input) +{ + PSOutput ret = (PSOutput)0; + ret.linearDepth = input.depth; + + float4 albedo = float4(0.0f, 0.0f, 0.0f, 0.0f); + + // Textures should be in "..\..\OBJAssets\sponza\", but it doesn't copy them over correctly when doing that. + switch(input.materialID) + { + case 0: // leaf + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_thorn_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/, /*$(Image2D:textures\sponza_thorn_mask.png:R8_UNorm:float:false:true)*/); break; + + case 1: // vase_round + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\vase_round.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 2: // Material__57 + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\vase_plant.png:RGBA8_UNorm_SRGB:float4:true:true)*/, /*$(Image2D:textures\vase_plant_mask.png:R8_UNorm:float:false:true)*/); break; + + case 3: // Material__298 + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\background.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 4: // bricks + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\spnza_bricks_a_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 5: // arch + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_arch_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 6: // ceiling + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_ceiling_a_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 7: // column_a + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_column_a_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 8: // floor + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_floor_a_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 9: // column_c + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_column_c_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 10: // details + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_details_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 11: // column_b + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_column_b_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 12: // Material__47 + albedo = float4(0.0f, 0.0f, 0.0f, 0.0f); break; + + case 13: // flagpole + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_flagpole_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 14: // fabric_e + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_fabric_green_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 15: // fabric_d + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_fabric_blue_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 16: // fabric_a + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_fabric_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 17: // fabric_g + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_curtain_blue_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 18: // fabric_c + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_curtain_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 19: // fabric_f + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_curtain_green_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 20: // chain + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\chain_texture.png:RGBA8_UNorm_SRGB:float4:true:true)*/, /*$(Image2D:textures\chain_texture_mask.png:R8_UNorm:float:false:true)*/); break; + + case 21: // vase_hanging + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\vase_hanging.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 22: // vase + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\vase_dif.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 23: // Material__25 + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\lion.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + case 24: // roof + albedo = ReadAlbedo(input.UV, /*$(Image2D:textures\sponza_roof_diff.png:RGBA8_UNorm_SRGB:float4:true:true)*/); break; + + default: albedo = float4(1.0f, 0.0f, 1.0f, 1.0f); break; + } + + #if OPAQUE_PASS == 1 + if (albedo.a < 1.0f) + discard; + #else + if (albedo.a >= 1.0f) + discard; + #endif + + float3 lightDir = normalize(float3(0.2f, 1.0f, 0.3f)); + float3 lightColor = float3(1.0f, 1.0f, 1.0f); + float3 ambientLightColor = float3(0.1f, 0.1f, 0.1f); + + float3 color = albedo * (max(dot(input.normal, lightDir), 0.0f) * lightColor + ambientLightColor); + + ret.colorTarget = float4(color, albedo.a); + + return ret; +} + +/* +Info about obj format: https://paulbourke.net/dataformats/mtl/ + +Obj notes: +map_ka +map_kd +map_ks +map_ke +map_d +map_bump + +* bump (MASTER_Interior_01_Floor_Tile_Hexagonal_BLENDSHADER) +* d - transparency +* illum - illumination model +* ka - ambient color +* kd - diffuse color +* ks - specular color +* ke - emissive color +* Ni - refraction index +* Ns - specular exponent +* Tr - transparency (1-d) +* Tf - transmission color +*/ \ No newline at end of file diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo_tonemap.hlsl b/Techniques/PostProcessing/DepthOfField/dof_demo_tonemap.hlsl new file mode 100644 index 00000000..fd37f9d2 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo_tonemap.hlsl @@ -0,0 +1,124 @@ +// Unnamed technique, shader Tonemap +/*$(ShaderResources)*/ + +// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ +float3 ACESFilm(float3 x) +{ + float a = 2.51f; + float b = 0.03f; + float c = 2.43f; + float d = 0.59f; + float e = 0.14f; + return saturate((x*(a*x+b))/(x*(c*x+d)+e)); +} + +// ============= ACES BEGIN +// https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl + +// The code in this file was originally written by Stephen Hill (@self_shadow), who deserves all +// credit for coming up with this fit and implementing it. Buy him a beer next time you see him. :) + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +float3 SRGBToLinear(in float3 sRGBCol) +{ + float3 linearRGBLo = sRGBCol / 12.92; + float3 linearRGBHi = pow((sRGBCol + 0.055) / 1.055, float3(2.4, 2.4, 2.4)); + float3 linearRGB; + linearRGB.r = sRGBCol.r <= 0.04045 ? linearRGBLo.r : linearRGBHi.r; + linearRGB.g = sRGBCol.g <= 0.04045 ? linearRGBLo.g : linearRGBHi.g; + linearRGB.b = sRGBCol.b <= 0.04045 ? linearRGBLo.b : linearRGBHi.b; + return linearRGB; +} + +// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT +static const float3x3 ACESInputMat = +{ + {0.59719, 0.35458, 0.04823}, + {0.07600, 0.90834, 0.01566}, + {0.02840, 0.13383, 0.83777} +}; + +// ODT_SAT => XYZ => D60_2_D65 => sRGB +static const float3x3 ACESOutputMat = +{ + { 1.60475, -0.53108, -0.07367}, + {-0.10208, 1.10813, -0.00605}, + {-0.00327, -0.07276, 1.07602} +}; + +float3 RRTAndODTFit(float3 v) +{ + float3 a = v * (v + 0.0245786f) - 0.000090537f; + float3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f; + return a / b; +} + +float3 ACESFitted(float3 color) +{ + color = mul(ACESInputMat, color); + + // Apply RRT and ODT + color = RRTAndODTFit(color); + + color = mul(ACESOutputMat, color); + + // Clamp to [0, 1] + color = saturate(color); + + return color; +} + +// ============= ACES END + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + uint2 px = DTid.xy; + + // convert exposure from FStops to a multiplier + float exposure = pow(2.0f, /*$(Variable:ExposureFStops)*/); + + float3 rgb = max(HDR[px].rgb * exposure, 0.0f); + + switch(/*$(Variable:ToneMapper)*/) + { + // Do nothing, only apply exposure + case ToneMappingOperation::None: break; + + // https://64.github.io/tonemapping/ + case ToneMappingOperation::Reinhard_Simple: + { + rgb = rgb / (1.0f + rgb); + break; + } + case ToneMappingOperation::ACES_Luminance: + { + // The * 0.6f is to undo the exposure baked in, per the author's instructions + rgb = ACESFilm(rgb * 0.6f); + break; + } + case ToneMappingOperation::ACES: + { + rgb = ACESFitted(rgb); + break; + } + } + + rgb = clamp(rgb, 0.0f, 1.0f); + SDR[px] = float4(LinearToSRGB(rgb), 1.0f); +} + +/* +Shader Resources: + Texture HDR (as SRV) + Texture SDR (as UAV) +*/ diff --git a/Techniques/PostProcessing/DepthOfField/dof_demo_vs.hlsl b/Techniques/PostProcessing/DepthOfField/dof_demo_vs.hlsl new file mode 100644 index 00000000..853957c5 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/dof_demo_vs.hlsl @@ -0,0 +1,33 @@ +// Unnamed technique, shader VS +/*$(ShaderResources)*/ + +struct VSInput +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 UV : TEXCOORD0; + int materialID : TEXCOORD1; +}; + +struct VSOutput // AKA PSInput +{ + float4 position : SV_POSITION; + float2 UV : TEXCOORD0; + float3 normal : TEXCOORD1; + int materialID : TEXCOORD2; + float depth : TEXCOORD3; +}; + +VSOutput vsmain(VSInput input) +{ + VSOutput ret = (VSOutput)0; + ret.position = mul(float4(input.position, 1.0f), /*$(Variable:ViewProjMtx)*/); + ret.UV = input.UV; + ret.normal = input.normal; + ret.materialID = input.materialID; + + float4 cameraPos = mul(float4(input.position, 1.0f), /*$(Variable:ViewMtx)*/); + ret.depth = cameraPos.z / cameraPos.w; + + return ret; +} diff --git a/Techniques/PostProcessing/DepthOfField/textures/background.png b/Techniques/PostProcessing/DepthOfField/textures/background.png new file mode 100644 index 00000000..e1695860 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21f5955648b003a0046ca16054aef2db07901d73662e8b8141e73ba551e06f87 +size 1279899 diff --git a/Techniques/PostProcessing/DepthOfField/textures/background_bump.png b/Techniques/PostProcessing/DepthOfField/textures/background_bump.png new file mode 100644 index 00000000..015e7413 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/background_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c816df0108455787a9ffba973b01788d3cd2724dbfe1ff148dd1a51df37b2baa +size 211001 diff --git a/Techniques/PostProcessing/DepthOfField/textures/chain_texture.png b/Techniques/PostProcessing/DepthOfField/textures/chain_texture.png new file mode 100644 index 00000000..3a295b32 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/chain_texture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5745cf634538333bcad860e5da4bd57d288166631aadc4b0268fc2103b152242 +size 374829 diff --git a/Techniques/PostProcessing/DepthOfField/textures/chain_texture_bump.png b/Techniques/PostProcessing/DepthOfField/textures/chain_texture_bump.png new file mode 100644 index 00000000..21e5ec96 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/chain_texture_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bcb283948533a96100cb90f1bffa4edb609c887b336ba21be12ec713430933e +size 37014 diff --git a/Techniques/PostProcessing/DepthOfField/textures/chain_texture_mask.png b/Techniques/PostProcessing/DepthOfField/textures/chain_texture_mask.png new file mode 100644 index 00000000..06d39d6d --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/chain_texture_mask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43c246a2de3b9bea28add7b188324765443e30223fcee13061719e2d357194e1 +size 1150 diff --git a/Techniques/PostProcessing/DepthOfField/textures/floor_gloss.png b/Techniques/PostProcessing/DepthOfField/textures/floor_gloss.png new file mode 100644 index 00000000..f1efd8bd --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/floor_gloss.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de0f989550e4cf7e0753c7480cd2b533ecb9d61b395033fbc3dbe71140aebaf2 +size 1419271 diff --git a/Techniques/PostProcessing/DepthOfField/textures/lion.png b/Techniques/PostProcessing/DepthOfField/textures/lion.png new file mode 100644 index 00000000..aa240202 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/lion.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13c763cb8d01e781121180a2f0c7ddc6c672d0a146ffc1359a5795dba99db5c2 +size 1685074 diff --git a/Techniques/PostProcessing/DepthOfField/textures/lion2_bump.png b/Techniques/PostProcessing/DepthOfField/textures/lion2_bump.png new file mode 100644 index 00000000..cbea1ad6 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/lion2_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcca6af06b7c7ca9b5ef0829db9ad7f2437ddaa2d6484d3811ad9a8b21a81ea3 +size 287706 diff --git a/Techniques/PostProcessing/DepthOfField/textures/lion_bump.png b/Techniques/PostProcessing/DepthOfField/textures/lion_bump.png new file mode 100644 index 00000000..cd778d30 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/lion_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c9c6c4e42a9160f518f27af3755e8b45e0342882e422d3c6ecb397efcdc8acd +size 283932 diff --git a/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_bump.png b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_bump.png new file mode 100644 index 00000000..e5b7083d --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ce6e00a0d90f377b8f922f006b8078d72272259b1816e24d511302c0822dfd8 +size 613084 diff --git a/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_diff.png b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_diff.png new file mode 100644 index 00000000..75e58a61 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6653d814e78df5b1d72bff0bc4f055b19f40c60125368c66f706862a77b11e19 +size 1850821 diff --git a/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_spec.png b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_spec.png new file mode 100644 index 00000000..e22cd8c2 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/spnza_bricks_a_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07e6c0d154316dca9f06ac8f30e155786d1b4c9f4f75a5f57901f96338d452f7 +size 789292 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_bump.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_bump.png new file mode 100644 index 00000000..9292cf50 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ed13ea591ff9d0c4e950a372e59de8e95dd58af9d0f1fcc5794b87927e8d9ab +size 72484 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_diff.png new file mode 100644 index 00000000..b28417da --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a2e127ce784d2d4f061eae58a780cdcc8daba6c0f254d06e5494e41d4874ff2 +size 1545689 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_spec.png new file mode 100644 index 00000000..db24b7f4 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_arch_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cff3751f78b5d8c59eb599477187c7ff2874a76140f442ed52a45e7def08e412 +size 519758 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_diff.png new file mode 100644 index 00000000..b1f55f83 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d6ff12242bd2b0680c45b27d0234cb4fc636959a2575f29dd6eb02251348f4c +size 1748205 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_spec.png new file mode 100644 index 00000000..6ebad647 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_ceiling_a_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d8ae36a72774c51128a2810035377b08c7214b9fa1db6d0d4d2229162339828 +size 611209 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_bump.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_bump.png new file mode 100644 index 00000000..61c832e8 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d88c0f98ac0d37a6c0759962bb797c3f1e9dbf976035308cde4cba92a1156b40 +size 314193 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_diff.png new file mode 100644 index 00000000..7d581544 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13c3511250c790ad260845ffd5d56f4622bb3760316831403c3cc182bcf40095 +size 1743092 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_spec.png new file mode 100644 index 00000000..77581f96 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_a_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66f596b9e37fdaf84b581bb671c40942d59f0dda3470f743b8cbe7928cbc4cab +size 624131 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_bump.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_bump.png new file mode 100644 index 00000000..d42366d0 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5f818c01f960fc43258e5be57c77b717209078a50758d43c6c61b89253c0395 +size 306062 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_diff.png new file mode 100644 index 00000000..99dc1c92 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e893c9f0a8ca1cb7b649476eaa6ce98ece4d82b447f2a9858dbf0be4ce05c8e1 +size 2127842 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_spec.png new file mode 100644 index 00000000..130adfb9 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_b_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6850e2de861b79d48722fd286f3726755d8d5f5f7c459e0600bc9f9f03c6f5fe +size 625709 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_bump.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_bump.png new file mode 100644 index 00000000..56c58ffc --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25badc8f4f8ecb7f982265534d60fd0f0da961ee4f64abfafa8b31ec07534e27 +size 322713 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_diff.png new file mode 100644 index 00000000..7c7b0454 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eaf9050e0cb05bc5184b4fc7108085036e049ca6a3a93c0b11ed8e920831472d +size 2021589 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_spec.png new file mode 100644 index 00000000..eb8bd90f --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_column_c_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77641f66babf57ef10d36d4f4357d39b38c510779f87a3e63c0d797c40c425b7 +size 662176 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_blue_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_blue_diff.png new file mode 100644 index 00000000..0afcf9b9 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:267f19cc7b95d665965f49117e6ef5cabc62ae65b5c921ca86c5f53ab5f55f97 +size 9202020 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_diff.png new file mode 100644 index 00000000..98d0d270 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dbe47dc0d50b3b5917d94f92c667a1068de776cf1b1af9f931358671a8e8a677 +size 8834304 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_green_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_green_diff.png new file mode 100644 index 00000000..3241c1df --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_curtain_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a1141c908bbbcc66064ef0cd1888d26e4493560ca1a8add94ba96e4413ef0b5 +size 8325274 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_details_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_details_diff.png new file mode 100644 index 00000000..4b8f6202 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_details_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01012e0e81c20b10856dd34476069aadf1270cedd47e13b2760ae7dec341a7ab +size 1342967 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_details_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_details_spec.png new file mode 100644 index 00000000..da36d159 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_details_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:405eb35e24f254a9ff4de6f8021f847e92af5d95ad91dfd5c88c239c0bbfeec0 +size 618549 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_blue_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_blue_diff.png new file mode 100644 index 00000000..9076f08c --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7398d4f96ac101b92a42f8e093754fa239bb80e0038727e49574abed5473c20 +size 2097497 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_diff.png new file mode 100644 index 00000000..5d0dffb8 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fe1ee45005ddcbcde414096c1018c9296e5dfed528ecc99f9ce7d82862fd963 +size 2208126 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_green_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_green_diff.png new file mode 100644 index 00000000..efcf8d11 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb009dd943c52da29e3d7dd4d30e12a912769ffc7659e97dba7a2483fa79c6c3 +size 2162350 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_purple.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_purple.png new file mode 100644 index 00000000..1b8b68d4 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_purple.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1de10bfe0c410f33e3a54aa4987bf7e7c209b3f00190779d1ce73001261bb294 +size 1104562 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_spec.png new file mode 100644 index 00000000..ffbf88f6 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_fabric_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f44c12f0749297ec5cfa73a6d867b8771cb366eb47233ff989c15f674e3573a0 +size 462762 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_diff.png new file mode 100644 index 00000000..74ada029 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c65b8651f12a05063118a91bd2c1ebb37a403936bb2b79226cf842917ebfbcbe +size 1314735 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_spec.png new file mode 100644 index 00000000..71e423ba --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_flagpole_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e19367ea4099b185b86e9cbf932b54d2c7ec24ec4d7ed281adf8467d9be85af2 +size 597329 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_diff.png new file mode 100644 index 00000000..cfb4a235 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec677f8d95abc307a7551a501ed20c9cd79bbc38d41963a7d74a35d096d2f1c4 +size 1881715 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_spec.png new file mode 100644 index 00000000..bd239723 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_floor_a_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a46518c046ccb196bb25bc72c89546dca8625fc278de6a34256789e84d3cfdc +size 730796 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_roof_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_roof_diff.png new file mode 100644 index 00000000..3fda470d --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_roof_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be5c0e86671a709c5d2f87820f92414bf4c069c5041d2fb548f8bf130f7616dd +size 2280888 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_bump.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_bump.png new file mode 100644 index 00000000..98ba0b93 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fddd9ab74a4ca2b63feba790102407aaeb1c3c675595f8836e9b97b783f7019c +size 35900 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_diff.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_diff.png new file mode 100644 index 00000000..a5f3256a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbe4564dcfbba7f225f6df00caa92365cf653d6bf496bb3da59b164fa1c84aac +size 450994 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_mask.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_mask.png new file mode 100644 index 00000000..f8797993 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_mask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57f195177f3ff443e43eb7590859feb4c89164107ea69d6f26ee0a1deefa5c7b +size 68251 diff --git a/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_spec.png b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_spec.png new file mode 100644 index 00000000..997cd52c --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/sponza_thorn_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1576e5befee26cebb25be28626980e34d4cfd306968772b1359a8713c7d5cebc +size 360991 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_bump.png b/Techniques/PostProcessing/DepthOfField/textures/vase_bump.png new file mode 100644 index 00000000..76e12c82 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e93b7ae479ffee85ea789c75cd4d12e96c813db73d914d13d3403ca379c0eb1f +size 431658 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_dif.png b/Techniques/PostProcessing/DepthOfField/textures/vase_dif.png new file mode 100644 index 00000000..a4e2440a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_dif.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:141d957726bb80708e3210d481c82d4038016cc31e414c541eea76d61e600bd5 +size 1739865 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_hanging.png b/Techniques/PostProcessing/DepthOfField/textures/vase_hanging.png new file mode 100644 index 00000000..9a5fb329 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_hanging.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:310b171c5508c7f1df97cc87ebb2139141f4fbf6cd65d6cf1675e92ed64521b6 +size 1240906 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_plant.png b/Techniques/PostProcessing/DepthOfField/textures/vase_plant.png new file mode 100644 index 00000000..ac8efb8a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_plant.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e3e7cdcc544beec19338b7e3f33e7814847b1e73294f4bae4c18d3740a7b1e1 +size 817124 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_plant_mask.png b/Techniques/PostProcessing/DepthOfField/textures/vase_plant_mask.png new file mode 100644 index 00000000..89deb77a --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_plant_mask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d179d56d0750c9e64200bdc17b65c11ff8bda6a593f4d1453df05ade1a70927 +size 85746 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_plant_spec.png b/Techniques/PostProcessing/DepthOfField/textures/vase_plant_spec.png new file mode 100644 index 00000000..ecfe3d11 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_plant_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2332e35c817e17fe0185a6c246ac68bd38ad73c33372b86a887362a2e485402 +size 716987 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_round.png b/Techniques/PostProcessing/DepthOfField/textures/vase_round.png new file mode 100644 index 00000000..95a252f9 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_round.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ee2138dc016aff582e50c2725b7749cdf0681537147d3cd9034e0d10414fb7c +size 1798469 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_round_bump.png b/Techniques/PostProcessing/DepthOfField/textures/vase_round_bump.png new file mode 100644 index 00000000..8473991e --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_round_bump.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0bf21985bf48a5392f7faba4e043b77582512cd88866c9b1cff4ec0939c19b1f +size 77501 diff --git a/Techniques/PostProcessing/DepthOfField/textures/vase_round_spec.png b/Techniques/PostProcessing/DepthOfField/textures/vase_round_spec.png new file mode 100644 index 00000000..81786d79 --- /dev/null +++ b/Techniques/PostProcessing/DepthOfField/textures/vase_round_spec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfe9e52cae7cf1fe654ca7088916e29405bde0150812ac419f0da74467c4db0a +size 1697907 diff --git a/Techniques/PostProcessing/GaussBlur/GaussBlur.gg b/Techniques/PostProcessing/GaussBlur/GaussBlur.gg new file mode 100644 index 00000000..c0e766ad --- /dev/null +++ b/Techniques/PostProcessing/GaussBlur/GaussBlur.gg @@ -0,0 +1,217 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "Sigma", + "comment": "Strength of blur. Standard deviation of gaussian distribution.", + "type": "Float", + "dflt": "1.0f", + "visibility": "User" + }, + { + "name": "Support", + "comment": "From 0 to 1. Controls the size of the filter by specifying how much of the Gaussian distribution to account for. 1 is infinitely large. 0.995 is more reasonable.", + "type": "Float", + "dflt": "0.995", + "visibility": "User" + }, + { + "name": "sRGB", + "comment": "set to true if input is an sRGB format texture", + "type": "Bool", + "dflt": "false", + "visibility": "User" + }, + { + "name": "Disable", + "type": "Bool", + "dflt": "false", + "visibility": "User" + } + ], + "shaders": [ + { + "name": "GaussBlurCS", + "fileName": "GaussBlurCS.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Input", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Output", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "DoBlurH", + "editorPos": [ + -31.0, + 1.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsFalse" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "Input", + "dstPin": "resource" + }, + { + "srcPin": "Output", + "dstNode": "Temp", + "dstPin": "resource" + } + ], + "shader": { + "name": "GaussBlurCS" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + }, + "defines": [ + { + "name": "BLURH", + "value": "1" + } + ] + } + }, + { + "resourceTexture": { + "name": "Input", + "editorPos": [ + -181.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "resourceTexture": { + "name": "Output", + "editorPos": [ + 11.0, + 98.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Input" + } + }, + "size": { + "node": { + "name": "Input" + } + } + } + }, + { + "actionCopyResource": { + "name": "DontBlur", + "editorPos": [ + 324.0, + -1.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsTrue" + }, + "linkProperties": [ + {}, + {} + ], + "source": { + "node": "DoBlurH", + "pin": "Input" + }, + "dest": { + "node": "DoBlurV", + "pin": "Output" + } + } + }, + { + "actionComputeShader": { + "name": "DoBlurV", + "editorPos": [ + 149.0, + 44.0 + ], + "condition": { + "variable1": "Disable", + "comparison": "IsFalse" + }, + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "DoBlurH", + "dstPin": "Output" + }, + { + "srcPin": "Output", + "dstNode": "Output", + "dstPin": "resource" + } + ], + "shader": { + "name": "GaussBlurCS" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + }, + "defines": [ + { + "name": "BLURH", + "value": "0" + } + ] + } + }, + { + "resourceTexture": { + "name": "Temp", + "editorPos": [ + -181.0, + 50.0 + ], + "visibility": "Exported", + "format": { + "node": { + "name": "Input" + } + }, + "size": { + "node": { + "name": "Input" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/PostProcessing/GaussBlur/GaussBlur.gguser b/Techniques/PostProcessing/GaussBlur/GaussBlur.gguser new file mode 100644 index 00000000..35ed5672 --- /dev/null +++ b/Techniques/PostProcessing/GaussBlur/GaussBlur.gguser @@ -0,0 +1,33 @@ +{ + "version": "2.0", + "snapshot": { + "resourceViewNodeIndex": 4, + "resourceViewResourceIndex": 3, + "importedResources": [ + { + "nodeName": "Input", + "texture": { + "fileName": "..\\..\\logo.png" + } + } + ], + "savedVariables": [ + { + "name": "Sigma", + "value": "2.000000" + }, + { + "name": "Support", + "value": "0.995000" + }, + { + "name": "sRGB", + "value": "true" + }, + { + "name": "Disable", + "value": "false" + } + ] + } +} \ No newline at end of file diff --git a/Techniques/PostProcessing/GaussBlur/GaussBlurCS.hlsl b/Techniques/PostProcessing/GaussBlur/GaussBlurCS.hlsl new file mode 100644 index 00000000..23986f1c --- /dev/null +++ b/Techniques/PostProcessing/GaussBlur/GaussBlurCS.hlsl @@ -0,0 +1,87 @@ +// Unnamed technique, shader GaussBlurCS +/*$(ShaderResources)*/ + +// Calculations adapted from http://demofox.org/gauss.html + +#define c_sigma /*$(Variable:Sigma)*/ +#define c_support /*$(Variable:Support)*/ + +float erf(float x) +{ + // save the sign of x + float sign = (x >= 0) ? 1 : -1; + x = abs(x); + + // constants + static const float a1 = 0.254829592; + static const float a2 = -0.284496736; + static const float a3 = 1.421413741; + static const float a4 = -1.453152027; + static const float a5 = 1.061405429; + static const float p = 0.3275911; + + // A&S formula 7.1.26 + float t = 1.0/(1.0 + p*x); + float y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-x * x); + return sign * y; // erf(-x) = -erf(x); +} + +float IntegrateGaussian(float x, float sigma) +{ + float p1 = erf((x-0.5)/sigma*sqrt(0.5)); + float p2 = erf((x+0.5)/sigma*sqrt(0.5)); + return (p2-p1)/2.0; +} + +float3 LinearToSRGB(float3 linearCol) +{ + float3 sRGBLo = linearCol * 12.92; + float3 sRGBHi = (pow(abs(linearCol), float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055; + float3 sRGB; + sRGB.r = linearCol.r <= 0.0031308 ? sRGBLo.r : sRGBHi.r; + sRGB.g = linearCol.g <= 0.0031308 ? sRGBLo.g : sRGBHi.g; + sRGB.b = linearCol.b <= 0.0031308 ? sRGBLo.b : sRGBHi.b; + return sRGB; +} + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + int2 px = DTid.xy; + int2 maxPx; + Input.GetDimensions(maxPx.x, maxPx.y); + maxPx -= int2(1,1); + + // calculate radius of our blur based on sigma and support percentage + const int radius = int(ceil(sqrt(-2.0 * c_sigma * c_sigma * log(1.0 - c_support)))); + + // initialize values + float weight = 0.0f; + float3 color = float3(0.0f, 0.0f, 0.0f); + + // loop horizontally or vertically, as appropriate + for (int index = -radius; index <= radius; ++index) + { + float kernel = IntegrateGaussian(index, c_sigma); + + int2 offset = (BLURH) ? int2(index, 0) : int2(0, index); + + int2 readPx = clamp(px + offset, int2(0, 0), maxPx); + + color += Input[readPx].rgb * kernel; + weight += kernel; + } + + // normalize blur + color /= weight; + + if (/*$(Variable:sRGB)*/) + color = LinearToSRGB(color); + + Output[px] = float4(color, 1.0f); +} + +/* +Shader Resources: + Texture Input (as SRV) + Texture Output (as UAV) +*/ diff --git a/Techniques/PostProcessing/TemporalAccumulation/Accumulate.hlsl b/Techniques/PostProcessing/TemporalAccumulation/Accumulate.hlsl new file mode 100644 index 00000000..c1dd43fb --- /dev/null +++ b/Techniques/PostProcessing/TemporalAccumulation/Accumulate.hlsl @@ -0,0 +1,22 @@ +// Unnamed technique, shader TemporalAccum +/*$(ShaderResources)*/ + +/*$(_compute:csmain)*/(uint3 DTid : SV_DispatchThreadID) +{ + float alpha = (/*$(Variable:Reset)*/ || !/*$(Variable:Enabled)*/) + ? 1.0f + : /*$(Variable:Alpha)*/; + + uint2 px = DTid.xy; + + float4 oldValue = Accum[px]; + float4 newValue = Input[px]; + + Accum[px] = lerp(oldValue, newValue, alpha); +} + +/* +Shader Resources: + Texture Input (as SRV) + Texture Accum (as UAV) +*/ diff --git a/Techniques/PostProcessing/TemporalAccumulation/TemporalAccumulation.gg b/Techniques/PostProcessing/TemporalAccumulation/TemporalAccumulation.gg new file mode 100644 index 00000000..4952af9b --- /dev/null +++ b/Techniques/PostProcessing/TemporalAccumulation/TemporalAccumulation.gg @@ -0,0 +1,114 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "variables": [ + { + "name": "Alpha", + "comment": "For exponential moving average. From 0 to 1. TAA commonly uses 0.1.", + "type": "Float", + "dflt": "0.1f", + "visibility": "User" + }, + { + "name": "Enabled", + "type": "Bool", + "dflt": "true", + "visibility": "User" + }, + { + "name": "Reset", + "type": "Bool", + "dflt": "false", + "visibility": "User", + "UISettings": { + "UIHint": "Button" + } + } + ], + "shaders": [ + { + "name": "Accumulate", + "fileName": "Accumulate.hlsl", + "entryPoint": "csmain", + "resources": [ + { + "name": "Input", + "type": "Texture", + "access": "SRV" + }, + { + "name": "Accum", + "type": "Texture", + "access": "UAV" + } + ] + } + ], + "nodes": [ + { + "resourceTexture": { + "name": "Input", + "editorPos": [ + -37.0, + -14.0 + ], + "visibility": "Imported" + } + }, + { + "actionComputeShader": { + "name": "DoAccum", + "editorPos": [ + 75.0, + 2.0 + ], + "linkProperties": [ + {}, + {}, + {} + ], + "connections": [ + { + "srcPin": "Input", + "dstNode": "Input", + "dstPin": "resource" + }, + { + "srcPin": "Accum", + "dstNode": "Accum", + "dstPin": "resource" + } + ], + "shader": { + "name": "Accumulate" + }, + "dispatchSize": { + "node": { + "name": "Input" + } + } + } + }, + { + "resourceTexture": { + "name": "Accum", + "editorPos": [ + -37.0, + 50.0 + ], + "transient": false, + "visibility": "Exported", + "format": { + "node": { + "name": "Input" + } + }, + "size": { + "node": { + "name": "Input" + } + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/assertFormatting.gg b/Techniques/UnitTests/ShaderAssert/assertFormatting.gg new file mode 100644 index 00000000..f95a4f20 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/assertFormatting.gg @@ -0,0 +1,28 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "assertFormatting_CS", + "fileName": "assertFormatting_cs.hlsl", + "entryPoint": "main_cs" + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "Node 1", + "editorPos": [ + 492.0, + 1145.0 + ], + "linkProperties": [ + {} + ], + "shader": { + "name": "AssertFormatting_CS" + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/assertFormatting_cs.hlsl b/Techniques/UnitTests/ShaderAssert/assertFormatting_cs.hlsl new file mode 100644 index 00000000..de6f5405 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/assertFormatting_cs.hlsl @@ -0,0 +1,13 @@ +// Unnamed technique, shader simpleAssertYES_cs +/*$(ShaderResources)*/ + +/*$(_compute:main_cs)*/(uint3 DTid : SV_DispatchThreadID) +{ + float v0 = 1.1; + float v1 = 1.2; + float v2 = 1.3; + float v3 = 1.4; + float v4 = 1.5; + float v5 = 1.6; + /*$(Assert: 1>4, "v0:%.1f v1:%.1f v2:%.1f v3:%.1f v4:%.1f v5:%.1f", v0, v1, v2, v3, v4, v5 )*/ +} diff --git a/Techniques/UnitTests/ShaderAssert/assertsTest.py b/Techniques/UnitTests/ShaderAssert/assertsTest.py new file mode 100644 index 00000000..e6129445 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/assertsTest.py @@ -0,0 +1,175 @@ +import Host + +# don't save gguser files during this script execution +Host.DisableGGUserSave(True) + +class AssertInfo: + def __init__(self, assertId = -1): + if assertId >= 0: + self.fmtId = Host.GetShaderAssertFormatStrId(assertId) + self.msg = Host.GetShaderAssertMsg(assertId) + self.displayName = Host.GetShaderAssertDisplayName(assertId) + else: + self.fmtId = 0 + self.msg = '' + self.displayName = '' + + def __eq__(self, r): + return self.fmtId == r.fmtId and self.msg == r.msg and self.displayName == r.displayName + + @staticmethod + def construct(fmtId, msg, displayName): + a = AssertInfo() + a.fmtId = fmtId + a.msg = msg + a.displayName = displayName + return a + + def __str__(self) : + return f"\nAssert:{{\n DisplayName:{self.displayName}, \n msg:{self.msg}, \n fmtId:{self.fmtId}\n}}" + +def getCollectedAsserts(): + assertsCount = Host.GetCollectedShaderAssertsCount() + return [AssertInfo(assertId) for assertId in range(0, assertsCount)] + +def assertsToStr(asserts): + return '\n'.join([f"{a}" for a in asserts]) + +def runTechniques(): + #skip frame in flight + Host.RunTechnique() + Host.RunTechnique() + Host.RunTechnique() + +Tasks = [ + { + 'name' : "TEST BASIC ASSERT: VS:YES, PS:YES", + 'gg' : "Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(0, "\"VS\"", "Node_1.__simpleAssertYES_VS__GigiAssertUAV"), + AssertInfo.construct(1, "\"PS\"", "Node_1.__simpleAssertYES_PS__GigiAssertUAV") + ], + } + }, + { + 'name' : "TEST BASIC ASSERT: VS:NO, PS:YES", + 'gg' : "Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(1, "\"PS\"", "Node_1.__simpleAssertYES_PS__GigiAssertUAV") + ], + } + }, + { + 'name' : "TEST BASIC ASSERT: CS:YES", + 'gg' : "Techniques/UnitTests/ShaderAssert/simpleAssertCsYes.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(0, "\"CS\"", "Node_1.__simpleAssertYES_CS__GigiAssertUAV") + ], + } + }, + { + 'name' : "ASSERT FORMATTING: COMPLEX FMT", + 'gg' : "Techniques/UnitTests/ShaderAssert/assertFormatting.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(0, "\"v0:1.1 v1:1.2 v2:1.3 v3:1.4 v4:1.5 v5:1.6\"", "Node_1.__assertFormatting_CS__GigiAssertUAV") + ], + } + }, + { + 'name' : "ASSERT FORMATTING: NO FMT STRING", + 'gg' : "Techniques/UnitTests/ShaderAssert/noFmtStringAssert.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(0, "1>4", "Node_1.__noFmtStringAssert_CS__GigiAssertUAV") + ], + } + }, + { + 'name' : "SAME CS SHADER AND SUBGRAPH", + 'gg' : "Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gg", + 'expected' : { + 'asserts' : [ + AssertInfo.construct(0, "1>4", "MainNode.__noFmtStringAssert_CS__GigiAssertUAV"), + AssertInfo.construct(0, "1>4", "SubGraphNode_InsideSubGraphNode.__SubGraphNode_noFmtStringAssert_CS__GigiAssertUAV") + ], + } + }, +] + +def DoTask(task, i): + name = task['name'] + + Host.Log("Info", f"Processing Assert test '{name} [{i+1}/{len(Tasks)}]'") + + if not Host.LoadGG(task['gg']): + return [False, f"Failed to load {task['gg']}"] + + runTechniques() + Host.WaitOnGPU() + + expected = task['expected'] + + collectedAsserts = getCollectedAsserts() + expectedAssertsCount = len(expected['asserts']) + + if not expectedAssertsCount == len(collectedAsserts): + return [False, f"Wrong fired asserts count expected:{expectedAssertsCount}," + + f"got:{len(collectedAsserts)}.\n\nFIRED ASSERTS: {assertsToStr(collectedAsserts)}" + + f"\n\nEXPECTED ASSERTS: {assertsToStr(expected['asserts'])}" + ] + + invalidAsserts = [] + for i in range(0, len(collectedAsserts)): + expectedAssert = expected['asserts'][i] + collectedAssert = collectedAsserts[i] + if not expectedAssert == collectedAssert: + invalidAsserts.append([i, expectedAssert, collectedAssert]) + + if len(invalidAsserts) != 0: + header = '\n------' + return [False, f"Unexpected asserts:\n" + + header + + header.join([f"\n i:{a[0]}\n EXPECTED:\n{a[1]}\n GOT:{a[2]}\n" for a in invalidAsserts])] + + + return [True, ''] + +def DoTasks(): + totalTasks = len(Tasks) + + failedTasks = [] + for i in range(0, totalTasks): + task = Tasks[i] + res = DoTask(task, i) + if res[0] == False: + failedTasks.append([task, res[1]]) + + failedTasksCount = len(failedTasks) + if failedTasksCount > 0: + header = '\n-----------------------' + resultStr = header + header.join( + [f"\nFAILED_ASSERT_TASK:\n name:{failedTasks[i][0]['name']}\n gg: {failedTasks[i][0]['gg']}\n msg: {failedTasks[i][1]}" for i in range(0, len(failedTasks))] + ) + Host.Log("Error", f"\nShader Asserts failed tasks [{len(failedTasks)}/{totalTasks}]\n {resultStr}") + return False + + return True + +def DoTest(): + Host.SetShaderAssertsLogging(False) + TestPassed = DoTasks() + Host.Log("Info", f"Finished processing of the {len(Tasks)} Shader Assert tests") + Host.SetShaderAssertsLogging(True) + + return TestPassed + +# This is so the test can be ran by itself directly +if __name__ == "builtins": + if DoTest(): + Host.Log("Info", "test Passed") + else: + Host.Log("Error", "Test Failed") diff --git a/Techniques/UnitTests/ShaderAssert/noFmtStringAssert.gg b/Techniques/UnitTests/ShaderAssert/noFmtStringAssert.gg new file mode 100644 index 00000000..6772bb93 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/noFmtStringAssert.gg @@ -0,0 +1,28 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "noFmtStringAssert_CS", + "fileName": "noFmtStringAssert_cs.hlsl", + "entryPoint": "main_cs" + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "Node 1", + "editorPos": [ + -101.0, + -30.0 + ], + "linkProperties": [ + {} + ], + "shader": { + "name": "noFmtStringAssert_CS" + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/noFmtStringAssertWithStub_cs.hlsl b/Techniques/UnitTests/ShaderAssert/noFmtStringAssertWithStub_cs.hlsl new file mode 100644 index 00000000..8775fcf9 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/noFmtStringAssertWithStub_cs.hlsl @@ -0,0 +1,9 @@ +// Unnamed technique, shader simpleAssertYES_cs +/*$(ShaderResources)*/ + +/*$(_compute:main_cs)*/(uint3 DTid : SV_DispatchThreadID) +{ + /*$(Assert:1>4)*/ + uint dim, stride; + stub_uav.GetDimensions(dim, stride); +} diff --git a/Techniques/UnitTests/ShaderAssert/noFmtStringAssert_cs.hlsl b/Techniques/UnitTests/ShaderAssert/noFmtStringAssert_cs.hlsl new file mode 100644 index 00000000..ea93b1cd --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/noFmtStringAssert_cs.hlsl @@ -0,0 +1,7 @@ +// Unnamed technique, shader simpleAssertYES_cs +/*$(ShaderResources)*/ + +/*$(_compute:main_cs)*/(uint3 DTid : SV_DispatchThreadID) +{ + /*$(Assert:1>4)*/ +} diff --git a/Techniques/UnitTests/ShaderAssert/noFmtStringSubgraph.gg b/Techniques/UnitTests/ShaderAssert/noFmtStringSubgraph.gg new file mode 100644 index 00000000..7186a63d --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/noFmtStringSubgraph.gg @@ -0,0 +1,56 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "noFmtStringAssert_CS", + "fileName": "noFmtStringAssertWithStub_cs.hlsl", + "entryPoint": "main_cs", + "resources": [ + { + "name": "stub_uav", + "type": "Buffer", + "access": "UAV", + "buffer": { + "type": "Float" + } + } + ] + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "InsideSubGraphNode", + "editorPos": [ + -37.0, + 18.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "stub_uav", + "dstNode": "stub_res_node", + "dstPin": "resource" + } + ], + "shader": { + "name": "noFmtStringAssert_CS" + } + } + }, + { + "resourceBuffer": { + "name": "stub_res_node", + "editorPos": [ + -165.0, + 18.0 + ], + "visibility": "Imported" + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gg b/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gg new file mode 100644 index 00000000..54fa6a94 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gg @@ -0,0 +1,83 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "noFmtStringAssert_CS", + "fileName": "noFmtStringAssertWithStub_cs.hlsl", + "entryPoint": "main_cs", + "resources": [ + { + "name": "stub_uav", + "type": "Buffer", + "access": "UAV", + "buffer": { + "type": "Float" + } + } + ] + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "MainNode", + "editorPos": [ + -91.0, + 18.0 + ], + "linkProperties": [ + {}, + {} + ], + "connections": [ + { + "srcPin": "stub_uav", + "dstNode": "Node 2", + "dstPin": "resource" + } + ], + "shader": { + "name": "noFmtStringAssert_CS" + } + } + }, + { + "resourceBuffer": { + "name": "Node 2", + "editorPos": [ + -245.0, + 82.0 + ], + "format": { + "type": "Float" + } + } + }, + { + "actionSubGraph": { + "name": "SubGraphNode", + "editorPos": [ + 132.0, + 2.0 + ], + "linkProperties": [ + {} + ], + "connections": [ + { + "srcPin": "stub_res_node", + "dstNode": "MainNode", + "dstPin": "stub_uav" + } + ], + "fileName": "noFmtStringSubgraph.gg", + "subGraphData": { + "importedResources": [ + "stub_res_node" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gguser b/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gguser new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/sameShaderWithSubgraphs.gguser @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertCsYes.gg b/Techniques/UnitTests/ShaderAssert/simpleAssertCsYes.gg new file mode 100644 index 00000000..392bb795 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertCsYes.gg @@ -0,0 +1,28 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "simpleAssertYES_CS", + "fileName": "simpleAssertYES_cs.hlsl", + "entryPoint": "main_cs" + } + ], + "nodes": [ + { + "actionComputeShader": { + "name": "Node 1", + "editorPos": [ + 534.0, + 1151.0 + ], + "linkProperties": [ + {} + ], + "shader": { + "name": "simpleAssertYES_CS" + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertNO_vs.hlsl b/Techniques/UnitTests/ShaderAssert/simpleAssertNO_vs.hlsl new file mode 100644 index 00000000..6fa06677 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertNO_vs.hlsl @@ -0,0 +1,15 @@ +// Unnamed technique, shader simpleAssertYES_VS +/*$(ShaderResources)*/ + +struct VSOutput // AKA PSInput +{ + float4 position : SV_POSITION; +}; + +VSOutput main_vs() +{ + /*$(Assert: 1<2, "VS")*/ + + VSOutput ret = (VSOutput)0; + return ret; +} diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gg b/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gg new file mode 100644 index 00000000..41d9ff20 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gg @@ -0,0 +1,80 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "simpleAssertNO_VS", + "fileName": "simpleAssertNO_vs.hlsl", + "type": "Vertex", + "entryPoint": "main_vs" + }, + { + "name": "simpleAssertYES_PS", + "fileName": "simpleAssertYES_ps.hlsl", + "type": "Pixel", + "entryPoint": "main_ps" + } + ], + "nodes": [ + { + "actionDrawCall": { + "name": "Node 1", + "editorPos": [ + 612.0, + 1063.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "vertexShader": { + "name": "simpleAssertNO_VS" + }, + "pixelShader": { + "name": "simpleAssertYES_PS" + }, + "countPerInstance": 4, + "depthWrite": false, + "colorTargets": [ + { + "node": "Node 2", + "pin": "resource" + }, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "geometryType": "PointList" + } + }, + { + "resourceTexture": { + "name": "Node 2", + "editorPos": [ + 443.0, + 1170.0 + ], + "visibility": "Exported", + "format": { + "format": "RGBA8_Unorm" + }, + "size": { + "multiply": [ + 256, + 256, + 1 + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gguser b/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gguser new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertVsNoPsYes.gguser @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gg b/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gg new file mode 100644 index 00000000..7ec38ab5 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gg @@ -0,0 +1,80 @@ +{ + "$schema": "gigischema.json", + "version": "0.99b", + "shaders": [ + { + "name": "simpleAssertYES_VS", + "fileName": "simpleAssertYES_vs.hlsl", + "type": "Vertex", + "entryPoint": "main_vs" + }, + { + "name": "simpleAssertYES_PS", + "fileName": "simpleAssertYES_ps.hlsl", + "type": "Pixel", + "entryPoint": "main_ps" + } + ], + "nodes": [ + { + "actionDrawCall": { + "name": "Node 1", + "editorPos": [ + 612.0, + 1063.0 + ], + "linkProperties": [ + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "vertexShader": { + "name": "simpleAssertYES_VS" + }, + "pixelShader": { + "name": "simpleAssertYES_PS" + }, + "countPerInstance": 4, + "depthWrite": false, + "colorTargets": [ + { + "node": "Node 2", + "pin": "resource" + }, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "geometryType": "PointList" + } + }, + { + "resourceTexture": { + "name": "Node 2", + "editorPos": [ + 443.0, + 1170.0 + ], + "visibility": "Exported", + "format": { + "format": "RGBA8_Unorm" + }, + "size": { + "multiply": [ + 256, + 256, + 1 + ] + } + } + } + ] +} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gguser b/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gguser new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertVsYesPsYes.gguser @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertYES_cs.hlsl b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_cs.hlsl new file mode 100644 index 00000000..b72a95e4 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_cs.hlsl @@ -0,0 +1,7 @@ +// Unnamed technique, shader simpleAssertYES_cs +/*$(ShaderResources)*/ + +/*$(_compute:main_cs)*/(uint3 DTid : SV_DispatchThreadID) +{ + /*$(Assert: 1>4, "CS")*/ +} diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertYES_ps.hlsl b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_ps.hlsl new file mode 100644 index 00000000..3e89f3f8 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_ps.hlsl @@ -0,0 +1,29 @@ +// Unnamed technique, shader simpleAssertYES_PS +/*$(ShaderResources)*/ + + +#line 2 + + +struct PSInput // AKA VSOutput +{ + float4 position : SV_POSITION; + //TODO: fill this out +}; + +struct PSOutput +{ + float4 colorTarget : SV_Target0; + //TODO: fill this out +}; + +PSOutput main_ps(PSInput input) +{ + /*$(Assert: 2>5, "PS" )*/ + + + + PSOutput ret = (PSOutput)0; + // TODO: fill this out + return ret; +} diff --git a/Techniques/UnitTests/ShaderAssert/simpleAssertYES_vs.hlsl b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_vs.hlsl new file mode 100644 index 00000000..ea248d01 --- /dev/null +++ b/Techniques/UnitTests/ShaderAssert/simpleAssertYES_vs.hlsl @@ -0,0 +1,15 @@ +// Unnamed technique, shader simpleAssertYES_VS +/*$(ShaderResources)*/ + +struct VSOutput // AKA PSInput +{ + float4 position : SV_POSITION; +}; + +VSOutput main_vs() +{ + /*$(Assert: 5<2, "VS")*/ + + VSOutput ret = (VSOutput)0; + return ret; +} diff --git a/UserDocumentation/GigiShaders_Documentation.docx b/UserDocumentation/GigiShaders_Documentation.docx index 9fc037b7..00ff466c 100644 Binary files a/UserDocumentation/GigiShaders_Documentation.docx and b/UserDocumentation/GigiShaders_Documentation.docx differ diff --git a/UserDocumentation/GigiShaders_Documentation.pdf b/UserDocumentation/GigiShaders_Documentation.pdf index 544e431f..986ef2ab 100644 Binary files a/UserDocumentation/GigiShaders_Documentation.pdf and b/UserDocumentation/GigiShaders_Documentation.pdf differ diff --git a/UserDocumentation/GigiViewerDX12_Documentation.docx b/UserDocumentation/GigiViewerDX12_Documentation.docx index 6c96afdf..b8296f3b 100644 Binary files a/UserDocumentation/GigiViewerDX12_Documentation.docx and b/UserDocumentation/GigiViewerDX12_Documentation.docx differ diff --git a/UserDocumentation/GigiViewerDX12_Documentation.pdf b/UserDocumentation/GigiViewerDX12_Documentation.pdf index 7c9d5dc7..e01a8ef8 100644 Binary files a/UserDocumentation/GigiViewerDX12_Documentation.pdf and b/UserDocumentation/GigiViewerDX12_Documentation.pdf differ diff --git a/UserDocumentation/PythonTypes.txt b/UserDocumentation/PythonTypes.txt index 980ca65d..bd80e5bb 100644 --- a/UserDocumentation/PythonTypes.txt +++ b/UserDocumentation/PythonTypes.txt @@ -419,23 +419,24 @@ Host.GigiCompileResult_WrongVersion = 1 Host.GigiCompileResult_WrongParams = 2 Host.GigiCompileResult_CantLoadRenderGraph = 3 - Host.GigiCompileResult_ShaderReflection = 4 - Host.GigiCompileResult_Validation = 5 - Host.GigiCompileResult_ReferenceFixup = 6 - Host.GigiCompileResult_DepluralizeFileCopies = 7 - Host.GigiCompileResult_NoBackend = 8 - Host.GigiCompileResult_BackendData = 9 - Host.GigiCompileResult_Sanitize = 10 - Host.GigiCompileResult_NotCompiledYet = 11 - Host.GigiCompileResult_InterpreterError = 12 - Host.GigiCompileResult_InlineSubGraphs = 13 - Host.GigiCompileResult_ErrorCheck = 14 - Host.GigiCompileResult_ShaderFileDuplication = 15 - Host.GigiCompileResult_AddNodeInfoToShaders = 16 - Host.GigiCompileResult_DataFixup = 17 - Host.GigiCompileResult_DfltFixup = 18 - Host.GigiCompileResult_LAST = 18 - Host.GigiCompileResult_COUNT = 19 + Host.GigiCompileResult_ShaderAsserts = 4 + Host.GigiCompileResult_ShaderReflection = 5 + Host.GigiCompileResult_Validation = 6 + Host.GigiCompileResult_ReferenceFixup = 7 + Host.GigiCompileResult_DepluralizeFileCopies = 8 + Host.GigiCompileResult_NoBackend = 9 + Host.GigiCompileResult_BackendData = 10 + Host.GigiCompileResult_Sanitize = 11 + Host.GigiCompileResult_NotCompiledYet = 12 + Host.GigiCompileResult_InterpreterError = 13 + Host.GigiCompileResult_InlineSubGraphs = 14 + Host.GigiCompileResult_ErrorCheck = 15 + Host.GigiCompileResult_ShaderFileDuplication = 16 + Host.GigiCompileResult_AddNodeInfoToShaders = 17 + Host.GigiCompileResult_DataFixup = 18 + Host.GigiCompileResult_DfltFixup = 19 + Host.GigiCompileResult_LAST = 19 + Host.GigiCompileResult_COUNT = 20 GigiCompileWarning: Host.GigiCompileWarning_FIRST = 0 @@ -468,11 +469,13 @@ Host.SetVariableOperator_Divide = 3 Host.SetVariableOperator_Modulo = 4 Host.SetVariableOperator_PowerOf2GE = 5 - Host.SetVariableOperator_BitwiseOr = 6 - Host.SetVariableOperator_BitwiseAnd = 7 - Host.SetVariableOperator_BitwiseXor = 8 - Host.SetVariableOperator_BitwiseNot = 9 - Host.SetVariableOperator_Noop = 10 - Host.SetVariableOperator_LAST = 10 - Host.SetVariableOperator_COUNT = 11 + Host.SetVariableOperator_Minimum = 6 + Host.SetVariableOperator_Maximum = 7 + Host.SetVariableOperator_BitwiseOr = 8 + Host.SetVariableOperator_BitwiseAnd = 9 + Host.SetVariableOperator_BitwiseXor = 10 + Host.SetVariableOperator_BitwiseNot = 11 + Host.SetVariableOperator_Noop = 12 + Host.SetVariableOperator_LAST = 12 + Host.SetVariableOperator_COUNT = 13 diff --git a/external/df_serialize/Config.h b/external/df_serialize/Config.h index c368f06d..953cafda 100644 --- a/external/df_serialize/Config.h +++ b/external/df_serialize/Config.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "GigiAssert.h" // flags used by struct fields @@ -42,6 +43,7 @@ #define SCHEMA_FLAG_UI_COLLAPSABLE ((size_t) (1 << 1)) // This field should have a collapsable header #define SCHEMA_FLAG_UI_ARRAY_FATITEMS ((size_t) (1 << 2)) // If true, puts all items on the same line. #define SCHEMA_FLAG_NO_SERIALIZE ((size_t) (1 << 3)) // Don't load / save. Also don't show in UI, and don't generate equality tests. -#define SCHEMA_FLAG_UI_MULTILINETEXT ((size_t) (1 << 4)) // if true, the text edit box is multiline -#define SCHEMA_FLAG_UI_ARRAY_HIDE_INDEX ((size_t) (1 << 5)) // If true, does not show the index of array items -#define SCHEMA_FLAG_UI_CONST ((size_t) (1 << 6)) // If true, does not allow field to be edited +#define SCHEMA_FLAG_SERIALIZE_DFLT ((size_t) (1 << 4)) // Write value, even if it's the default value +#define SCHEMA_FLAG_UI_MULTILINETEXT ((size_t) (1 << 5)) // if true, the text edit box is multiline +#define SCHEMA_FLAG_UI_ARRAY_HIDE_INDEX ((size_t) (1 << 6)) // If true, does not show the index of array items +#define SCHEMA_FLAG_UI_CONST ((size_t) (1 << 7)) // If true, does not allow field to be edited diff --git a/external/df_serialize/MakeJSONWriteHeader.h b/external/df_serialize/MakeJSONWriteHeader.h index ae416fd3..5a269ae6 100644 --- a/external/df_serialize/MakeJSONWriteHeader.h +++ b/external/df_serialize/MakeJSONWriteHeader.h @@ -62,7 +62,7 @@ enum class JSONWriteOverrideResult if (((_FLAGS) & SCHEMA_FLAG_NO_SERIALIZE) == 0) \ { \ static const _TYPE c_defaultValue = _DEFAULT; \ - if (value._NAME != c_defaultValue) \ + if (value._NAME != c_defaultValue || (((_FLAGS) & SCHEMA_FLAG_SERIALIZE_DFLT) != 0)) \ ret.AddMember(#_NAME, MakeJSONValue(value._NAME, allocator), allocator); \ } @@ -91,7 +91,7 @@ enum class JSONWriteOverrideResult break; \ } \ } \ - if (different) \ + if (different || (((_FLAGS) & SCHEMA_FLAG_SERIALIZE_DFLT) != 0)) \ { \ rapidjson::Value arr; \ arr.SetArray(); \ diff --git a/gigihelp.html b/gigihelp.html index 3952862e..559b12b6 100644 --- a/gigihelp.html +++ b/gigihelp.html @@ -359,6 +359,7 @@

Enums

WrongVersion WrongParams CantLoadRenderGraph +ShaderAsserts ShaderReflection Validation ReferenceFixup @@ -412,6 +413,8 @@

Enums

Divide/ Modulo% PowerOf2GEThe next power of two, greater or equal to the current value +Minimummin(A,B) +Maximummax(A,B) BitwiseOrA | B BitwiseAndA & B BitwiseXorA ^ B @@ -448,6 +451,14 @@

Structs


+VariableReferenceConstOnly : A reference to a variable. Only const variables allowed.

+ + + + +
VariableReferenceConstOnly
std::string name""The name of the variable.
int variableIndex-1Calculated for convenience.
+
+ StructReference : A reference to a struct

@@ -687,6 +698,14 @@

Structs

StructReference

+TokenReplacement : A shader token replacement

+ + + + +
TokenReplacement
std::string name""The token string.
std::string value""The replacement.
+
+ LoadedTextureReference : Information about a loaded texture referenced by this shader.

@@ -723,6 +742,7 @@

Structs

+ @@ -756,12 +776,13 @@

Structs

- + + @@ -993,6 +1014,7 @@

Structs

+
LoadedTextureReference
ShaderType typeShaderType::ComputeThe type of shader it is
std::string entryPoint""The shader entrypoint.
ShaderDefine defines[]The defines the shader is compiled with.
TokenReplacement tokenReplacements[]The token replacements specific for the shader.
int CSNumThreads[3]{ 8 , 8 , 1 }For compute shaders only, the number of threads each dispatch has. 61,1,1 suggested for 1d. 8,8,1 for 2d. 4,4,4 for 3d.
int NumThreads[3]{ 8 , 8 , 1 }The number of threads each dispatch has, for applicable shader types. 64,1,1 suggested for 1d. 8,8,1 for 2d. 4,4,4 for 3d.
bool copyFiletrueif false, will not copy the file over. A hackaround for when you have multiple raytracing shaders in the same file. TODO: resolve this better.
DataFieldType typeDataFieldType::CountThe type of the variable
bool ConstfalseIf true, the variable is declared const and cannot change at runtime
bool StaticfalseIf true, the variable has the same value for all instances of the technique
std::string dflt""The default value of the variable
std::string dflt""The default value of the variable. The default memory is zero initialized before this is parsed, so if you don't give it enough initializers, it will use zero for the unlisted fields.
VariableVisibility visibilityVariableVisibility::InternalWho can see and interact with this variable
std::string Enum""Integer types can specify an enum, which will then make symbols in both C++ and shader code.
BackendRestriction backends{}This variable can be limited to specific backends
bool transientfalseIf true, the variable should not be saved between runs of this technique. The Gigi viewer uses this to decide if it should save it in the gguser file or not, for example.
VariableUISettings UISettings{}UI Settings.
std::string UIGroup""Used to organize variables into folders in the viewer. separate folders with dots. For instance: settings.controls
int enumIndex-1Calculated for convenience.
std::string originalName""The name before renames and sanitization
std::string scope""The scope that the node lives in. A possibly nested list of subgraph node names, seperated by a dot.
std::string name""variable name
VariableVisibility visibilityVariableVisibility::InternalWho can see and interact with this variable
std::string replaceWithStr{}If set, the subgraph variable will be deleted and all references will use this parent graph variable instead.
std::string replaceWithValue{}Replace the variable with a literal value. At gigi compile time it makes an internal private variable of the correct type with this string as the default value.
bool isLoopIndexfalseIf true, this variable will recieve the loop index.
VariableReference replaceWith{}If set, the subgraph variable will be deleted and all references will use this parent graph variable instead.
@@ -1014,7 +1036,7 @@

Structs

float editorPos[2]{ 0.0f , 0.0f }The position of the node in the editor std::unordered_map inputPinIds{} std::unordered_map outputPinIds{} -int nodeIndex-1The index in the list of render graph nodes +int nodeIndex-1The index in the list of render graph nodes. This is filled in after loading by the ReferenceFixupVisitor and is in [0,N) with no gaps. std::string originalName""The name before renames and sanitization
@@ -1189,6 +1211,7 @@

Structs

SubGraphData subGraphData{}A cache of the interface of the other graph. SubGraphVariableSettings variableSettings[]Per variable settings for subgraph variables. int loopCount1Number of times to execute the technique. +VariableReferenceConstOnly loopCountVariable{}The variable to use for the loopCount. Only const variables supported currently. int loopIndex-1When unrolling subgraph loops, the loop index of the node is stored here.
@@ -1327,6 +1350,7 @@

Structs

std::string JitteredViewProjMtx_varName"JitteredViewProjMtx"ViewProjMtx with jitter. std::string InvJitteredViewProjMtx_varName"InvJitteredViewProjMtx"Inverted ViewProjMtx with jitter. std::string CameraPos_varName"CameraPos" +std::string CameraAltitudeAzimuth_varName"CameraAltitudeAzimuth" std::string CameraChanged_varName"CameraChanged" std::string CameraJitter_varName"CameraJitter" std::string ShadingRateImageTileSize_varName"ShadingRateImageTileSize" @@ -1342,35 +1366,53 @@

Structs


-GGUserFile_Bookmark : A bookmark for resources to show up in a short list, to be more quickly found.

- - - - -
GGUserFile_Bookmark
std::string name""
std::string viewableResourceDisplayName""
-
- -GGUserFile_ImportedResourcePreset : A preset of imported resource settings

+GGUserFileV1 : The contents of a .gguser file

- - + + + + + + + +
GGUserFile_ImportedResourcePreset
std::string name""
GGUserFileV1
std::string version"1.0"The version of the .gguser file
GGUserFile_SystemVars systemVars{}
int resourceViewType0The type of resource being viewed
int resourceViewNodeIndex-1The index of the node bieng viewed
int resourceViewResourceIndex-1The index of that resource within that node being used
int syncInterval1IDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.
GGUserFile_ImportedResource importedResources[]
GGUserFile_SavedVariable savedVariables[]

-GGUserFile : The contents of a .gguser file

+GGUserFileV2Snapshot : The snapshot of a GGUserFileV2

- - - + + - + + + + + + - - +
GGUserFile
std::string version"1.0"The version of the .gguser file
GGUserFile_SystemVars systemVars{}
GGUserFileV2Snapshot
std::string name""The snapshot name
int resourceViewType0The type of resource being viewed
int resourceViewNodeIndex-1The index of the node bieng viewed
int resourceViewResourceIndex-1The index of that resource within that node being used
int syncIntervaltrueIDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.
bool loadVarstrueWhether variables will be loaded from this snapshot
bool loadCameratrueWhether the camera will be loaded from this snapshot
bool loadResourcestrueWhether imported resources will be loaded from this snapshot
bool loadViewtrueWhether the resource viewed will be loaded from this snapshot
float cameraPos[3]{ 0.0f , 0.0f , - 10.0f }Used by snapshots to capture the camera position
float cameraAltitudeAzimuth[2]{ 0.0f , 0.0f }Used by snapshots to capture the camera orientation
GGUserFile_ImportedResource importedResources[]
GGUserFile_SavedVariable savedVariables[]
GGUserFile_Bookmark bookmarks[]
GGUserFile_ImportedResourcePreset importedResourcePresets[]
+
+ +GGUserFileV2 : The contents of a .gguser file

+ + + + + + + +
GGUserFileV2
std::string version"2.0"The version of the .gguser file
int syncInterval1IDXGISwapChain::Present() parameter: Synchronize presentation after the nth vertical blank.
GGUserFile_SystemVars systemVars{}
GGUserFileV2Snapshot snapshot{}
GGUserFileV2Snapshot snapshots[]
+
+ +GGUserFileVersionOnly : Only the version of the .gguser file

+ + +
GGUserFileVersionOnly
std::string version"1.0"The version of the .gguser file

@@ -1542,6 +1584,8 @@

Structs

std::string versionUpgradedMessage""Text to show about the version upgrade BackendTemplateConfig templateConfig{}Code generation template config bool generateGraphVizFlagfalseSet to true if the generating GraphViz. Should be set to true from a command line parameter +std::vector assertsFormatStrings{}The unique formatting strings of the asserts messages +std::unordered_set firedAssertsIdentifiers{}The identifiers of the fired asserts to ignore them later on
diff --git a/gigischema.json b/gigischema.json index dcecedb1..d7752686 100644 --- a/gigischema.json +++ b/gigischema.json @@ -43,7 +43,7 @@ "type": "boolean" }, "dflt": { - "description": "The default value of the variable", + "description": "The default value of the variable. The default memory is zero initialized before this is parsed, so if you don't give it enough initializers, it will use zero for the unlisted fields.", "type": "string" }, "visibility": { @@ -100,6 +100,10 @@ } } }, + "UIGroup": { + "description": "Used to organize variables into folders in the viewer. separate folders with dots. For instance: settings.controls", + "type": "string" + }, "UIHint": { "description": "Any hints for UI", "type": "string", @@ -2138,6 +2142,10 @@ "description": "If set, the subgraph variable will be deleted and all references will use this parent graph variable instead.", "type": "string" }, + "replaceWithValue": { + "description": "Replace the variable with a literal value. At gigi compile time it makes an internal private variable of the correct type with this string as the default value.", + "type": "string" + }, "isLoopIndex": { "description": "If true, this variable will recieve the loop index.", "type": "boolean" @@ -2158,6 +2166,16 @@ "loopCount": { "description": "Number of times to execute the technique.", "type": "integer" + }, + "loopCountVariable": { + "description": "The variable to use for the loopCount. Only const variables supported currently.", + "type": "object", + "properties": { + "name": { + "description": "The name of the variable.", + "type": "string" + } + } } } }, @@ -2369,7 +2387,7 @@ "op": { "description": "", "type": "string", - "enum": ["Add", "Subtract", "Multiply", "Divide", "Modulo", "PowerOf2GE", "BitwiseOr", "BitwiseAnd", "BitwiseXor", "BitwiseNot", "Noop"] + "enum": ["Add", "Subtract", "Multiply", "Divide", "Modulo", "PowerOf2GE", "Minimum", "Maximum", "BitwiseOr", "BitwiseAnd", "BitwiseXor", "BitwiseNot", "Noop"] }, "BVar": { "description": "The variable on the right side of the operator",