From 7685d29e3a86ae9c43cfe70254af58d487ff85ed Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 22 May 2026 10:43:38 +0700 Subject: [PATCH 01/26] updated dxc --- 3rdparty/dxc/dxc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/dxc/dxc b/3rdparty/dxc/dxc index c765af7b86..a532a63697 160000 --- a/3rdparty/dxc/dxc +++ b/3rdparty/dxc/dxc @@ -1 +1 @@ -Subproject commit c765af7b863c5af1e0e4d2d61dd7ae0f1f37f546 +Subproject commit a532a63697946c09871f4932e4e0ce6e89a843de From 5c248b4b9b664ba592713d16d66e7049b5ea5f4d Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 22 May 2026 11:27:23 +0700 Subject: [PATCH 02/26] reference backend basic structure + some impl for albedo, generate --- .../CReferenceUnidirectionalPathTracing.h | 89 ++++++ .../nbl/asset/material_compiler3/IBackend.h | 25 ++ src/nbl/CMakeLists.txt | 1 + .../CReferenceUnidirectionalPathTracing.cpp | 280 ++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h create mode 100644 include/nbl/asset/material_compiler3/IBackend.h create mode 100644 src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h new file mode 100644 index 0000000000..3d91ea99d3 --- /dev/null +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -0,0 +1,89 @@ +// Copyright (C) 2018-2026 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_ASSET_MATERIAL_COMPILER_V3_C_REFERENCE_UNIDIRECTIONAL_PATH_TRACING_H_INCLUDED_ +#define _NBL_ASSET_MATERIAL_COMPILER_V3_C_REFERENCE_UNIDIRECTIONAL_PATH_TRACING_H_INCLUDED_ + +#include "nbl/asset/material_compiler3/IBackend.h" + +namespace nbl::asset::material_compiler3 +{ + +//template +struct OrientedMaterial +{ + uint32_t emitter_id; + uint32_t prefetch_offset; + uint32_t prefetch_count; + uint32_t instr_offset; + uint32_t rem_pdf_count; + uint32_t nprecomp_count; + uint32_t genchoice_count; + + core::blake3_hash_t hash; + + struct stream_t + { + uint32_t first; + uint32_t count; + }; + stream_t get_rem_and_pdf() const { return { instr_offset, rem_pdf_count }; } + stream_t get_gen_choice() const { return { instr_offset + rem_pdf_count, genchoice_count }; } + stream_t get_norm_precomp() const { return { instr_offset + rem_pdf_count + genchoice_count, nprecomp_count }; } + stream_t get_tex_prefetch() const { return { prefetch_offset, prefetch_count }; } +}; + +class CReferenceUnidirectionalPathTracing : public IBackend +{ +public: + struct CResult : public IBackend::IResult + { + // TODO need all this? + //instr_stream::traversal_t instructions; + //instr_stream::tex_prefetch::prefetch_stream_t prefetch_stream; + //core::vector bsdfData; + //core::vector emitterData; + + //bool noPrefetchStream; + //bool noNormPrecompStream; + //bool allIsotropic; + //bool noBSDF; + //uint32_t usedRegisterCount; + //uint32_t globalPrefetchRegCountFlags; + //uint32_t paramTexPresence[instr_stream::SBSDFUnion::MAX_TEXTURES][2]; + //// always same value and the value + //std::pair paramConstants[instr_stream::SBSDFUnion::MAX_TEXTURES]; + + //core::unordered_set opcodes; + //core::unordered_set NDFs; + + //one element for each input IR root node + core::vector materials; + + //has to go after #version and before required user-provided descriptors and functions + std::string fragmentShaderSource_declarations; + //has to go after required user-provided descriptors and functions and before the rest of shader (especially entry point function) + std::string fragmentShaderSource; + }; + + CResult compile(const CTrueIR* ir, const std::span materials); + +private: + std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; + + void getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); +}; + +} + +#endif diff --git a/include/nbl/asset/material_compiler3/IBackend.h b/include/nbl/asset/material_compiler3/IBackend.h new file mode 100644 index 0000000000..9f68a7c607 --- /dev/null +++ b/include/nbl/asset/material_compiler3/IBackend.h @@ -0,0 +1,25 @@ +// Copyright (C) 2018-2026 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_ASSET_MATERIAL_COMPILER_V3_I_BACKEND_H_INCLUDED_ +#define _NBL_ASSET_MATERIAL_COMPILER_V3_I_BACKEND_H_INCLUDED_ + +#include "nbl/asset/material_compiler3/CTrueIR.h" + +namespace nbl::asset::material_compiler3 +{ + +class IBackend +{ +public: + struct IResult// : public core::IReferenceCounted + { + + }; + + IResult compile(const CTrueIR*, const std::span); +}; + +} + +#endif diff --git a/src/nbl/CMakeLists.txt b/src/nbl/CMakeLists.txt index 502d0c70c8..feb1e664fb 100644 --- a/src/nbl/CMakeLists.txt +++ b/src/nbl/CMakeLists.txt @@ -170,6 +170,7 @@ set(NBL_ASSET_SOURCES # Materials asset/material_compiler3/CFrontendIR.cpp asset/material_compiler3/CTrueIR.cpp + asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp # Shaders asset/utils/ISPIRVOptimizer.cpp diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp new file mode 100644 index 0000000000..950b178fff --- /dev/null +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -0,0 +1,280 @@ +// Copyright (C) 2022-2026 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#define _NBL_ASSET_MATERIAL_COMPILER3_C_REFERENCE_UNIDIRECTIONAL_PATH_TRACING_CPP_ +#include "nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h" + +namespace nbl::asset::material_compiler3 +{ + +CReferenceUnidirectionalPathTracing::CResult CReferenceUnidirectionalPathTracing::compile(const CTrueIR* ir, const std::span materialHandles) +{ + CResult res; + + // TODO: handle textures somehow + // TODO: templated structs for types in certain functions, e.g. cache (generate + quotient) + std::ostringstream code; + + // loop through layers in IR and construct materials map? maybe just node map is fine + core::vector compiledBSDFRootNodes; + auto compileBSDFRootNode = [&](const CTrueIR::INode* root) -> void { + getAlbedoHLSLCode(code, root, ir); + // TODO: the other functions + // TODO: loop through the children, also might need to do reverse order or forward declare function signatures + }; + + const auto& materials = ir->getMaterials(); + for (uint32_t i = 0; i < materialHandles.size(); i++) + { + if (materialHandles[i].value == CTrueIR::SMaterialHandle::Invalid) + continue; + + const auto& mat = materials[materialHandles[i].value]; + if (auto node = ir->getObjectPool().deref(mat.front.root); node) + compileBSDFRootNode(node); + if (auto node = ir->getObjectPool().deref(mat.back.root); node) + compileBSDFRootNode(node); + } + + // each layer/node writes as string its own code? or just hash + // 8 functions each node: albedo, normal, aov_throughput, transparency, generate, quotientAndWeight, evalAndWeight, emission + + res.fragmentShaderSource = code.str(); + + return res; +} + +std::string CReferenceUnidirectionalPathTracing::getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator) const +{ + // break up hash into 8 pieces of uint32_t + const auto hash = node->computeHash(ir->getObjectPool()); + uint32_t hashPieces[8]; + for (uint8_t i = 0; i < 8; i++) + for (uint8_t j = 0; j < 4; j++) + hlsl::glsl::bitfieldInsert(hashPieces[i], static_cast(hash.data[4 * i + 0]), j * 8, 8); + std::stringstream hashString; + for (uint8_t i = 0; i < 8; i++) + { + hashString << hashPieces[i]; + if (i < 7) + hashString << separator; + } + return hashString.str(); +} + +void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "spectral_t brdf = albedo<" << childBrdfHash << ">();\n"; + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "spectral_t btdf = albedo<" << childBtdfHash << ">();\n"; + } + + // TODO: mix result + sstr << "spectral_t retval = (brdf + btdf) * 0.5;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "spectral_t product = albedo<" << childProductHash << ">();\n"; + // TODO: what to do with child caches? + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "spectral_t rest = albedo<" << childRestHash << ">();\n"; + // TODO: what to do with child caches? + } + + // TODO: weight sample + sstr << "spectral_t retval = (product + rest) * 0.5;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + // TODO + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + // TODO + break; + } + case CTrueIR::INode::EFinalType::COrenNayar: + { + const auto* oren_nayar = dynamic_cast(node); + if (!oren_nayar) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + auto roughness = oren_nayar->ndfParams.getRougness(); + sstr << "using oren_nayar_t = bxdf::reflection::SOrenNayar;\n"; + sstr << "using creation_t = typename oren_nayar_t::creation_type;\n"; + sstr << "creation_t params;\nparams.A = " << roughness.data()[0].scale << ";\n"; + sstr << "oren_nayar_t bxdf = diffuse_op_type::create(params);\n"; + + sstr << "typename oren_nayar_t::anisocache_type bxdf_cache;\n"; + sstr << "sample_t _sample = bxdf.generate(inter, xi, bxdf_cache);\n"; + // TODO: what to do with child caches? + + sstr << "return hlsl::promote();\n}\n"; + break; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + { + // TODO + break; + } + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\nreturn hlsl::promote(0);\n}\n"; // TODO: what args needed? uv? + } + } +} + +void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nsample_t generate<" << hashString; + sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<" // TODO: class type specific cache + << hashString << ">) cache)\n{\n"; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "gen_cache<" << childBrdfHash << "> brdf_cache;\n"; + sstr << "sample_t brdf = generate<" << childBrdfHash << ">(inter, xi, brdf_cache);\n"; + // TODO: what to do with child caches? + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "gen_cache<" << childBtdfHash << "> btdf_cache;\n"; + sstr << "sample_t btdf = generate<" << childBtdfHash << ">(inter, xi_extra, btdf_cache);\n"; + // TODO: what to do with child caches? + } + + // TODO: do resampled importance sampling HLSL code + + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nsample_t generate<" << hashString; + sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(gen_cache<" + << hashString << ">) cache)\n{\n"; + + sstr << "uint16_t chosenLobe = 0;\npdf_t choiceRcpPdf = 1.f;\n"; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "gen_cache<" << childProductHash << "> product_cache;\n"; + sstr << "sample_t product = generate<" << childProductHash << ">(inter, xi, product_cache);\n"; + // TODO: what to do with child caches? + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "gen_cache<" << childRestHash << "> rest_cache;\n"; + sstr << "sample_t rest = generate<" << childRestHash << ">(inter, xi, rest_cache);\n"; + // TODO: what to do with child caches? + } + + // TODO: weight sample + + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + // TODO + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + // TODO + break; + } + case CTrueIR::INode::EFinalType::COrenNayar: + { + const auto* oren_nayar = dynamic_cast(node); + if (!oren_nayar) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nsample_t generate<" << hashString; + sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(gen_cache<" + << hashString << ">) cache)\n{\n"; + + auto roughness = oren_nayar->ndfParams.getRougness(); + sstr << "using oren_nayar_t = bxdf::reflection::SOrenNayar;\n"; + sstr << "using creation_t = typename oren_nayar_t::creation_type;\n"; + sstr << "creation_t params;\nparams.A = " << roughness.data()[0].scale << ";\n"; + sstr << "oren_nayar_t bxdf = diffuse_op_type::create(params);\n"; + + sstr << "typename oren_nayar_t::anisocache_type bxdf_cache;\n"; + sstr << "sample_t _sample = bxdf.generate(inter, xi, bxdf_cache);\n"; + // TODO: what to do with child caches? + + sstr << "return _sample;\n}\n"; + break; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + { + // TODO + break; + } + default: + break; + } +} + +} From 5fd455791309bf4392504b4fb38b63814e68dc7a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 22 May 2026 16:28:39 +0700 Subject: [PATCH 03/26] main compile function of backend does templated function declarations, and loops through node and children --- .../CReferenceUnidirectionalPathTracing.h | 26 +------ .../CReferenceUnidirectionalPathTracing.cpp | 75 +++++++++++++++++-- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index 3d91ea99d3..755ac7eb1d 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -38,28 +38,6 @@ class CReferenceUnidirectionalPathTracing : public IBackend public: struct CResult : public IBackend::IResult { - // TODO need all this? - //instr_stream::traversal_t instructions; - //instr_stream::tex_prefetch::prefetch_stream_t prefetch_stream; - //core::vector bsdfData; - //core::vector emitterData; - - //bool noPrefetchStream; - //bool noNormPrecompStream; - //bool allIsotropic; - //bool noBSDF; - //uint32_t usedRegisterCount; - //uint32_t globalPrefetchRegCountFlags; - //uint32_t paramTexPresence[instr_stream::SBSDFUnion::MAX_TEXTURES][2]; - //// always same value and the value - //std::pair paramConstants[instr_stream::SBSDFUnion::MAX_TEXTURES]; - - //core::unordered_set opcodes; - //core::unordered_set NDFs; - - //one element for each input IR root node - core::vector materials; - //has to go after #version and before required user-provided descriptors and functions std::string fragmentShaderSource_declarations; //has to go after required user-provided descriptors and functions and before the rest of shader (especially entry point function) @@ -75,6 +53,8 @@ class CReferenceUnidirectionalPathTracing : public IBackend void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getAOVThroughputHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); @@ -82,6 +62,8 @@ class CReferenceUnidirectionalPathTracing : public IBackend void getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 950b178fff..6ce11d8a7b 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -13,14 +13,75 @@ CReferenceUnidirectionalPathTracing::CResult CReferenceUnidirectionalPathTracing // TODO: handle textures somehow // TODO: templated structs for types in certain functions, e.g. cache (generate + quotient) + // TODO: where do all the type aliases come from? e.g. sample_t, vector3_t, etc. std::ostringstream code; + // define templates of node functions + util structs + code << "template\nstruct gen_cache;\n"; // cache struct + + code << "template\nspectral_t albedo();\n"; // TODO: what args needed? uv? + code << "template\nvector3_t normal();\n"; // TODO: what args needed? uv? + code << "template\nvector3_t aov_throughput();\n"; // TODO: confirm return value is vec3, what args needed? uv? + code << "template\nvector3_t transparency();\n"; // TODO: return value is vec3? what args needed? + + // TODO: check how many rand numbers, might need to declare template functions by node type as well (because rand numbers vary by generate, etc.) + // if the above is the case, will have to check whether the node-specific template function declaration is included yet, then add before function definition + code << "template\n" + << "sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, " + << "NBL_REF_ARG(gen_cache) cache);\n"; + + code << "template\n" + << "quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, " + << "NBL_REF_ARG(gen_cache) cache);\n"; + + code << "template\n" + << "eval_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter);\n"; + + code << "template\nspectral_t emission();\n"; // TODO: what args needed? + // loop through layers in IR and construct materials map? maybe just node map is fine - core::vector compiledBSDFRootNodes; - auto compileBSDFRootNode = [&](const CTrueIR::INode* root) -> void { - getAlbedoHLSLCode(code, root, ir); - // TODO: the other functions - // TODO: loop through the children, also might need to do reverse order or forward declare function signatures + core::vector> nodeStack; + core::unordered_set> visitedNodes; + auto compileBSDFRootNode = [&](CTrueIR::typed_pointer_type rootHandle) -> void { + nodeStack.clear(); + visitedNodes.clear(); + + nodeStack.push_back(rootHandle); + const auto& pool = ir->getObjectPool(); + + while (!nodeStack.empty()) + { + const auto handle = nodeStack.back(); + nodeStack.pop_back(); + const auto* node = pool.deref(handle); + if (!node) + continue; + + getAlbedoHLSLCode(code, node, ir); + getNormalHLSLCode(code, node, ir); + getAOVThroughputHLSLCode(code, node, ir); + getTransparencyHLSLCode(code, node, ir); + getGenerateHLSLCode(code, node, ir); + getEvalWeightHLSLCode(code, node, ir); + getQuotientWeightHLSLCode(code, node, ir); + getEmissionHLSLCode(code, node, ir); + + // TODO: might need to do children first or forward declare function signatures + const auto childCount = node->getChildCount(); + if (childCount) + { + for (auto childIx = 0; childIx < childCount; childIx++) + { + const auto childHandle = node->getChildHandle(childIx); + if (const auto child = pool.deref(childHandle); child) + { + const auto [unused, inserted] = visitedNodes.insert(childHandle); + if (inserted) + nodeStack.push_back(childHandle); + } + } + } + } }; const auto& materials = ir->getMaterials(); @@ -31,9 +92,9 @@ CReferenceUnidirectionalPathTracing::CResult CReferenceUnidirectionalPathTracing const auto& mat = materials[materialHandles[i].value]; if (auto node = ir->getObjectPool().deref(mat.front.root); node) - compileBSDFRootNode(node); + compileBSDFRootNode(mat.front.root); if (auto node = ir->getObjectPool().deref(mat.back.root); node) - compileBSDFRootNode(node); + compileBSDFRootNode(mat.back.root); } // each layer/node writes as string its own code? or just hash From 2aab0eb69caa57bbb0a3908f858cd13fcd2e85f0 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 25 May 2026 11:34:40 +0700 Subject: [PATCH 04/26] change compile to return ptr, minor fixes in combining node child results in albedo --- .../CReferenceUnidirectionalPathTracing.h | 33 +++--------------- .../nbl/asset/material_compiler3/IBackend.h | 6 ++-- .../CReferenceUnidirectionalPathTracing.cpp | 34 +++++++------------ 3 files changed, 20 insertions(+), 53 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index 755ac7eb1d..fda4436916 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -8,43 +8,18 @@ namespace nbl::asset::material_compiler3 { - -//template -struct OrientedMaterial -{ - uint32_t emitter_id; - uint32_t prefetch_offset; - uint32_t prefetch_count; - uint32_t instr_offset; - uint32_t rem_pdf_count; - uint32_t nprecomp_count; - uint32_t genchoice_count; - - core::blake3_hash_t hash; - - struct stream_t - { - uint32_t first; - uint32_t count; - }; - stream_t get_rem_and_pdf() const { return { instr_offset, rem_pdf_count }; } - stream_t get_gen_choice() const { return { instr_offset + rem_pdf_count, genchoice_count }; } - stream_t get_norm_precomp() const { return { instr_offset + rem_pdf_count + genchoice_count, nprecomp_count }; } - stream_t get_tex_prefetch() const { return { prefetch_offset, prefetch_count }; } -}; -class CReferenceUnidirectionalPathTracing : public IBackend +class CReferenceUnidirectionalPathTracing final : public IBackend { public: - struct CResult : public IBackend::IResult + class CResult final : public IBackend::IResult { - //has to go after #version and before required user-provided descriptors and functions + public: std::string fragmentShaderSource_declarations; - //has to go after required user-provided descriptors and functions and before the rest of shader (especially entry point function) std::string fragmentShaderSource; }; - CResult compile(const CTrueIR* ir, const std::span materials); + core::smart_refctd_ptr compile(const CTrueIR* ir, const std::span materials); private: std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; diff --git a/include/nbl/asset/material_compiler3/IBackend.h b/include/nbl/asset/material_compiler3/IBackend.h index 9f68a7c607..c0ce755354 100644 --- a/include/nbl/asset/material_compiler3/IBackend.h +++ b/include/nbl/asset/material_compiler3/IBackend.h @@ -9,15 +9,15 @@ namespace nbl::asset::material_compiler3 { -class IBackend +class IBackend : public core::IReferenceCounted { public: - struct IResult// : public core::IReferenceCounted + class IResult : public core::IReferenceCounted { }; - IResult compile(const CTrueIR*, const std::span); + core::smart_refctd_ptr compile(const CTrueIR*, const std::span); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 6ce11d8a7b..a7345bfcf2 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -7,9 +7,9 @@ namespace nbl::asset::material_compiler3 { -CReferenceUnidirectionalPathTracing::CResult CReferenceUnidirectionalPathTracing::compile(const CTrueIR* ir, const std::span materialHandles) + core::smart_refctd_ptr CReferenceUnidirectionalPathTracing::compile(const CTrueIR* ir, const std::span materialHandles) { - CResult res; + auto res = core::make_smart_refctd_ptr(); // TODO: handle textures somehow // TODO: templated structs for types in certain functions, e.g. cache (generate + quotient) @@ -100,7 +100,7 @@ CReferenceUnidirectionalPathTracing::CResult CReferenceUnidirectionalPathTracing // each layer/node writes as string its own code? or just hash // 8 functions each node: albedo, normal, aov_throughput, transparency, generate, quotientAndWeight, evalAndWeight, emission - res.fragmentShaderSource = code.str(); + res->fragmentShaderSource = code.str(); return res; } @@ -147,8 +147,7 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr << "spectral_t btdf = albedo<" << childBtdfHash << ">();\n"; } - // TODO: mix result - sstr << "spectral_t retval = (brdf + btdf) * 0.5;\n"; + sstr << "spectral_t retval = brdf + btdf;\n"; sstr << "return retval;\n}\n"; break; } @@ -174,8 +173,7 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& // TODO: what to do with child caches? } - // TODO: weight sample - sstr << "spectral_t retval = (product + rest) * 0.5;\n"; + sstr << "spectral_t retval = product + rest;\n"; sstr << "return retval;\n}\n"; break; } @@ -197,24 +195,18 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& const auto hashString = getHashAs4UintsString(node, ir); sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? - - auto roughness = oren_nayar->ndfParams.getRougness(); - sstr << "using oren_nayar_t = bxdf::reflection::SOrenNayar;\n"; - sstr << "using creation_t = typename oren_nayar_t::creation_type;\n"; - sstr << "creation_t params;\nparams.A = " << roughness.data()[0].scale << ";\n"; - sstr << "oren_nayar_t bxdf = diffuse_op_type::create(params);\n"; - - sstr << "typename oren_nayar_t::anisocache_type bxdf_cache;\n"; - sstr << "sample_t _sample = bxdf.generate(inter, xi, bxdf_cache);\n"; - // TODO: what to do with child caches? - - sstr << "return hlsl::promote();\n}\n"; - break; + sstr << "return hlsl::promote(0.0);\n}\n"; break; } case CTrueIR::INode::EFinalType::CCookTorrance: { - // TODO + const auto* cook_torrance = dynamic_cast(node); + if (!cook_torrance) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << "return hlsl::promote(0.0);\n}\n"; break; } default: From 28d970774dda0abb56d2e456dc9c3973297c982a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 25 May 2026 15:47:59 +0700 Subject: [PATCH 05/26] complete albedo hlsl impl --- .../CReferenceUnidirectionalPathTracing.cpp | 112 ++++++++++++++++-- 1 file changed, 100 insertions(+), 12 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index a7345bfcf2..5c95035650 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -164,46 +164,134 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& { const auto childProductHash = getHashAs4UintsString(childProduct, ir); sstr << "spectral_t product = albedo<" << childProductHash << ">();\n"; - // TODO: what to do with child caches? } if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) { const auto childRestHash = getHashAs4UintsString(childRest, ir); sstr << "spectral_t rest = albedo<" << childRestHash << ">();\n"; - // TODO: what to do with child caches? } sstr << "spectral_t retval = product + rest;\n"; sstr << "return retval;\n}\n"; break; } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t child" << static_cast(i) << " = albedo<" << childHash << ">();\n"; + } + } + + sstr << "spectral_t retval = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << ";\n"; + sstr << "return retval;\n}\n"; + break; + } case CTrueIR::INode::EFinalType::CWeightedContributor: { - // TODO + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + const auto childContribHash = getHashAs4UintsString(childContrib, ir); + sstr << "spectral_t contributor = albedo<" << childContribHash << ">();\n"; + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + const auto childFactorHash = getHashAs4UintsString(childFactor, ir); + sstr << "spectral_t factor = albedo<" << childFactorHash << ">();\n"; + } + + sstr << "spectral_t retval = contributor + factor;\n"; + sstr << "return retval;\n}\n"; break; } case CTrueIR::INode::EFinalType::CCorellatedTransmission: { - // TODO + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t btdf = albedo<" << childHash << ">();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t brdf = albedo<" << childHash << ">();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t coated = albedo<" << childHash << ">();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t next = albedo<" << childHash << ">();\n"; + } + + sstr << "spectral_t retval = btdf + brdf + coated + next;\n"; + sstr << "return retval;\n}\n"; break; } - case CTrueIR::INode::EFinalType::COrenNayar: + case CTrueIR::INode::EFinalType::CSpectralVariable: { - const auto* oren_nayar = dynamic_cast(node); - if (!oren_nayar) + const auto* spectral = dynamic_cast(node); + if (!spectral) break; + auto bins = spectral->getSpectralBins(); const auto hashString = getHashAs4UintsString(node, ir); sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? - sstr << "return hlsl::promote(0.0);\n}\n"; + if (bins > 1) + { + sstr << "return spectral_t("; + for (uint8_t i = 0; i < bins; i++) + sstr << spectral->getParameter(i).scale << (i < bins - 1 ? "," : ""); + sstr << ");\n}\n"; + } + else + sstr << "return hlsl::promote(" << spectral->getParameter(0).scale << ");\n}\n"; break; } + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: { - const auto* cook_torrance = dynamic_cast(node); - if (!cook_torrance) - break; - const auto hashString = getHashAs4UintsString(node, ir); sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? sstr << "return hlsl::promote(0.0);\n}\n"; From efec002942fbfcb3ff0db1e9887f305bce54900c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 25 May 2026 16:16:50 +0700 Subject: [PATCH 06/26] backend normal hlsl impl --- .../CReferenceUnidirectionalPathTracing.cpp | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 5c95035650..487abfcacf 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -19,8 +19,8 @@ namespace nbl::asset::material_compiler3 // define templates of node functions + util structs code << "template\nstruct gen_cache;\n"; // cache struct - code << "template\nspectral_t albedo();\n"; // TODO: what args needed? uv? - code << "template\nvector3_t normal();\n"; // TODO: what args needed? uv? + code << "template\nspectral_t albedo();\n"; // TODO: might add interaction arg + code << "template\nvector3_t normal(NBL_CONST_REF_ARG(aniso_interaction_t) inter);\n"; code << "template\nvector3_t aov_throughput();\n"; // TODO: confirm return value is vec3, what args needed? uv? code << "template\nvector3_t transparency();\n"; // TODO: return value is vec3? what args needed? @@ -305,6 +305,48 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& } } +void CReferenceUnidirectionalPathTracing::getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CContributorSum: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFactorCombiner: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CWeightedContributor: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +template<> +vector3_t normal<)===" << hashString << R"===(>(NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ + return inter.getN(); +} +)==="; // return shading normal by default + } + } +} + void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) From a22700fea25e2b5dc18937c5b0db6fb5642b1461 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 26 May 2026 13:52:08 +0700 Subject: [PATCH 07/26] combine material functions into a struct to avoid repeating hash templates, changed albedo + normal funcs --- .../CReferenceUnidirectionalPathTracing.h | 6 +- .../CReferenceUnidirectionalPathTracing.cpp | 123 +++++++++++------- 2 files changed, 82 insertions(+), 47 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index fda4436916..c0d24fac48 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -15,8 +15,8 @@ class CReferenceUnidirectionalPathTracing final : public IBackend class CResult final : public IBackend::IResult { public: - std::string fragmentShaderSource_declarations; - std::string fragmentShaderSource; + std::string fragmentShaderSource_common; + std::string fragmentShaderSource_raytracingPipeline; // only maps entry point to templated funcs }; core::smart_refctd_ptr compile(const CTrueIR* ir, const std::span materials); @@ -24,6 +24,8 @@ class CReferenceUnidirectionalPathTracing final : public IBackend private: std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; + void getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 487abfcacf..ab844d59a8 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -16,28 +16,13 @@ namespace nbl::asset::material_compiler3 // TODO: where do all the type aliases come from? e.g. sample_t, vector3_t, etc. std::ostringstream code; - // define templates of node functions + util structs - code << "template\nstruct gen_cache;\n"; // cache struct + code << R"===( +template +struct gen_cache; - code << "template\nspectral_t albedo();\n"; // TODO: might add interaction arg - code << "template\nvector3_t normal(NBL_CONST_REF_ARG(aniso_interaction_t) inter);\n"; - code << "template\nvector3_t aov_throughput();\n"; // TODO: confirm return value is vec3, what args needed? uv? - code << "template\nvector3_t transparency();\n"; // TODO: return value is vec3? what args needed? - - // TODO: check how many rand numbers, might need to declare template functions by node type as well (because rand numbers vary by generate, etc.) - // if the above is the case, will have to check whether the node-specific template function declaration is included yet, then add before function definition - code << "template\n" - << "sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, " - << "NBL_REF_ARG(gen_cache) cache);\n"; - - code << "template\n" - << "quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, " - << "NBL_REF_ARG(gen_cache) cache);\n"; - - code << "template\n" - << "eval_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter);\n"; - - code << "template\nspectral_t emission();\n"; // TODO: what args needed? +template +struct OrientedMaterial; +)==="; // loop through layers in IR and construct materials map? maybe just node map is fine core::vector> nodeStack; @@ -57,14 +42,7 @@ namespace nbl::asset::material_compiler3 if (!node) continue; - getAlbedoHLSLCode(code, node, ir); - getNormalHLSLCode(code, node, ir); - getAOVThroughputHLSLCode(code, node, ir); - getTransparencyHLSLCode(code, node, ir); - getGenerateHLSLCode(code, node, ir); - getEvalWeightHLSLCode(code, node, ir); - getQuotientWeightHLSLCode(code, node, ir); - getEmissionHLSLCode(code, node, ir); + getMaterialDeclarationCode(code, node, ir); // TODO: might need to do children first or forward declare function signatures const auto childCount = node->getChildCount(); @@ -82,6 +60,19 @@ namespace nbl::asset::material_compiler3 } } } + + for (const auto& nodeHandle : visitedNodes) + { + const auto* node = pool.deref(nodeHandle); + getAlbedoHLSLCode(code, node, ir); + getNormalHLSLCode(code, node, ir); + getAOVThroughputHLSLCode(code, node, ir); + getTransparencyHLSLCode(code, node, ir); + getGenerateHLSLCode(code, node, ir); + getEvalWeightHLSLCode(code, node, ir); + getQuotientWeightHLSLCode(code, node, ir); + getEmissionHLSLCode(code, node, ir); + } }; const auto& materials = ir->getMaterials(); @@ -100,7 +91,8 @@ namespace nbl::asset::material_compiler3 // each layer/node writes as string its own code? or just hash // 8 functions each node: albedo, normal, aov_throughput, transparency, generate, quotientAndWeight, evalAndWeight, emission - res->fragmentShaderSource = code.str(); + res->fragmentShaderSource_common = code.str(); + // TODO: set entry points in raytracingPipeline return res; } @@ -123,6 +115,30 @@ std::string CReferenceUnidirectionalPathTracing::getHashAs4UintsString(const CTr return hashString.str(); } +void CReferenceUnidirectionalPathTracing::getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + // define templates of node material structs + const auto hashString = getHashAs4UintsString(node, ir); + + // TODO: specialize gen_cache struct + + sstr << R"===( +template<> +struct OrientedMaterial<)===" << hashString << R"===(> +{ + static spectral_t albedo(); + static vector3_t normal(NBL_CONST_REF_ARG(aniso_interaction_t) inter); + static spectral_t aov_throughput(); + static scalar_t transparency(); + static sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); + static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); + static eval_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); + static spectral_t emission(); +} +)==="; + +} + void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) @@ -134,7 +150,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) { @@ -158,7 +177,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) { @@ -182,7 +204,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; const auto childCount = combiner->getChildCount(); @@ -209,7 +234,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) { @@ -233,7 +261,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; if (auto child = ir->getObjectPool().deref(transmission->btdf); child) { @@ -268,7 +299,10 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& auto bins = spectral->getSpectralBins(); const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ +)==="; if (bins > 1) { sstr << "return spectral_t("; @@ -291,16 +325,16 @@ void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& case CTrueIR::INode::EFinalType::CFresnel: [[fallthrough]] case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: - { - const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\n"; // TODO: what args needed? uv? - sstr << "return hlsl::promote(0.0);\n}\n"; - break; - } + [[fallthrough]] default: { const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nspectral_t albedo<" << hashString << ">()\n{\nreturn hlsl::promote(0);\n}\n"; // TODO: what args needed? uv? + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() +{ + return hlsl::promote(0.0); +} +)==="; } } } @@ -337,8 +371,7 @@ void CReferenceUnidirectionalPathTracing::getNormalHLSLCode(std::ostringstream& { const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -template<> -vector3_t normal<)===" << hashString << R"===(>(NBL_CONST_REF_ARG(aniso_interaction_t) inter) +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::normal(NBL_CONST_REF_ARG(aniso_interaction_t) inter) { return inter.getN(); } From abcb09242e8b954649b827a7acb5dbf6cef9430f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 26 May 2026 14:56:59 +0700 Subject: [PATCH 08/26] fixes to albedo and generate for new material struct --- .../CReferenceUnidirectionalPathTracing.cpp | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index ab844d59a8..598d87917f 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -44,7 +44,6 @@ struct OrientedMaterial; getMaterialDeclarationCode(code, node, ir); - // TODO: might need to do children first or forward declare function signatures const auto childCount = node->getChildCount(); if (childCount) { @@ -158,12 +157,12 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) { const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); - sstr << "spectral_t brdf = albedo<" << childBrdfHash << ">();\n"; + sstr << "spectral_t brdf = OrientedMaterial<" << childBrdfHash << ">::albedo();\n"; } if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) { const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); - sstr << "spectral_t btdf = albedo<" << childBtdfHash << ">();\n"; + sstr << "spectral_t btdf = OrientedMaterial<" << childBtdfHash << ">::albedo();\n"; } sstr << "spectral_t retval = brdf + btdf;\n"; @@ -185,12 +184,12 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) { const auto childProductHash = getHashAs4UintsString(childProduct, ir); - sstr << "spectral_t product = albedo<" << childProductHash << ">();\n"; + sstr << "spectral_t product = OrientedMaterial<" << childProductHash << ">::albedo();\n"; } if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) { const auto childRestHash = getHashAs4UintsString(childRest, ir); - sstr << "spectral_t rest = albedo<" << childRestHash << ">();\n"; + sstr << "spectral_t rest = OrientedMaterial<" << childRestHash << ">::albedo();\n"; } sstr << "spectral_t retval = product + rest;\n"; @@ -216,7 +215,7 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "spectral_t child" << static_cast(i) << " = albedo<" << childHash << ">();\n"; + sstr << "spectral_t child" << static_cast(i) << " = OrientedMaterial<" << childHash << ">::albedo();\n"; } } @@ -242,12 +241,12 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) { const auto childContribHash = getHashAs4UintsString(childContrib, ir); - sstr << "spectral_t contributor = albedo<" << childContribHash << ">();\n"; + sstr << "spectral_t contributor = OrientedMaterial<" << childContribHash << ">::albedo();\n"; } if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) { const auto childFactorHash = getHashAs4UintsString(childFactor, ir); - sstr << "spectral_t factor = albedo<" << childFactorHash << ">();\n"; + sstr << "spectral_t factor = OrientedMaterial<" << childFactorHash << ">::albedo();\n"; } sstr << "spectral_t retval = contributor + factor;\n"; @@ -269,22 +268,22 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() if (auto child = ir->getObjectPool().deref(transmission->btdf); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "spectral_t btdf = albedo<" << childHash << ">();\n"; + sstr << "spectral_t btdf = OrientedMaterial<" << childHash << ">::albedo();\n"; } if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "spectral_t brdf = albedo<" << childHash << ">();\n"; + sstr << "spectral_t brdf = OrientedMaterial<" << childHash << ">::albedo();\n"; } if (auto child = ir->getObjectPool().deref(transmission->coated); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "spectral_t coated = albedo<" << childHash << ">();\n"; + sstr << "spectral_t coated = OrientedMaterial<" << childHash << ">::albedo();\n"; } if (auto child = ir->getObjectPool().deref(transmission->next); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "spectral_t next = albedo<" << childHash << ">();\n"; + sstr << "spectral_t next = OrientedMaterial<" << childHash << ">::albedo();\n"; } sstr << "spectral_t retval = btdf + brdf + coated + next;\n"; @@ -391,22 +390,27 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nsample_t generate<" << hashString; - sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<" // TODO: class type specific cache - << hashString << ">) cache)\n{\n"; + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ +)==="; if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) { const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); - sstr << "gen_cache<" << childBrdfHash << "> brdf_cache;\n"; - sstr << "sample_t brdf = generate<" << childBrdfHash << ">(inter, xi, brdf_cache);\n"; + sstr << R"===( +gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; +sample_t brdf = OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); +)==="; // TODO: what to do with child caches? } if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) { const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); - sstr << "gen_cache<" << childBtdfHash << "> btdf_cache;\n"; - sstr << "sample_t btdf = generate<" << childBtdfHash << ">(inter, xi_extra, btdf_cache);\n"; + sstr << R"===( +gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; +sample_t btdf = OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); +)==="; // TODO: what to do with child caches? } @@ -422,9 +426,10 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nsample_t generate<" << hashString; - sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(gen_cache<" - << hashString << ">) cache)\n{\n"; + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ +)==="; sstr << "uint16_t chosenLobe = 0;\npdf_t choiceRcpPdf = 1.f;\n"; @@ -432,14 +437,14 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream { const auto childProductHash = getHashAs4UintsString(childProduct, ir); sstr << "gen_cache<" << childProductHash << "> product_cache;\n"; - sstr << "sample_t product = generate<" << childProductHash << ">(inter, xi, product_cache);\n"; + sstr << "sample_t product = OrientedMaterial<" << childProductHash << ">::generate(inter, xi, xi_extra, product_cache);\n"; // TODO: what to do with child caches? } if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) { const auto childRestHash = getHashAs4UintsString(childRest, ir); sstr << "gen_cache<" << childRestHash << "> rest_cache;\n"; - sstr << "sample_t rest = generate<" << childRestHash << ">(inter, xi, rest_cache);\n"; + sstr << "sample_t rest = OrientedMaterial<" << childRestHash << ">::generate(inter, xi_extra, xi, rest_cache);\n"; // TODO: what to do with child caches? } @@ -465,9 +470,10 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream break; const auto hashString = getHashAs4UintsString(node, ir); - sstr << "template<>\nsample_t generate<" << hashString; - sstr << ">(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(gen_cache<" - << hashString << ">) cache)\n{\n"; + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ +)==="; auto roughness = oren_nayar->ndfParams.getRougness(); sstr << "using oren_nayar_t = bxdf::reflection::SOrenNayar;\n"; @@ -481,7 +487,6 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream sstr << "return _sample;\n}\n"; break; - break; } case CTrueIR::INode::EFinalType::CCookTorrance: { From 26875860fbef7b59db3c8b1c0865bcfcc05a8c40 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 26 May 2026 16:13:39 +0700 Subject: [PATCH 09/26] transparency function impl added --- .../CReferenceUnidirectionalPathTracing.cpp | 210 +++++++++++++++++- 1 file changed, 208 insertions(+), 2 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 598d87917f..080ef3f1d7 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -249,7 +249,7 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t factor = OrientedMaterial<" << childFactorHash << ">::albedo();\n"; } - sstr << "spectral_t retval = contributor + factor;\n"; + sstr << "spectral_t retval = contributor * factor;\n"; sstr << "return retval;\n}\n"; break; } @@ -331,7 +331,7 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << R"===( static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() { - return hlsl::promote(0.0); + return hlsl::promote(1.0); } )==="; } @@ -379,6 +379,212 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::normal(NBL_CO } } +void CReferenceUnidirectionalPathTracing::getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ +)==="; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "scalar_t brdf = OrientedMaterial<" << childBrdfHash << ">::transparency();\n"; + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "scalar_t btdf = OrientedMaterial<" << childBtdfHash << ">::transparency();\n"; + } + + sstr << "scalar_t retval = brdf + btdf;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ +)==="; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "scalar_t product = OrientedMaterial<" << childProductHash << ">::transparency();\n"; + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "scalar_t rest = OrientedMaterial<" << childRestHash << ">::transparency();\n"; + } + + sstr << "scalar_t retval = product + rest;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "scalar_t child" << static_cast(i) << " = OrientedMaterial<" << childHash << ">::transparency();\n"; + } + } + + sstr << "scalar_t retval = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << ";\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ +)==="; + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + const auto childContribHash = getHashAs4UintsString(childContrib, ir); + sstr << "scalar_t contributor = OrientedMaterial<" << childContribHash << ">::transparency();\n"; + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + const auto childFactorHash = getHashAs4UintsString(childFactor, ir); + sstr << "scalar_t factor = OrientedMaterial<" << childFactorHash << ">::transparency();\n"; + } + + sstr << "scalar_t retval = contributor * factor;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ +)==="; + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "scalar_t btdf = OrientedMaterial<" << childHash << ">::transparency();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "scalar_t brdf = OrientedMaterial<" << childHash << ">::transparency();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "scalar_t coated = OrientedMaterial<" << childHash << ">::albedo();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "scalar_t next = OrientedMaterial<" << childHash << ">::albedo();\n"; + } + + sstr << "scalar_t retval = btdf + brdf + coated + next;\n"; + sstr << "return retval;\n}\n"; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: // only cook torrance btdf + { + const auto* btdf = dynamic_cast(node); + if (!btdf) + break; + + const auto transparency = hlsl::pow(btdf->ndfParams.getRougness()[0].scale, 0.001f); + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ + return )===" << transparency << R"===(; +} +)==="; + } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ + return hlsl::promote(1.0); +} +)==="; + } + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() +{ + return hlsl::promote(0.0); +} +)==="; + } + } +} + void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) From a3dbad54fa9ecf4e49c5456eca1f5bdc03ceef2a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 27 May 2026 11:21:03 +0700 Subject: [PATCH 10/26] add aovThroughput function + some fixes to transparency --- .../CReferenceUnidirectionalPathTracing.cpp | 256 +++++++++++++++++- 1 file changed, 241 insertions(+), 15 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 080ef3f1d7..22340024c7 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -127,7 +127,7 @@ struct OrientedMaterial<)===" << hashString << R"===(> { static spectral_t albedo(); static vector3_t normal(NBL_CONST_REF_ARG(aniso_interaction_t) inter); - static spectral_t aov_throughput(); + static spectral_t aovThroughput(); static scalar_t transparency(); static sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); @@ -379,6 +379,222 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::normal(NBL_CO } } +void CReferenceUnidirectionalPathTracing::getAOVThroughputHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ +)==="; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "spectral_t brdf = OrientedMaterial<" << childBrdfHash << ">::aovThroughput();\n"; + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "spectral_t btdf = OrientedMaterial<" << childBtdfHash << ">::aovThroughput();\n"; + } + + sstr << R"===( + return brdf + btdf; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ +)==="; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "spectral_t product = OrientedMaterial<" << childProductHash << ">::aovThroughput();\n"; + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "spectral_t rest = OrientedMaterial<" << childRestHash << ">::aovThroughput();\n"; + } + + sstr << R"===( + return product + rest; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t child" << static_cast(i) << " = OrientedMaterial<" << childHash << ">::aovThroughput();\n"; + } + } + + sstr << "spectral_t retval = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << R"===(; + return retval; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ +)==="; + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + const auto childContribHash = getHashAs4UintsString(childContrib, ir); + sstr << "spectral_t contributor = OrientedMaterial<" << childContribHash << ">::aovThroughput();\n"; + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + const auto childFactorHash = getHashAs4UintsString(childFactor, ir); + sstr << "spectral_t factor = OrientedMaterial<" << childFactorHash << ">::aovThroughput();\n"; + } + + sstr << R"===( + return contributor * factor; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ +)==="; + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t btdf = OrientedMaterial<" << childHash << ">::aovThroughput();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t brdf = OrientedMaterial<" << childHash << ">::aovThroughput();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t coated = OrientedMaterial<" << childHash << ">::aovThroughput();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t next = OrientedMaterial<" << childHash << ">::aovThroughput();\n"; + } + + sstr << R"===( + return btdf + brdf + coated + next; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: // only cook torrance btdf + { + const auto* btdf = dynamic_cast(node); + if (!btdf) + break; + + const auto transparency = hlsl::pow(btdf->ndfParams.getRougness()[0].scale, 0.001f); + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ + return )===" << transparency << R"===(; +} +)==="; + } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ + return hlsl::promote(1.0); +} +)==="; + } + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() +{ + return hlsl::promote(0.0); +} +)==="; + } + } +} + void CReferenceUnidirectionalPathTracing::getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) @@ -406,8 +622,10 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << "scalar_t btdf = OrientedMaterial<" << childBtdfHash << ">::transparency();\n"; } - sstr << "scalar_t retval = brdf + btdf;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return brdf + btdf; +} +)==="; break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -433,8 +651,10 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << "scalar_t rest = OrientedMaterial<" << childRestHash << ">::transparency();\n"; } - sstr << "scalar_t retval = product + rest;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return product + rest; +} +)==="; break; } case CTrueIR::INode::EFinalType::CFactorCombiner: @@ -463,8 +683,10 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << "scalar_t retval = "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); - sstr << ";\n"; - sstr << "return retval;\n}\n"; + sstr << R"===(; + return retval; +} +)==="; break; } case CTrueIR::INode::EFinalType::CWeightedContributor: @@ -490,8 +712,10 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << "scalar_t factor = OrientedMaterial<" << childFactorHash << ">::transparency();\n"; } - sstr << "scalar_t retval = contributor * factor;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return contributor * factor; +} +)==="; break; } case CTrueIR::INode::EFinalType::CCorellatedTransmission: @@ -519,16 +743,18 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() if (auto child = ir->getObjectPool().deref(transmission->coated); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "scalar_t coated = OrientedMaterial<" << childHash << ">::albedo();\n"; + sstr << "scalar_t coated = OrientedMaterial<" << childHash << ">::transparency();\n"; } if (auto child = ir->getObjectPool().deref(transmission->next); child) { const auto childHash = getHashAs4UintsString(child, ir); - sstr << "scalar_t next = OrientedMaterial<" << childHash << ">::albedo();\n"; + sstr << "scalar_t next = OrientedMaterial<" << childHash << ">::transparency();\n"; } - sstr << "scalar_t retval = btdf + brdf + coated + next;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return btdf + brdf + coated + next; +} +)==="; break; } case CTrueIR::INode::EFinalType::CCookTorrance: // only cook torrance btdf @@ -556,7 +782,7 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << R"===( static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() { - return hlsl::promote(1.0); + return 1.0; } )==="; } @@ -578,7 +804,7 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() sstr << R"===( static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() { - return hlsl::promote(0.0); + return 0.0; } )==="; } From c36f9f64d2608b0c5df2b54156b3bcf967fda10f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 27 May 2026 11:41:03 +0700 Subject: [PATCH 11/26] more changes to use raw string literals --- .../CReferenceUnidirectionalPathTracing.cpp | 85 ++++++++++++------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 22340024c7..579f3459b1 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -165,8 +165,10 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t btdf = OrientedMaterial<" << childBtdfHash << ">::albedo();\n"; } - sstr << "spectral_t retval = brdf + btdf;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return brdf + btdf; +} +)==="; break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -192,8 +194,10 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t rest = OrientedMaterial<" << childRestHash << ">::albedo();\n"; } - sstr << "spectral_t retval = product + rest;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return product + rest; +} +)==="; break; } case CTrueIR::INode::EFinalType::CFactorCombiner: @@ -222,8 +226,10 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t retval = "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); - sstr << ";\n"; - sstr << "return retval;\n}\n"; + sstr << R"===(; + return retval; +} +)==="; break; } case CTrueIR::INode::EFinalType::CWeightedContributor: @@ -249,8 +255,10 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t factor = OrientedMaterial<" << childFactorHash << ">::albedo();\n"; } - sstr << "spectral_t retval = contributor * factor;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return contributor * factor; +} +)==="; break; } case CTrueIR::INode::EFinalType::CCorellatedTransmission: @@ -286,8 +294,10 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() sstr << "spectral_t next = OrientedMaterial<" << childHash << ">::albedo();\n"; } - sstr << "spectral_t retval = btdf + brdf + coated + next;\n"; - sstr << "return retval;\n}\n"; + sstr << R"===( + return btdf + brdf + coated + next; +} +)==="; break; } case CTrueIR::INode::EFinalType::CSpectralVariable: @@ -831,8 +841,8 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO { const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); sstr << R"===( -gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; -sample_t brdf = OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; + sample_t brdf = OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); )==="; // TODO: what to do with child caches? } @@ -840,15 +850,18 @@ sample_t brdf = OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(int { const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); sstr << R"===( -gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; -sample_t btdf = OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + sample_t btdf = OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); )==="; // TODO: what to do with child caches? } // TODO: do resampled importance sampling HLSL code - sstr << "return retval;\n}\n"; + sstr << R"===( + return retval; +} +)==="; break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -861,28 +874,35 @@ sample_t btdf = OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(int sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" { + uint16_t chosenLobe = 0; + pdf_t choiceRcpPdf = 1.f; )==="; - sstr << "uint16_t chosenLobe = 0;\npdf_t choiceRcpPdf = 1.f;\n"; - if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) { const auto childProductHash = getHashAs4UintsString(childProduct, ir); - sstr << "gen_cache<" << childProductHash << "> product_cache;\n"; - sstr << "sample_t product = OrientedMaterial<" << childProductHash << ">::generate(inter, xi, xi_extra, product_cache);\n"; + sstr << R"===( + gen_cache<)===" << childProductHash << R"===(> product_cache; + sample_t product = OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, product_cache); +)==="; // TODO: what to do with child caches? } if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) { const auto childRestHash = getHashAs4UintsString(childRest, ir); - sstr << "gen_cache<" << childRestHash << "> rest_cache;\n"; - sstr << "sample_t rest = OrientedMaterial<" << childRestHash << ">::generate(inter, xi_extra, xi, rest_cache);\n"; + sstr << R"===( + gen_cache<)===" << childRestHash << R"===(> rest_cache; + sample_t rest = OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi_extra, xi, rest_cache); +)==="; // TODO: what to do with child caches? } // TODO: weight sample - sstr << "return retval;\n}\n"; + sstr << R"===( + return retval; +} +)==="; break; } case CTrueIR::INode::EFinalType::CWeightedContributor: @@ -902,22 +922,21 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO break; const auto hashString = getHashAs4UintsString(node, ir); + auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" { + using oren_nayar_t = bxdf::reflection::SOrenNayar; + using creation_t = typename oren_nayar_t::creation_type; + creation_t params; + params.A = )===" << roughness.data()[0].scale << R"===(; + oren_nayar_t bxdf = diffuse_op_type::create(params); + typename oren_nayar_t::anisocache_type bxdf_cache; + sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + return _sample; +} )==="; - - auto roughness = oren_nayar->ndfParams.getRougness(); - sstr << "using oren_nayar_t = bxdf::reflection::SOrenNayar;\n"; - sstr << "using creation_t = typename oren_nayar_t::creation_type;\n"; - sstr << "creation_t params;\nparams.A = " << roughness.data()[0].scale << ";\n"; - sstr << "oren_nayar_t bxdf = diffuse_op_type::create(params);\n"; - - sstr << "typename oren_nayar_t::anisocache_type bxdf_cache;\n"; - sstr << "sample_t _sample = bxdf.generate(inter, xi, bxdf_cache);\n"; // TODO: what to do with child caches? - - sstr << "return _sample;\n}\n"; break; } case CTrueIR::INode::EFinalType::CCookTorrance: From bc4776bd657f54191ba73eaac0c35be39dd68511 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 27 May 2026 15:27:39 +0700 Subject: [PATCH 12/26] emission functions --- .../CReferenceUnidirectionalPathTracing.cpp | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 579f3459b1..67467ad2b6 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -329,6 +329,8 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() [[fallthrough]] case CTrueIR::INode::EFinalType::CCookTorrance: [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + [[fallthrough]] case CTrueIR::INode::EFinalType::CBeer: [[fallthrough]] case CTrueIR::INode::EFinalType::CFresnel: @@ -370,6 +372,8 @@ void CReferenceUnidirectionalPathTracing::getNormalHLSLCode(std::ostringstream& [[fallthrough]] case CTrueIR::INode::EFinalType::CCookTorrance: [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + [[fallthrough]] case CTrueIR::INode::EFinalType::CBeer: [[fallthrough]] case CTrueIR::INode::EFinalType::CFresnel: @@ -949,4 +953,209 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } } +void CReferenceUnidirectionalPathTracing::getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ +)==="; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "spectral_t brdf = OrientedMaterial<" << childBrdfHash << ">::emission();\n"; + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "spectral_t btdf = OrientedMaterial<" << childBtdfHash << ">::emission();\n"; + } + + sstr << R"===( + return brdf + btdf; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ +)==="; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "spectral_t product = OrientedMaterial<" << childProductHash << ">::emission();\n"; + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "spectral_t rest = OrientedMaterial<" << childRestHash << ">::emission();\n"; + } + + sstr << R"===( + return product + rest; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t child" << static_cast(i) << " = OrientedMaterial<" << childHash << ">::emission();\n"; + } + } + + sstr << "spectral_t retval = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << R"===(; + return retval; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ +)==="; + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + const auto childContribHash = getHashAs4UintsString(childContrib, ir); + sstr << "spectral_t contributor = OrientedMaterial<" << childContribHash << ">::emission();\n"; + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + const auto childFactorHash = getHashAs4UintsString(childFactor, ir); + sstr << "spectral_t factor = OrientedMaterial<" << childFactorHash << ">::emission();\n"; + } + + sstr << R"===( + return contributor * factor; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ +)==="; + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t btdf = OrientedMaterial<" << childHash << ">::emission();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t brdf = OrientedMaterial<" << childHash << ">::emission();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t coated = OrientedMaterial<" << childHash << ">::emission();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "spectral_t next = OrientedMaterial<" << childHash << ">::emission();\n"; + } + + sstr << R"===( + return btdf + brdf + coated + next; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CEmitter: + { + const auto* emitter = dynamic_cast(node); + if (!emitter) + break; + + const auto strength = emitter->profile.scale; // TODO: how to get emission color like from IES? + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ + return hlsl::promote()===" << strength << R"===(); +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::emission() +{ + return hlsl::promote(0.0); +} +)==="; + } + } +} + } From d49f1d358ddee89a291b209fd6da86f36e149f7c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 28 May 2026 12:07:31 +0700 Subject: [PATCH 13/26] code to set up cook torrance bxdf, probably need to split out to another function --- .../CReferenceUnidirectionalPathTracing.cpp | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 67467ad2b6..d568d7eb1e 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -925,6 +925,9 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO if (!oren_nayar) break; + // TODO: config type alias from where (also allow aniso + // TODO: also might be btdf + const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( @@ -934,7 +937,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO using creation_t = typename oren_nayar_t::creation_type; creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; - oren_nayar_t bxdf = diffuse_op_type::create(params); + oren_nayar_t bxdf = oren_nayar_t::create(params); typename oren_nayar_t::anisocache_type bxdf_cache; sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); return _sample; @@ -945,7 +948,61 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } case CTrueIR::INode::EFinalType::CCookTorrance: { - // TODO + const auto* cook_torrance = dynamic_cast(node); + if (!cook_torrance) + break; + + // TODO: config type alias from where + // TODO: handle anisotropic types + + const auto hashString = getHashAs4UintsString(node, ir); + const auto roughness = cook_torrance->ndfParams.getRougness(); + + std::string bxdf_type; + std::string fresnel_create; + if (cook_torrance->orientedRealEta) + { + // btdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; + + const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; + fresnel_create = R"===( + bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); + bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); +)==="; + } + else + { + // brdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXIsotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; + + const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); + const auto eta = etaNode->getParameter(0).scale; + const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored + fresnel_create = R"===( + bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); +)==="; + } + + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + using cook_torrance_t = )===" << bxdf_type << R"===(; + cook_torrance_t bxdf; + bxdf.ndf = cook_torrance_t::ndf_type::create()===" << roughness.data()[0].scale << R"===(); +)===" << fresnel_create << R"===( + typename cook_torrance_t::anisocache_type bxdf_cache; + sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + return _sample; +} +)==="; + // TODO: what to do with child caches? break; } default: From c2d128837013f998343814cb03528c87e39280b5 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 28 May 2026 16:26:33 +0700 Subject: [PATCH 14/26] complete generate function impls --- .../CReferenceUnidirectionalPathTracing.cpp | 180 ++++++++++++++---- 1 file changed, 138 insertions(+), 42 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index d568d7eb1e..8a50d484dc 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -839,33 +839,35 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" { -)==="; + uint16_t chosenLobe = 0; + pdf_t choiceRcpPdf = 1.f; - if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) - { - const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); - sstr << R"===( - gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; - sample_t brdf = OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + spectral_t lumaContrib = inter.getLuminosityContributionHint(); )==="; - // TODO: what to do with child caches? - } - if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) - { - const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); - sstr << R"===( - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - sample_t btdf = OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); -)==="; - // TODO: what to do with child caches? - } - // TODO: do resampled importance sampling HLSL code + const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); + const auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); + // TODO: what if either node (or both) not available? + + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); sstr << R"===( - return retval; -} + scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBrdfHash << R"===(>::albedo())); + if (u.x < prob) + { + chosenLobe = 0; + gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; + return OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + } + else + { + chosenLobe = 1; + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + } )==="; + // TODO: chosenLobe goes into cache to use in quotient break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -880,43 +882,115 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO { uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; + + spectral_t lumaContrib = inter.getLuminosityContributionHint(); )==="; - if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) - { - const auto childProductHash = getHashAs4UintsString(childProduct, ir); - sstr << R"===( - gen_cache<)===" << childProductHash << R"===(> product_cache; - sample_t product = OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, product_cache); + const auto childProduct = ir->getObjectPool().deref(sum->product); + const auto childRest = ir->getObjectPool().deref(sum->rest); + // TODO: what if either node (or both) not available? + + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + const auto childRestHash = getHashAs4UintsString(childRest, ir); + + sstr << R"===( + scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childRestHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childProductHash << R"===(>::albedo())); + if (u.x < prob) + { + chosenLobe = 0; + gen_cache<)===" << childProductHash << R"===(> brdf_cache; + return OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + } + else + { + chosenLobe = 1; + gen_cache<)===" << childRestHash << R"===(> btdf_cache; + return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + } )==="; - // TODO: what to do with child caches? - } - if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + // TODO: chosenLobe goes into cache to use in quotient + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ +)==="; + + if (auto child = ir->getObjectPool().deref(contrib->contributor); child) { - const auto childRestHash = getHashAs4UintsString(childRest, ir); + const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( - gen_cache<)===" << childRestHash << R"===(> rest_cache; - sample_t rest = OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi_extra, xi, rest_cache); + gen_cache<)===" << childHash << R"===(> contrib_cache; + sample_t contrib = OrientedMaterial<)===" << childHash << R"===(>::generate(inter, xi, xi_extra, contrib_cache); )==="; // TODO: what to do with child caches? } - // TODO: weight sample - sstr << R"===( - return retval; + return contrib; } )==="; break; } - case CTrueIR::INode::EFinalType::CWeightedContributor: + case CTrueIR::INode::EFinalType::CCorellatedTransmission: { - // TODO - break; + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + uint16_t chosenLobe = 0; + pdf_t choiceRcpPdf = 1.f; + + spectral_t lumaContrib = inter.getLuminosityContributionHint(); +)==="; + + const auto childBtdf= ir->getObjectPool().deref(transmission->btdf); + const auto childBottom = ir->getObjectPool().deref(transmission->brdfBottom); + const auto childCoated= ir->getObjectPool().deref(transmission->coated); + // TODO: what if some nodes not available? + + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + const auto childBottomHash = getHashAs4UintsString(childBottom, ir); + const auto childCoatedHash = getHashAs4UintsString(childCoated, ir); + + sstr << R"===( + scalar_t weightBtdf = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()); + scalar_t weightBottom = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBottomHash << R"===(>::albedo()); + scalar_t weightCoated = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childCoatedHash << R"===(>::albedo()); + scalar_t probA = 1.0 / (1.0 + weightBottom / weightBtdf); + scalar_t probB = 1.0 / (1.0 + (weightCoated + weightBtdf) / weightBottom); + if (u.x < probA) + { + chosenLobe = 0; + gen_cache<)===" << childBtdfHash << R"===(> brdf_cache; + return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); } - case CTrueIR::INode::EFinalType::CCorellatedTransmission: + else if (u.y < probB) + { + chosenLobe = 1; + gen_cache<)===" << childBottomHash << R"===(> btdf_cache; + return OrientedMaterial<)===" << childBottomHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + } + else { - // TODO + chosenLobe = 2; + gen_cache<)===" << childCoatedHash << R"===(> coated_cache; + return OrientedMaterial<)===" << childCoatedHash << R"===(>::generate(inter, xi, xi_extra, coated_cache); + } +)==="; + // TODO: chosenLobe goes into cache to use in quotient + // TODO: next node? break; } case CTrueIR::INode::EFinalType::COrenNayar: @@ -925,7 +999,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO if (!oren_nayar) break; - // TODO: config type alias from where (also allow aniso + // TODO: config type alias from where (also allow aniso) // TODO: also might be btdf const auto hashString = getHashAs4UintsString(node, ir); @@ -1005,6 +1079,28 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO // TODO: what to do with child caches? break; } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + // TODO: config type alias from where (also allow aniso) + // TODO: also might be btdf + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + using transmission_t = bxdf::transmission::SDeltaDistribution; + transmission_t bxdf; + typename oren_nayar_t::anisocache_type bxdf_cache; + sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + return _sample; +} +)==="; + break; + } default: break; } From 6359f94bab83d3366ac666764bedf18b59987b7c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 1 Jun 2026 15:57:16 +0700 Subject: [PATCH 15/26] quotientAndWeight functions impl --- .../CReferenceUnidirectionalPathTracing.cpp | 389 +++++++++++++++++- 1 file changed, 379 insertions(+), 10 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 8a50d484dc..c659ac5e96 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -131,7 +131,7 @@ struct OrientedMaterial<)===" << hashString << R"===(> static scalar_t transparency(); static sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); - static eval_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); + static value_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static spectral_t emission(); } )==="; @@ -868,6 +868,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } )==="; // TODO: chosenLobe goes into cache to use in quotient + // TODO: probability of lobe also goes into cache break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -898,14 +899,14 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO if (u.x < prob) { chosenLobe = 0; - gen_cache<)===" << childProductHash << R"===(> brdf_cache; + gen_cache<)===" << childProductHash << R"===(> product_cache; return OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); } else { chosenLobe = 1; - gen_cache<)===" << childRestHash << R"===(> btdf_cache; - return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + gen_cache<)===" << childRestHash << R"===(> rest_cache; + return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, rest_cache); } )==="; // TODO: chosenLobe goes into cache to use in quotient @@ -973,14 +974,14 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO if (u.x < probA) { chosenLobe = 0; - gen_cache<)===" << childBtdfHash << R"===(> brdf_cache; - return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); } else if (u.y < probB) { chosenLobe = 1; - gen_cache<)===" << childBottomHash << R"===(> btdf_cache; - return OrientedMaterial<)===" << childBottomHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + gen_cache<)===" << childBottomHash << R"===(> bottom_cache; + return OrientedMaterial<)===" << childBottomHash << R"===(>::generate(inter, xi, xi_extra, bottom_cache); } else { @@ -1086,7 +1087,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO break; // TODO: config type alias from where (also allow aniso) - // TODO: also might be btdf const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( @@ -1094,7 +1094,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO { using transmission_t = bxdf::transmission::SDeltaDistribution; transmission_t bxdf; - typename oren_nayar_t::anisocache_type bxdf_cache; + typename transmission_t::anisocache_type bxdf_cache; sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); return _sample; } @@ -1106,6 +1106,375 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } } +void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + const std::string combineRestWithRetValCode = R"===( + retval.weight += rest.weight(); + + constexpr bool UseMoreDiv = false; + if constexpr (UseMoreDiv) + { + retval.quotient /= scalar_t(1.0) + rest.weight() / chosenPdf; + retval.quotient += rest.value() / retval.weight(); + } + else // this branch uses one less div + { + const scalar_t rcpChosenPdf = scalar_t(1.0) / chosenPdf; + retval.quotient += rest.value() * rcpChosenPdf; + retval.quotient /= scalar_t(1.0) + rest.weight() * rcpChosenPdf; + } + + // correct for the fact that the `choiceProb` are not normalized + retval.quotient *= choiceSum; + retval.pdf /= choiceSum; + } + + return retval; +)==="; + + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + // TODO + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{uint16_t chosenLobe = 0; + pdf_t choiceProb = 1.0; + pdf_t choiceSum = 1.0; + +)==="; + // TODO get chosen lobe from cache + // TODO also get choice prob from cache + + const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); + const auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); + // TODO: what if either node (or both) not available? + + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + + // TODO how to get child cache from generate? + + sstr << R"===( + quotient_weight_t retval; + if (chosenLobe == 0) + { + gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; + retval = OrientedMaterial<)===" << childBrdfHash << R"===(>::quotientAndWeight(_sample, inter, brdf_cache); + } + else + { + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); + } + + if (retval.weight() < bit_cast(numeric_limits::infinity)) + { + const scalar_t chosenPdf = retval.weight() * choiceProb; + value_weight_t rest; + + if (chosenLobe == 0) + { + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + rest = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter, btdf_cache); + } + else + { + gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; + rest = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter, brdf_cache); + } +)===" << combineRestWithRetValCode; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + // TODO + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + uint16_t chosenLobe = 0; + pdf_t choiceProb = 1.0; + pdf_t choiceSum = 1.0; +)==="; + + const auto childProduct = ir->getObjectPool().deref(sum->product); + const auto childRest = ir->getObjectPool().deref(sum->rest); + // TODO: what if either node (or both) not available? + + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + const auto childRestHash = getHashAs4UintsString(childRest, ir); + + sstr << R"===( + quotient_weight_t retval; + if (chosenLobe == 0) + { + gen_cache<)===" << childProductHash << R"===(> product_cache; + retval = OrientedMaterial<)===" << childProductHash << R"===(>::quotientAndWeight(_sample, inter, product_cache); + } + else + { + gen_cache<)===" << childRestHash << R"===(> rest_cache; + retval = OrientedMaterial<)===" << childRestHash << R"===(>::quotientAndWeight(_sample, inter, rest_cache); + } + + if (retval.weight() < bit_cast(numeric_limits::infinity)) + { + const scalar_t chosenPdf = retval.weight() * choiceProb; + value_weight_t rest; + + if (chosenLobe == 0) + { + gen_cache<)===" << childRestHash << R"===(> rest_cache; + rest = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter, rest_cache); + } + else + { + gen_cache<)===" << childProductHash << R"===(> product_cache; + rest = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter, product_cache); + } +)===" << combineRestWithRetValCode; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + // TODO + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ +)==="; + + if (auto child = ir->getObjectPool().deref(contrib->contributor); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + gen_cache<)===" << childHash << R"===(> contrib_cache; + quotient_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, contrib_cache); +)==="; + // TODO: what to do with child caches? + } + + if (auto child = ir->getObjectPool().deref(contrib->factor); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + gen_cache<)===" << childHash << R"===(> factor_cache; + quotient_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, factor_cache); +)==="; + // TODO: what to do with child caches? + } + + sstr << R"===( + contrib.quotient *= factor.quotient(); + contrib.weight *= factor.weight(); + return contrib; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + // TODO + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + uint16_t chosenLobe = 0; + pdf_t choiceProb = 1.0; + pdf_t choiceSum = 1.0; +)==="; + + const auto childBtdf = ir->getObjectPool().deref(transmission->btdf); + const auto childBottom = ir->getObjectPool().deref(transmission->brdfBottom); + const auto childCoated = ir->getObjectPool().deref(transmission->coated); + // TODO: what if some nodes not available? + + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + const auto childBottomHash = getHashAs4UintsString(childBottom, ir); + const auto childCoatedHash = getHashAs4UintsString(childCoated, ir); + + sstr << R"===(R"===( + quotient_weight_t retval; + if (chosenLobe == 0) + { + gen_cache<)===" << childBtdfHash << R"===(> brdf_cache; + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, brdf_cache); + } + else if (chosenLobe == 1) + { + gen_cache<)===" << childBottomHash << R"===(> btdf_cache; + retval = OrientedMaterial<)===" << childBottomHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); + } + else + { + gen_cache<)===" << childCoatedHash << R"===(> btdf_cache; + retval = OrientedMaterial<)===" << childCoatedHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); + } + + if (retval.weight() < bit_cast(numeric_limits::infinity)) + { + const scalar_t chosenPdf = retval.weight() * choiceProb; + value_weight_t rest = value_weight_t::create(0.0,0.0); + + if (chosenLobe != 0) + { + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + value_weight_t child = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter, btdf_cache); + rest.value += child.value(); + // TODO check lobe can generate then add weight + rest.weight += child.weight(); + } + if (chosenLobe != 1) + { + gen_cache<)===" << childBottomHash << R"===(> bottom_cache; + value_weight_t child = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter, bottom_cache); + rest.value += child.value(); + // TODO check lobe can generate then add weight + rest.weight += child.weight(); + } + if (chosenLobe != 2) + { + gen_cache<)===" << childCoatedHash << R"===(> coated_cache; + value_weight_t child = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter, coated_cache); + rest.value += child.value(); + // TODO check lobe can generate then add weight + rest.weight += child.weight(); + } +)===" << combineRestWithRetValCode; + // TODO: next node? + break; + } + case CTrueIR::INode::EFinalType::COrenNayar: + { + const auto* oren_nayar = dynamic_cast(node); + if (!oren_nayar) + break; + + // TODO: config type alias from where (also allow aniso) + // TODO: also might be btdf + + const auto hashString = getHashAs4UintsString(node, ir); + auto roughness = oren_nayar->ndfParams.getRougness(); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + using oren_nayar_t = bxdf::reflection::SOrenNayar; + using creation_t = typename oren_nayar_t::creation_type; + creation_t params; + params.A = )===" << roughness.data()[0].scale << R"===(; + oren_nayar_t bxdf = oren_nayar_t::create(params); + typename oren_nayar_t::anisocache_type bxdf_cache; + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + return quo; +} +)==="; + // TODO: what to do with child caches? + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + { + const auto* cook_torrance = dynamic_cast(node); + if (!cook_torrance) + break; + + // TODO: config type alias from where + // TODO: handle anisotropic types + + const auto hashString = getHashAs4UintsString(node, ir); + const auto roughness = cook_torrance->ndfParams.getRougness(); + + std::string bxdf_type; + std::string fresnel_create; + if (cook_torrance->orientedRealEta) + { + // btdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; + + const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; + fresnel_create = R"===( + bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); + bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); +)==="; + } + else + { + // brdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXIsotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; + + const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); + const auto eta = etaNode->getParameter(0).scale; + const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored + fresnel_create = R"===( + bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); +)==="; + } + + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + using cook_torrance_t = )===" << bxdf_type << R"===(; + cook_torrance_t bxdf; + bxdf.ndf = cook_torrance_t::ndf_type::create()===" << roughness.data()[0].scale << R"===(); +)===" << fresnel_create << R"===( + typename cook_torrance_t::anisocache_type bxdf_cache; + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + return quo; +} +)==="; + // TODO: what to do with child caches? + break; + } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + // TODO: config type alias from where (also allow aniso) + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +{ + using transmission_t = bxdf::transmission::SDeltaDistribution; + transmission_t bxdf; + typename transmission_t::anisocache_type bxdf_cache; + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + return quo; +} +)==="; + break; + } + default: + break; + } +} + void CReferenceUnidirectionalPathTracing::getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) From 7bb2204c38b6bd54e65a7a412e4c7950cd20c1d6 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 1 Jun 2026 16:40:19 +0700 Subject: [PATCH 16/26] evalAndWeight functions impls --- .../CReferenceUnidirectionalPathTracing.cpp | 379 +++++++++++++++--- 1 file changed, 334 insertions(+), 45 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index c659ac5e96..9ede35e322 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -131,7 +131,7 @@ struct OrientedMaterial<)===" << hashString << R"===(> static scalar_t transparency(); static sample_t generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); - static value_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); + static value_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter); static spectral_t emission(); } )==="; @@ -837,7 +837,7 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; @@ -879,7 +879,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; @@ -920,7 +920,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { )==="; @@ -948,7 +948,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; @@ -1006,7 +1006,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using oren_nayar_t = bxdf::reflection::SOrenNayar; using creation_t = typename oren_nayar_t::creation_type; @@ -1066,7 +1066,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using cook_torrance_t = )===" << bxdf_type << R"===(; cook_torrance_t bxdf; @@ -1090,7 +1090,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using transmission_t = bxdf::transmission::SDeltaDistribution; transmission_t bxdf; @@ -1143,8 +1143,9 @@ void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostring const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" -{uint16_t chosenLobe = 0; +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) +{ + uint16_t chosenLobe = 0; pdf_t choiceProb = 1.0; pdf_t choiceSum = 1.0; @@ -1180,15 +1181,9 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie value_weight_t rest; if (chosenLobe == 0) - { - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - rest = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter, btdf_cache); - } + rest = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); else - { - gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; - rest = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter, brdf_cache); - } + rest = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); )===" << combineRestWithRetValCode; break; } @@ -1201,7 +1196,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint16_t chosenLobe = 0; pdf_t choiceProb = 1.0; @@ -1234,15 +1229,9 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie value_weight_t rest; if (chosenLobe == 0) - { - gen_cache<)===" << childRestHash << R"===(> rest_cache; - rest = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter, rest_cache); - } + rest = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); else - { - gen_cache<)===" << childProductHash << R"===(> product_cache; - rest = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter, product_cache); - } + rest = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); )===" << combineRestWithRetValCode; break; } @@ -1255,7 +1244,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { )==="; @@ -1296,7 +1285,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint16_t chosenLobe = 0; pdf_t choiceProb = 1.0; @@ -1312,22 +1301,22 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto childBottomHash = getHashAs4UintsString(childBottom, ir); const auto childCoatedHash = getHashAs4UintsString(childCoated, ir); - sstr << R"===(R"===( + sstr << R"===( quotient_weight_t retval; if (chosenLobe == 0) { - gen_cache<)===" << childBtdfHash << R"===(> brdf_cache; - retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, brdf_cache); + gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); } else if (chosenLobe == 1) { - gen_cache<)===" << childBottomHash << R"===(> btdf_cache; - retval = OrientedMaterial<)===" << childBottomHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); + gen_cache<)===" << childBottomHash << R"===(> bottom_cache; + retval = OrientedMaterial<)===" << childBottomHash << R"===(>::quotientAndWeight(_sample, inter, bottom_cache); } else { - gen_cache<)===" << childCoatedHash << R"===(> btdf_cache; - retval = OrientedMaterial<)===" << childCoatedHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); + gen_cache<)===" << childCoatedHash << R"===(> coated_cache; + retval = OrientedMaterial<)===" << childCoatedHash << R"===(>::quotientAndWeight(_sample, inter, coated_cache); } if (retval.weight() < bit_cast(numeric_limits::infinity)) @@ -1337,24 +1326,21 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie if (chosenLobe != 0) { - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - value_weight_t child = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter, btdf_cache); + value_weight_t child = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); // TODO check lobe can generate then add weight rest.weight += child.weight(); } if (chosenLobe != 1) { - gen_cache<)===" << childBottomHash << R"===(> bottom_cache; - value_weight_t child = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter, bottom_cache); + value_weight_t child = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); // TODO check lobe can generate then add weight rest.weight += child.weight(); } if (chosenLobe != 2) { - gen_cache<)===" << childCoatedHash << R"===(> coated_cache; - value_weight_t child = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter, coated_cache); + value_weight_t child = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); // TODO check lobe can generate then add weight rest.weight += child.weight(); @@ -1375,7 +1361,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using oren_nayar_t = bxdf::reflection::SOrenNayar; using creation_t = typename oren_nayar_t::creation_type; @@ -1435,7 +1421,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using cook_torrance_t = )===" << bxdf_type << R"===(; cook_torrance_t bxdf; @@ -1459,7 +1445,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto hashString = getHashAs4UintsString(node, ir); sstr << R"===( -static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache" +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { using transmission_t = bxdf::transmission::SDeltaDistribution; transmission_t bxdf; @@ -1475,6 +1461,309 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } } +void CReferenceUnidirectionalPathTracing::getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + // TODO + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ +)==="; + + const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); + const auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); + // TODO: what if either node (or both) not available? + + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + + // TODO defensive sampler + // TODO check lobe can generate + + sstr << R"===( + value_weight_t retval = value_weight_t::create(0.0,0.0); + pdf_t targetSum = 0.0; + { + value_weight_t lobe = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + { + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + + retval.weight /= targetSum; + return retval; +)==="; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + // TODO + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ +)==="; + + const auto childProduct = ir->getObjectPool().deref(sum->product); + const auto childRest = ir->getObjectPool().deref(sum->rest); + // TODO: what if either node (or both) not available? + + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + const auto childRestHash = getHashAs4UintsString(childRest, ir); + + sstr << R"===( + value_weight_t retval = value_weight_t::create(0.0,0.0); + pdf_t targetSum = 0.0; + { + value_weight_t lobe = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + { + value_weight_t lobe = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + + retval.weight /= targetSum; + return retval; +)==="; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + // TODO + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ +)==="; + + if (auto child = ir->getObjectPool().deref(contrib->contributor); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + gen_cache<)===" << childHash << R"===(> contrib_cache; + value_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, contrib_cache); +)==="; + // TODO: what to do with child caches? + } + + if (auto child = ir->getObjectPool().deref(contrib->factor); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + gen_cache<)===" << childHash << R"===(> factor_cache; + value_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, factor_cache); +)==="; + // TODO: what to do with child caches? + } + + sstr << R"===( + contrib.quotient *= factor.quotient(); + contrib.weight *= factor.weight(); + return contrib; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + // TODO + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ +)==="; + + const auto childBtdf = ir->getObjectPool().deref(transmission->btdf); + const auto childBottom = ir->getObjectPool().deref(transmission->brdfBottom); + const auto childCoated = ir->getObjectPool().deref(transmission->coated); + // TODO: what if some nodes not available? + + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + const auto childBottomHash = getHashAs4UintsString(childBottom, ir); + const auto childCoatedHash = getHashAs4UintsString(childCoated, ir); + + sstr << R"===( + value_weight_t retval = value_weight_t::create(0.0,0.0); + pdf_t targetSum = 0.0; + { + value_weight_t lobe = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + { + value_weight_t lobe = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + { + value_weight_t lobe = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + // TODO check lobe can generate + const scalar_t target = lobe.choiceTarget(interaction); + targetSum += target; + retval.weight += lobe.weight() * target; + } + + retval.weight /= targetSum; + return retval; +)==="; + // TODO: next node? + break; + } + case CTrueIR::INode::EFinalType::COrenNayar: + { + const auto* oren_nayar = dynamic_cast(node); + if (!oren_nayar) + break; + + // TODO: config type alias from where (also allow aniso) + // TODO: also might be btdf + + const auto hashString = getHashAs4UintsString(node, ir); + auto roughness = oren_nayar->ndfParams.getRougness(); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ + using oren_nayar_t = bxdf::reflection::SOrenNayar; + using creation_t = typename oren_nayar_t::creation_type; + creation_t params; + params.A = )===" << roughness.data()[0].scale << R"===(; + oren_nayar_t bxdf = oren_nayar_t::create(params); + quotient_weight_t quo = bxdf.evalAndWeight(_sample, inter); + return quo; +} +)==="; + // TODO: what to do with child caches? + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + { + const auto* cook_torrance = dynamic_cast(node); + if (!cook_torrance) + break; + + // TODO: config type alias from where + // TODO: handle anisotropic types + + const auto hashString = getHashAs4UintsString(node, ir); + const auto roughness = cook_torrance->ndfParams.getRougness(); + + std::string bxdf_type; + std::string fresnel_create; + if (cook_torrance->orientedRealEta) + { + // btdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; + + const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; + fresnel_create = R"===( + bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); + bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); +)==="; + } + else + { + // brdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXIsotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; + + const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); + const auto eta = etaNode->getParameter(0).scale; + const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored + fresnel_create = R"===( + bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); +)==="; + } + + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ + using cook_torrance_t = )===" << bxdf_type << R"===(; + cook_torrance_t bxdf; + bxdf.ndf = cook_torrance_t::ndf_type::create()===" << roughness.data()[0].scale << R"===(); +)===" << fresnel_create << R"===( + value_weight_t quo = bxdf.evalAndWeight(_sample, inter); + return quo; +} +)==="; + // TODO: what to do with child caches? + break; + } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + // TODO: config type alias from where (also allow aniso) + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ + using transmission_t = bxdf::transmission::SDeltaDistribution; + transmission_t bxdf; + value_weight_t quo = bxdf.evalAndWeight(_sample, inter); + return quo; +} +)==="; + break; + } + default: + break; + } +} + void CReferenceUnidirectionalPathTracing::getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) From 3c6c684c83e63383f0fbc7b4f41b735ab8f3a356 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 1 Jun 2026 17:08:08 +0700 Subject: [PATCH 17/26] fix some eval bugs not doing eval --- .../CReferenceUnidirectionalPathTracing.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 9ede35e322..740d1b5259 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -1575,8 +1575,7 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe { const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( - gen_cache<)===" << childHash << R"===(> contrib_cache; - value_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, contrib_cache); + value_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::evalAndWeight(_sample, inter); )==="; // TODO: what to do with child caches? } @@ -1585,10 +1584,8 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe { const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( - gen_cache<)===" << childHash << R"===(> factor_cache; - value_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, factor_cache); + value_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::evalAndWeight(_sample, inter); )==="; - // TODO: what to do with child caches? } sstr << R"===( @@ -1678,7 +1675,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe return quo; } )==="; - // TODO: what to do with child caches? break; } case CTrueIR::INode::EFinalType::CCookTorrance: @@ -1736,7 +1732,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe return quo; } )==="; - // TODO: what to do with child caches? break; } case CTrueIR::INode::EFinalType::CDeltaTransmission: From 534b9595e77f15df5dd9cc6a8b1757b2248322bc Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 2 Jun 2026 16:53:53 +0700 Subject: [PATCH 18/26] add cache struct declares, defines and usage --- .../CReferenceUnidirectionalPathTracing.h | 4 + .../CReferenceUnidirectionalPathTracing.cpp | 229 +++++++++++------- 2 files changed, 148 insertions(+), 85 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index c0d24fac48..56a4e015b6 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -24,8 +24,12 @@ class CReferenceUnidirectionalPathTracing final : public IBackend private: std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; + bool isNodeTypeContributor(CTrueIR::INode::EFinalType type) const; + void getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getCacheDefineCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 740d1b5259..a60252d5c5 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -7,7 +7,7 @@ namespace nbl::asset::material_compiler3 { - core::smart_refctd_ptr CReferenceUnidirectionalPathTracing::compile(const CTrueIR* ir, const std::span materialHandles) +core::smart_refctd_ptr CReferenceUnidirectionalPathTracing::compile(const CTrueIR* ir, const std::span materialHandles) { auto res = core::make_smart_refctd_ptr(); @@ -34,6 +34,7 @@ struct OrientedMaterial; nodeStack.push_back(rootHandle); const auto& pool = ir->getObjectPool(); + std::string rootHandleString; while (!nodeStack.empty()) { const auto handle = nodeStack.back(); @@ -63,6 +64,7 @@ struct OrientedMaterial; for (const auto& nodeHandle : visitedNodes) { const auto* node = pool.deref(nodeHandle); + getCacheDefineCode(code, node, ir); getAlbedoHLSLCode(code, node, ir); getNormalHLSLCode(code, node, ir); getAOVThroughputHLSLCode(code, node, ir); @@ -114,14 +116,22 @@ std::string CReferenceUnidirectionalPathTracing::getHashAs4UintsString(const CTr return hashString.str(); } +bool CReferenceUnidirectionalPathTracing::isNodeTypeContributor(CTrueIR::INode::EFinalType type) const +{ + return (type == CTrueIR::INode::EFinalType::COrenNayar) || + (type == CTrueIR::INode::EFinalType::CCookTorrance) || + (type == CTrueIR::INode::EFinalType::CDeltaTransmission); +} + void CReferenceUnidirectionalPathTracing::getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { // define templates of node material structs const auto hashString = getHashAs4UintsString(node, ir); - - // TODO: specialize gen_cache struct sstr << R"===( +template<> +struct gen_cache<)===" << hashString << R"===(>; + template<> struct OrientedMaterial<)===" << hashString << R"===(> { @@ -133,11 +143,109 @@ struct OrientedMaterial<)===" << hashString << R"===(> static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static value_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter); static spectral_t emission(); -} +}; )==="; } +void CReferenceUnidirectionalPathTracing::getCacheDefineCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + const auto hashString = getHashAs4UintsString(node, ir); + const auto nodeType = node->getFinalType(); + + if (isNodeTypeContributor(nodeType)) + { + switch (nodeType) + { + case CTrueIR::INode::EFinalType::COrenNayar: + { + // should be leaf here, so not going to try children + // TODO: config type alias from where (also allow aniso) + // TODO: also might be btdf + sstr << R"===( +template<> +struct gen_cache<)===" << hashString << R"===(> +{ + using bxdf_t = bxdf::reflection::SOrenNayar; + typename bxdf_t::anisocache_type bxdf_cache; +}; +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCookTorrance: + { + const auto cook_torrance = dynamic_cast(node); + std::string bxdf_type; + if (cook_torrance->orientedRealEta) + { + // btdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; + } + else + { + // brdf + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXIsotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; + } + sstr << R"===( +template<> +struct gen_cache<)===" << hashString << R"===(> +{ + using bxdf_t = )===" << bxdf_type << R"===(; + typename bxdf_t::anisocache_type bxdf_cache; +}; +)==="; + break; + } + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + sstr << R"===( +template<> +struct gen_cache<)===" << hashString << R"===(> +{ + using bxdf_t = bxdf::transmission::SDeltaDistribution; + typename bxdf_t::anisocache_type bxdf_cache; +}; +)==="; + } + default: + break; + } + } + else + { + sstr << R"===( +template<> +struct gen_cache<)===" << hashString << R"===(> +{ + uint8_t chosenLobe; +)==="; + const auto childCount = node->getChildCount(); + if (childCount) + { + for (auto childIx = 0; childIx < childCount; childIx++) + { + const auto childHandle = node->getChildHandle(childIx); + if (const auto child = ir->getObjectPool().deref(childHandle); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + gen_cache<)===" << childHash << R"===(> child)===" << childIx << R"===(; +)==="; + } + } + } + sstr << R"===( +}; +)==="; + } +} + void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) { switch (node->getFinalType()) @@ -839,7 +947,6 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; spectral_t lumaContrib = inter.getLuminosityContributionHint(); @@ -856,18 +963,15 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBrdfHash << R"===(>::albedo())); if (u.x < prob) { - chosenLobe = 0; - gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; - return OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + cache.chosenLobe = 0; + return OrientedMaterial<)===" << childBrdfHash << R"===(>::generate(inter, xi, xi_extra, cache.child0); } else { - chosenLobe = 1; - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + cache.chosenLobe = 1; + return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, cache.child1); } )==="; - // TODO: chosenLobe goes into cache to use in quotient // TODO: probability of lobe also goes into cache break; } @@ -881,7 +985,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; spectral_t lumaContrib = inter.getLuminosityContributionHint(); @@ -898,18 +1001,15 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childRestHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childProductHash << R"===(>::albedo())); if (u.x < prob) { - chosenLobe = 0; - gen_cache<)===" << childProductHash << R"===(> product_cache; - return OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, brdf_cache); + cache.chosenLobe = 0; + return OrientedMaterial<)===" << childProductHash << R"===(>::generate(inter, xi, xi_extra, cache.child0); } else { - chosenLobe = 1; - gen_cache<)===" << childRestHash << R"===(> rest_cache; - return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, rest_cache); + cache.chosenLobe = 1; + return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, cache.child1); } )==="; - // TODO: chosenLobe goes into cache to use in quotient break; } case CTrueIR::INode::EFinalType::CWeightedContributor: @@ -928,10 +1028,8 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO { const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( - gen_cache<)===" << childHash << R"===(> contrib_cache; - sample_t contrib = OrientedMaterial<)===" << childHash << R"===(>::generate(inter, xi, xi_extra, contrib_cache); + sample_t contrib = OrientedMaterial<)===" << childHash << R"===(>::generate(inter, xi, xi_extra, cache.child0); )==="; - // TODO: what to do with child caches? } sstr << R"===( @@ -950,7 +1048,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; pdf_t choiceRcpPdf = 1.f; spectral_t lumaContrib = inter.getLuminosityContributionHint(); @@ -973,21 +1070,18 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO scalar_t probB = 1.0 / (1.0 + (weightCoated + weightBtdf) / weightBottom); if (u.x < probA) { - chosenLobe = 0; - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, btdf_cache); + cache.chosenLobe = 0; + return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, cache.child0); } else if (u.y < probB) { - chosenLobe = 1; - gen_cache<)===" << childBottomHash << R"===(> bottom_cache; - return OrientedMaterial<)===" << childBottomHash << R"===(>::generate(inter, xi, xi_extra, bottom_cache); + cache.chosenLobe = 1; + return OrientedMaterial<)===" << childBottomHash << R"===(>::generate(inter, xi, xi_extra, cache.child1); } else { - chosenLobe = 2; - gen_cache<)===" << childCoatedHash << R"===(> coated_cache; - return OrientedMaterial<)===" << childCoatedHash << R"===(>::generate(inter, xi, xi_extra, coated_cache); + cache.chosenLobe = 2; + return OrientedMaterial<)===" << childCoatedHash << R"===(>::generate(inter, xi, xi_extra, cache.child2); } )==="; // TODO: chosenLobe goes into cache to use in quotient @@ -1013,8 +1107,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; oren_nayar_t bxdf = oren_nayar_t::create(params); - typename oren_nayar_t::anisocache_type bxdf_cache; - sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + sample_t _sample = bxdf.generate(inter, xi, cache.bxdf_cache); return _sample; } )==="; @@ -1072,8 +1165,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO cook_torrance_t bxdf; bxdf.ndf = cook_torrance_t::ndf_type::create()===" << roughness.data()[0].scale << R"===(); )===" << fresnel_create << R"===( - typename cook_torrance_t::anisocache_type bxdf_cache; - sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + sample_t _sample = bxdf.generate(inter, xi, cache.bxdf_cache); return _sample; } )==="; @@ -1094,8 +1186,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO { using transmission_t = bxdf::transmission::SDeltaDistribution; transmission_t bxdf; - typename transmission_t::anisocache_type bxdf_cache; - sample_t _sample = bxdf.generate(inter, xi, bxdf_cache); + sample_t _sample = bxdf.generate(inter, xi, cache.bxdf_cache); return _sample; } )==="; @@ -1145,12 +1236,11 @@ void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostring sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; + uint8_t chosenLobe = child.chosenLobe; pdf_t choiceProb = 1.0; pdf_t choiceSum = 1.0; )==="; - // TODO get chosen lobe from cache // TODO also get choice prob from cache const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); @@ -1159,21 +1249,13 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); - - // TODO how to get child cache from generate? sstr << R"===( quotient_weight_t retval; if (chosenLobe == 0) - { - gen_cache<)===" << childBrdfHash << R"===(> brdf_cache; - retval = OrientedMaterial<)===" << childBrdfHash << R"===(>::quotientAndWeight(_sample, inter, brdf_cache); - } + retval = OrientedMaterial<)===" << childBrdfHash << R"===(>::quotientAndWeight(_sample, inter, cache.child0); else - { - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); - } + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, cache.child1); if (retval.weight() < bit_cast(numeric_limits::infinity)) { @@ -1198,7 +1280,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; + uint8_t chosenLobe = cache.chosenLobe; pdf_t choiceProb = 1.0; pdf_t choiceSum = 1.0; )==="; @@ -1213,15 +1295,9 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie sstr << R"===( quotient_weight_t retval; if (chosenLobe == 0) - { - gen_cache<)===" << childProductHash << R"===(> product_cache; - retval = OrientedMaterial<)===" << childProductHash << R"===(>::quotientAndWeight(_sample, inter, product_cache); - } + retval = OrientedMaterial<)===" << childProductHash << R"===(>::quotientAndWeight(_sample, inter, cache.child0); else - { - gen_cache<)===" << childRestHash << R"===(> rest_cache; - retval = OrientedMaterial<)===" << childRestHash << R"===(>::quotientAndWeight(_sample, inter, rest_cache); - } + retval = OrientedMaterial<)===" << childRestHash << R"===(>::quotientAndWeight(_sample, inter, cache.child1); if (retval.weight() < bit_cast(numeric_limits::infinity)) { @@ -1237,7 +1313,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } case CTrueIR::INode::EFinalType::CWeightedContributor: { - // TODO const auto* contrib = dynamic_cast(node); if (!contrib) break; @@ -1252,10 +1327,8 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie { const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( - gen_cache<)===" << childHash << R"===(> contrib_cache; - quotient_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, contrib_cache); + quotient_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, cache.child0); )==="; - // TODO: what to do with child caches? } if (auto child = ir->getObjectPool().deref(contrib->factor); child) @@ -1265,7 +1338,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie gen_cache<)===" << childHash << R"===(> factor_cache; quotient_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, factor_cache); )==="; - // TODO: what to do with child caches? } sstr << R"===( @@ -1278,7 +1350,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } case CTrueIR::INode::EFinalType::CCorellatedTransmission: { - // TODO const auto* transmission = dynamic_cast(node); if (!transmission) break; @@ -1287,7 +1358,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - uint16_t chosenLobe = 0; + uint8_t chosenLobe = cache.chosenLobe; pdf_t choiceProb = 1.0; pdf_t choiceSum = 1.0; )==="; @@ -1304,20 +1375,11 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie sstr << R"===( quotient_weight_t retval; if (chosenLobe == 0) - { - gen_cache<)===" << childBtdfHash << R"===(> btdf_cache; - retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, btdf_cache); - } + retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::quotientAndWeight(_sample, inter, cache.child0); else if (chosenLobe == 1) - { - gen_cache<)===" << childBottomHash << R"===(> bottom_cache; - retval = OrientedMaterial<)===" << childBottomHash << R"===(>::quotientAndWeight(_sample, inter, bottom_cache); - } + retval = OrientedMaterial<)===" << childBottomHash << R"===(>::quotientAndWeight(_sample, inter, cache.child1); else - { - gen_cache<)===" << childCoatedHash << R"===(> coated_cache; - retval = OrientedMaterial<)===" << childCoatedHash << R"===(>::quotientAndWeight(_sample, inter, coated_cache); - } + retval = OrientedMaterial<)===" << childCoatedHash << R"===(>::quotientAndWeight(_sample, inter, cache.child2); if (retval.weight() < bit_cast(numeric_limits::infinity)) { @@ -1368,8 +1430,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; oren_nayar_t bxdf = oren_nayar_t::create(params); - typename oren_nayar_t::anisocache_type bxdf_cache; - quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, cache.bxdf_cache); return quo; } )==="; @@ -1427,8 +1488,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie cook_torrance_t bxdf; bxdf.ndf = cook_torrance_t::ndf_type::create()===" << roughness.data()[0].scale << R"===(); )===" << fresnel_create << R"===( - typename cook_torrance_t::anisocache_type bxdf_cache; - quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, cache.bxdf_cache); return quo; } )==="; @@ -1449,8 +1509,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie { using transmission_t = bxdf::transmission::SDeltaDistribution; transmission_t bxdf; - typename transmission_t::anisocache_type bxdf_cache; - quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, bxdf_cache); + quotient_weight_t quo = bxdf.quotientAndWeight(_sample, inter, cache.bxdf_cache); return quo; } )==="; From 89845ac701a4c6d642046ce7e373bdf4963b230b Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 3 Jun 2026 14:31:52 +0700 Subject: [PATCH 19/26] canGenerate function and use in quotient and eval funcs --- .../CReferenceUnidirectionalPathTracing.h | 11 +- .../CReferenceUnidirectionalPathTracing.cpp | 326 +++++++++++++++--- 2 files changed, 286 insertions(+), 51 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index 56a4e015b6..6357e8a79b 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -25,26 +25,19 @@ class CReferenceUnidirectionalPathTracing final : public IBackend std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; bool isNodeTypeContributor(CTrueIR::INode::EFinalType type) const; - void getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getCacheDefineCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getAOVThroughputHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index a60252d5c5..6cfb0e0db3 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -143,6 +143,8 @@ struct OrientedMaterial<)===" << hashString << R"===(> static quotient_weight_t quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache); static value_weight_t evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter); static spectral_t emission(); + + static bool canGenerate(); }; )==="; @@ -1260,12 +1262,23 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie if (retval.weight() < bit_cast(numeric_limits::infinity)) { const scalar_t chosenPdf = retval.weight() * choiceProb; - value_weight_t rest; + value_weight_t rest = value_weight_t::create(0.0, 0.0); + value_weight_t other; if (chosenLobe == 0) - rest = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); + { + other = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); + rest.value = other.value(); + if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) + rest.weight = other.weight(); + } else - rest = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); + { + other = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); + rest.value = other.value(); + if (OrientedMaterial<)===" << childBrdfHash << R"===(>::canGenerate()) + rest.weight = other.weight(); + } )===" << combineRestWithRetValCode; break; } @@ -1302,12 +1315,23 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie if (retval.weight() < bit_cast(numeric_limits::infinity)) { const scalar_t chosenPdf = retval.weight() * choiceProb; - value_weight_t rest; + value_weight_t rest = value_weight_t::create(0.0, 0.0); + value_weight_t other; if (chosenLobe == 0) - rest = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); + { + other = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); + rest.value = other.value(); + if (OrientedMaterial<)===" << childRestHash << R"===(>::canGenerate()) + rest.weight = other.weight(); + } else - rest = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); + { + other = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); + rest.value = other.value(); + if (OrientedMaterial<)===" << childProductHash << R"===(>::canGenerate()) + rest.weight = other.weight(); + } )===" << combineRestWithRetValCode; break; } @@ -1337,12 +1361,14 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie sstr << R"===( gen_cache<)===" << childHash << R"===(> factor_cache; quotient_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, factor_cache); + bool factorHasWeight = OrientedMaterial<)===" << childHash << R"===(>::canGenerate(); )==="; } sstr << R"===( contrib.quotient *= factor.quotient(); - contrib.weight *= factor.weight(); + if (factorHasWeight) + contrib.weight *= factor.weight(); return contrib; } )==="; @@ -1390,22 +1416,22 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie { value_weight_t child = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); - // TODO check lobe can generate then add weight - rest.weight += child.weight(); + if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) + rest.weight += child.weight(); } if (chosenLobe != 1) { value_weight_t child = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); - // TODO check lobe can generate then add weight - rest.weight += child.weight(); + if (OrientedMaterial<)===" << childBottomHash << R"===(>::canGenerate()) + rest.weight += child.weight(); } if (chosenLobe != 2) { value_weight_t child = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); - // TODO check lobe can generate then add weight - rest.weight += child.weight(); + if (OrientedMaterial<)===" << childCoatedHash << R"===(>::canGenerate()) + rest.weight += child.weight(); } )===" << combineRestWithRetValCode; // TODO: next node? @@ -1553,18 +1579,22 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe { value_weight_t lobe = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childBrdfHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } { retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } retval.weight /= targetSum; @@ -1598,18 +1628,22 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe { value_weight_t lobe = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childProductHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } { value_weight_t lobe = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childRestHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } retval.weight /= targetSum; @@ -1644,12 +1678,14 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe const auto childHash = getHashAs4UintsString(child, ir); sstr << R"===( value_weight_t factor = OrientedMaterial<)===" << childHash << R"===(>::evalAndWeight(_sample, inter); + bool factorHasWeight = OrientedMaterial<)===" << childHash << R"===(>::canGenerate(); )==="; } sstr << R"===( contrib.quotient *= factor.quotient(); - contrib.weight *= factor.weight(); + if (factorHasWeight) + contrib.weight *= factor.weight(); return contrib; } )==="; @@ -1683,26 +1719,32 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe { value_weight_t lobe = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } { value_weight_t lobe = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childBottomHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } { value_weight_t lobe = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); - // TODO check lobe can generate - const scalar_t target = lobe.choiceTarget(interaction); - targetSum += target; - retval.weight += lobe.weight() * target; + if (OrientedMaterial<)===" << childCoatedHash << R"===(>::canGenerate()) + { + const scalar_t target = lobe.choiceTarget(inter); + targetSum += target; + retval.weight += lobe.weight() * target; + } } retval.weight /= targetSum; @@ -2023,4 +2065,204 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::emission() } } +void CReferenceUnidirectionalPathTracing::getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ +)==="; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + sstr << "bool brdf = OrientedMaterial<" << childBrdfHash << ">::canGenerate();\n"; + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + sstr << "bool btdf = OrientedMaterial<" << childBtdfHash << ">::canGenerate();\n"; + } + + sstr << R"===( + return brdf || btdf; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ +)==="; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + sstr << "bool product = OrientedMaterial<" << childProductHash << ">::canGenerate();\n"; + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + const auto childRestHash = getHashAs4UintsString(childRest, ir); + sstr << "bool rest = OrientedMaterial<" << childRestHash << ">::canGenerate();\n"; + } + + sstr << R"===( + return product || rest; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "bool child" << static_cast(i) << " = OrientedMaterial<" << childHash << ">::canGenerate();\n"; + } + } + + sstr << "bool retval = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "child" << static_cast(i) << (i < childCount - 1 ? " || " : ""); + sstr << R"===(; + return retval; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ +)==="; + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + const auto childContribHash = getHashAs4UintsString(childContrib, ir); + sstr << "bool contributor = OrientedMaterial<" << childContribHash << ">::canGenerate();\n"; + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + const auto childFactorHash = getHashAs4UintsString(childFactor, ir); + sstr << "bool factor = OrientedMaterial<" << childFactorHash << ">::canGenerate();\n"; + } + + sstr << R"===( + return contributor || factor; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ +)==="; + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "bool btdf = OrientedMaterial<" << childHash << ">::canGenerate();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "bool brdf = OrientedMaterial<" << childHash << ">::canGenerate();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "bool coated = OrientedMaterial<" << childHash << ">::canGenerate();\n"; + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << "bool next = OrientedMaterial<" << childHash << ">::canGenerate();\n"; + } + + sstr << R"===( + return btdf || brdf || coated || next; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ + return true; +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + { + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() +{ + return false; +} +)==="; + } + } +} + } From a1ce6d05441c5ddc8862ab106b8db171f379c096 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 3 Jun 2026 17:02:19 +0700 Subject: [PATCH 20/26] choiceTarget function impls --- .../CReferenceUnidirectionalPathTracing.h | 1 + .../CReferenceUnidirectionalPathTracing.cpp | 204 ++++++++++++------ 2 files changed, 145 insertions(+), 60 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index 6357e8a79b..b9d0c83e44 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -38,6 +38,7 @@ class CReferenceUnidirectionalPathTracing final : public IBackend void getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getChoiceTargetHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 6cfb0e0db3..4d350e9fcc 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -145,6 +145,7 @@ struct OrientedMaterial<)===" << hashString << R"===(> static spectral_t emission(); static bool canGenerate(); + static scalar_t choiceTarget(NBL_CONST_REF_ARG(aniso_interaction_t) inter, uint8_t chosenLobe, NBL_REF_ARG(scalar_t) choiceSum); }; )==="; @@ -949,8 +950,6 @@ void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - pdf_t choiceRcpPdf = 1.f; - spectral_t lumaContrib = inter.getLuminosityContributionHint(); )==="; @@ -962,7 +961,8 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); sstr << R"===( - scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBrdfHash << R"===(>::albedo())); + scalar_t dummy; + scalar_t prob = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, dummy); if (u.x < prob) { cache.chosenLobe = 0; @@ -987,8 +987,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - pdf_t choiceRcpPdf = 1.f; - spectral_t lumaContrib = inter.getLuminosityContributionHint(); )==="; @@ -1000,7 +998,8 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO const auto childRestHash = getHashAs4UintsString(childRest, ir); sstr << R"===( - scalar_t prob = 1.0 / (1.0 + hlsl::dot(lumaContrib, OrientedMaterial<)===" << childRestHash << R"===(>::albedo()) / hlsl::dot(lumaContrib, OrientedMaterial<)===" << childProductHash << R"===(>::albedo())); + scalar_t dummy; + scalar_t prob = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, dummy); if (u.x < prob) { cache.chosenLobe = 0; @@ -1050,8 +1049,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - pdf_t choiceRcpPdf = 1.f; - spectral_t lumaContrib = inter.getLuminosityContributionHint(); )==="; @@ -1239,9 +1236,8 @@ void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostring static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint8_t chosenLobe = child.chosenLobe; - pdf_t choiceProb = 1.0; - pdf_t choiceSum = 1.0; - + scalar_t choiceSum; + scalar_t choiceProb = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, chosenLobe, choiceSum); )==="; // TODO also get choice prob from cache @@ -1270,14 +1266,14 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie other = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); rest.value = other.value(); if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) - rest.weight = other.weight(); + rest.weight = other.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, choiceSum); } else { other = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); rest.value = other.value(); if (OrientedMaterial<)===" << childBrdfHash << R"===(>::canGenerate()) - rest.weight = other.weight(); + rest.weight = other.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, choiceSum); } )===" << combineRestWithRetValCode; break; @@ -1294,8 +1290,8 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint8_t chosenLobe = cache.chosenLobe; - pdf_t choiceProb = 1.0; - pdf_t choiceSum = 1.0; + scalar_t choiceSum; + scalar_t choiceProb = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, chosenLobe, choiceSum); )==="; const auto childProduct = ir->getObjectPool().deref(sum->product); @@ -1323,14 +1319,14 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie other = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); rest.value = other.value(); if (OrientedMaterial<)===" << childRestHash << R"===(>::canGenerate()) - rest.weight = other.weight(); + rest.weight = other.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, choiceSum); } else { other = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); rest.value = other.value(); if (OrientedMaterial<)===" << childProductHash << R"===(>::canGenerate()) - rest.weight = other.weight(); + rest.weight = other.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, choiceSum); } )===" << combineRestWithRetValCode; break; @@ -1385,8 +1381,8 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { uint8_t chosenLobe = cache.chosenLobe; - pdf_t choiceProb = 1.0; - pdf_t choiceSum = 1.0; + scalar_t choiceSum; + scalar_t choiceProb = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, chosenLobe, choiceSum); )==="; const auto childBtdf = ir->getObjectPool().deref(transmission->btdf); @@ -1417,21 +1413,21 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie value_weight_t child = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) - rest.weight += child.weight(); + rest.weight += child.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, choiceSum); } if (chosenLobe != 1) { value_weight_t child = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); if (OrientedMaterial<)===" << childBottomHash << R"===(>::canGenerate()) - rest.weight += child.weight(); + rest.weight += child.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, choiceSum); } if (chosenLobe != 2) { value_weight_t child = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); rest.value += child.value(); if (OrientedMaterial<)===" << childCoatedHash << R"===(>::canGenerate()) - rest.weight += child.weight(); + rest.weight += child.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 2, choiceSum); } )===" << combineRestWithRetValCode; // TODO: next node? @@ -1575,26 +1571,18 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe sstr << R"===( value_weight_t retval = value_weight_t::create(0.0,0.0); - pdf_t targetSum = 0.0; + scalar_t targetSum; { value_weight_t lobe = OrientedMaterial<)===" << childBrdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childBrdfHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, targetSum); } { retval = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, targetSum); } retval.weight /= targetSum; @@ -1624,26 +1612,18 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe sstr << R"===( value_weight_t retval = value_weight_t::create(0.0,0.0); - pdf_t targetSum = 0.0; + scalar_t targetSum; { value_weight_t lobe = OrientedMaterial<)===" << childProductHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childProductHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, targetSum); } { value_weight_t lobe = OrientedMaterial<)===" << childRestHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childRestHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, targetSum); } retval.weight /= targetSum; @@ -1715,36 +1695,24 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe sstr << R"===( value_weight_t retval = value_weight_t::create(0.0,0.0); - pdf_t targetSum = 0.0; + scalar_t targetSum; { value_weight_t lobe = OrientedMaterial<)===" << childBtdfHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childBtdfHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 0, targetSum); } { value_weight_t lobe = OrientedMaterial<)===" << childBottomHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childBottomHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 1, targetSum); } { value_weight_t lobe = OrientedMaterial<)===" << childCoatedHash << R"===(>::evalAndWeight(_sample, inter); retval.value += lobe.value(); if (OrientedMaterial<)===" << childCoatedHash << R"===(>::canGenerate()) - { - const scalar_t target = lobe.choiceTarget(inter); - targetSum += target; - retval.weight += lobe.weight() * target; - } + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, 2, targetSum); } retval.weight /= targetSum; @@ -2265,4 +2233,120 @@ static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() } } +void CReferenceUnidirectionalPathTracing::getChoiceTargetHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +{ + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NBL_CONST_REF_ARG(aniso_interaction_t) inter, uint8_t chosenLobe, NBL_REF_ARG(scalar_t) choiceSum) +{ + spectral_t lumaContrib = inter.getLuminosityContributionHint(); +)==="; + + const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); + const auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); + // TODO: what if either node (or both) not available? + + const auto childBrdfHash = getHashAs4UintsString(childBrdf, ir); + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + + sstr << R"===( + scalar_t weightBrdf = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBrdfHash << R"===(>::albedo()); + scalar_t weightBtdf = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()); + choiceSum = weightBrdf + weightBtdf; + if (chosenLobe == 0) + return 1.0 / (1.0 + weightBtdf / weightBrdf); + else + return 1.0 / (1.0 + weightBrdf / weightBtdf); +)==="; + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NBL_CONST_REF_ARG(aniso_interaction_t) inter, uint8_t chosenLobe, NBL_REF_ARG(scalar_t) choiceSum) +{ + spectral_t lumaContrib = inter.getLuminosityContributionHint(); +)==="; + + const auto childProduct = ir->getObjectPool().deref(sum->product); + const auto childRest = ir->getObjectPool().deref(sum->rest); + // TODO: what if either node (or both) not available? + + const auto childProductHash = getHashAs4UintsString(childProduct, ir); + const auto childRestHash = getHashAs4UintsString(childRest, ir); + + sstr << R"===( + scalar_t weightProduct = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childProductHash << R"===(>::albedo()); + scalar_t weightRest = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childRestHash << R"===(>::albedo()); + choiceSum = weightProduct + weightRest; + if (chosenLobe == 0) + return 1.0 / (1.0 + weightRest / weightProduct); + else + return 1.0 / (1.0 + weightProduct / weightRest); +)==="; + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NBL_CONST_REF_ARG(aniso_interaction_t) inter, uint8_t chosenLobe, NBL_REF_ARG(scalar_t) choiceSum) +{ + spectral_t lumaContrib = inter.getLuminosityContributionHint(); +)==="; + + const auto childBtdf = ir->getObjectPool().deref(transmission->btdf); + const auto childBottom = ir->getObjectPool().deref(transmission->brdfBottom); + const auto childCoated = ir->getObjectPool().deref(transmission->coated); + // TODO: what if some nodes not available? + + const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); + const auto childBottomHash = getHashAs4UintsString(childBottom, ir); + const auto childCoatedHash = getHashAs4UintsString(childCoated, ir); + + sstr << R"===( + scalar_t weightBtdf = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBtdfHash << R"===(>::albedo()); + scalar_t weightBottom = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childBottomHash << R"===(>::albedo()); + scalar_t weightCoated = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childCoatedHash << R"===(>::albedo()); + choiceSum = weightBtdf + weightBottom + weightCoated; + if (chosenLobe == 0) + return 1.0 / (1.0 + (weightCoated + weightBottom) / weightBtdf); + else if (chosenLobe == 1) + return 1.0 / (1.0 + (weightCoated + weightBtdf) / weightBottom); + else + return 1.0 / (1.0 + (weightBtdf + weightBottom) / weightCoated); +)==="; + // TODO: next node? + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + [[fallthrough]] + default: + break; + } +} + } From c21d469d262a7617ac4b7ac0844a318c532f5ce9 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 4 Jun 2026 11:19:52 +0700 Subject: [PATCH 21/26] some bug fixes + removed resolved todos --- .../CReferenceUnidirectionalPathTracing.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 4d350e9fcc..bf0380ab8a 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -12,7 +12,6 @@ core::smart_refctd_ptr CReferenceU auto res = core::make_smart_refctd_ptr(); // TODO: handle textures somehow - // TODO: templated structs for types in certain functions, e.g. cache (generate + quotient) // TODO: where do all the type aliases come from? e.g. sample_t, vector3_t, etc. std::ostringstream code; @@ -73,6 +72,8 @@ struct OrientedMaterial; getEvalWeightHLSLCode(code, node, ir); getQuotientWeightHLSLCode(code, node, ir); getEmissionHLSLCode(code, node, ir); + getCanGenerateHLSLCode(code, node, ir); + getChoiceTargetHLSLCode(code, node, ir); } }; @@ -974,7 +975,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO return OrientedMaterial<)===" << childBtdfHash << R"===(>::generate(inter, xi, xi_extra, cache.child1); } )==="; - // TODO: probability of lobe also goes into cache break; } case CTrueIR::INode::EFinalType::CContributorSum: @@ -1083,7 +1083,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO return OrientedMaterial<)===" << childCoatedHash << R"===(>::generate(inter, xi, xi_extra, cache.child2); } )==="; - // TODO: chosenLobe goes into cache to use in quotient // TODO: next node? break; } @@ -1168,7 +1167,6 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO return _sample; } )==="; - // TODO: what to do with child caches? break; } case CTrueIR::INode::EFinalType::CDeltaTransmission: @@ -1239,7 +1237,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie scalar_t choiceSum; scalar_t choiceProb = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, chosenLobe, choiceSum); )==="; - // TODO also get choice prob from cache const auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); const auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); @@ -1280,7 +1277,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } case CTrueIR::INode::EFinalType::CContributorSum: { - // TODO const auto* sum = dynamic_cast(node); if (!sum) break; @@ -1456,7 +1452,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie return quo; } )==="; - // TODO: what to do with child caches? break; } case CTrueIR::INode::EFinalType::CCookTorrance: @@ -1514,7 +1509,6 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie return quo; } )==="; - // TODO: what to do with child caches? break; } case CTrueIR::INode::EFinalType::CDeltaTransmission: @@ -1548,7 +1542,6 @@ void CReferenceUnidirectionalPathTracing::getEvalWeightHLSLCode(std::ostringstre { case CTrueIR::INode::EFinalType::COrientedLayer: { - // TODO const auto* layer = dynamic_cast(node); if (!layer) break; @@ -1567,7 +1560,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe const auto childBtdfHash = getHashAs4UintsString(childBtdf, ir); // TODO defensive sampler - // TODO check lobe can generate sstr << R"===( value_weight_t retval = value_weight_t::create(0.0,0.0); @@ -1592,7 +1584,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe } case CTrueIR::INode::EFinalType::CContributorSum: { - // TODO const auto* sum = dynamic_cast(node); if (!sum) break; @@ -1633,7 +1624,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe } case CTrueIR::INode::EFinalType::CWeightedContributor: { - // TODO const auto* contrib = dynamic_cast(node); if (!contrib) break; @@ -1650,7 +1640,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe sstr << R"===( value_weight_t contrib = OrientedMaterial<)===" << childHash << R"===(>::evalAndWeight(_sample, inter); )==="; - // TODO: what to do with child caches? } if (auto child = ir->getObjectPool().deref(contrib->factor); child) @@ -1673,7 +1662,6 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe } case CTrueIR::INode::EFinalType::CCorellatedTransmission: { - // TODO const auto* transmission = dynamic_cast(node); if (!transmission) break; From 7aa4e1cf0eeb3f9e2121bb9fb849be6a63c58c80 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 4 Jun 2026 15:26:48 +0700 Subject: [PATCH 22/26] common function for getting cook torrance bxdf, also handle anisotropic variant --- .../CReferenceUnidirectionalPathTracing.h | 2 + .../CReferenceUnidirectionalPathTracing.cpp | 169 +++++++----------- 2 files changed, 64 insertions(+), 107 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index b9d0c83e44..97bc5fc389 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -39,6 +39,8 @@ class CReferenceUnidirectionalPathTracing final : public IBackend void getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); void getChoiceTargetHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + + void getCookTorranceBxDFHLSLCode(const CTrueIR::CCookTorrance* cook_torrance, const CTrueIR* ir, std::string& bxdf_type, std::string& fresnel_create); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index bf0380ab8a..35452229d9 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -179,23 +179,11 @@ struct gen_cache<)===" << hashString << R"===(> case CTrueIR::INode::EFinalType::CCookTorrance: { const auto cook_torrance = dynamic_cast(node); + std::string bxdf_type; - if (cook_torrance->orientedRealEta) - { - // btdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; - else - bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; - } - else - { - // brdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::reflection::SGGXIsotropic"; - else - bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; - } + std::string fresnel_create; + getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); + sstr << R"===( template<> struct gen_cache<)===" << hashString << R"===(> @@ -1119,42 +1107,13 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO break; // TODO: config type alias from where - // TODO: handle anisotropic types const auto hashString = getHashAs4UintsString(node, ir); const auto roughness = cook_torrance->ndfParams.getRougness(); - + std::string bxdf_type; std::string fresnel_create; - if (cook_torrance->orientedRealEta) - { - // btdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; - else - bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; - - const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; - fresnel_create = R"===( - bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); - bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); -)==="; - } - else - { - // brdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::reflection::SGGXIsotropic"; - else - bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; - - const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); - const auto eta = etaNode->getParameter(0).scale; - const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored - fresnel_create = R"===( - bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); -)==="; - } + getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) @@ -1461,42 +1420,13 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie break; // TODO: config type alias from where - // TODO: handle anisotropic types const auto hashString = getHashAs4UintsString(node, ir); const auto roughness = cook_torrance->ndfParams.getRougness(); std::string bxdf_type; std::string fresnel_create; - if (cook_torrance->orientedRealEta) - { - // btdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; - else - bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; - - const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; - fresnel_create = R"===( - bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); - bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); -)==="; - } - else - { - // brdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::reflection::SGGXIsotropic"; - else - bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; - - const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); - const auto eta = etaNode->getParameter(0).scale; - const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored - fresnel_create = R"===( - bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); -)==="; - } + getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) @@ -1741,42 +1671,13 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe break; // TODO: config type alias from where - // TODO: handle anisotropic types const auto hashString = getHashAs4UintsString(node, ir); const auto roughness = cook_torrance->ndfParams.getRougness(); std::string bxdf_type; std::string fresnel_create; - if (cook_torrance->orientedRealEta) - { - // btdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; - else - bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; - - const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; - fresnel_create = R"===( - bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); - bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); -)==="; - } - else - { - // brdf - if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) - bxdf_type = "bxdf::reflection::SGGXIsotropic"; - else - bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; - - const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); - const auto eta = etaNode->getParameter(0).scale; - const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored - fresnel_create = R"===( - bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); -)==="; - } + getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); sstr << R"===( static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) @@ -2337,4 +2238,58 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NB } } +void CReferenceUnidirectionalPathTracing::getCookTorranceBxDFHLSLCode(const CTrueIR::CCookTorrance* cook_torrance, const CTrueIR* ir, + std::string& bxdf_type, std::string& fresnel_create) +{ + if (cook_torrance->orientedRealEta) + { + // btdf + if (cook_torrance->ndfParams.definitelyIsotropic()) + { + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricIsotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricIsotropic"; + } + else + { + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::transmission::SGGXDielectricAnisotropic"; + else + bxdf_type = "bxdf::transmission::SBeckmannDielectricAnisotropic"; + } + + const auto eta = ir->getObjectPool().deref(cook_torrance->orientedRealEta)->getParameter(0).scale; + fresnel_create = R"===( + bxdf::fresnel::OrientedEtas orientedEta = bxdf::fresnel::OrientedEtas::create(1.0, hlsl::promote()===" + std::to_string(eta) + R"===()); + bxdf.fresnel = cook_torrance_t::fresnel_type::create(orientedEta); +)==="; + } + else + { + // brdf + if (cook_torrance->ndfParams.definitelyIsotropic()) + { + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXIsotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannIsotropic"; + } + else + { + if (cook_torrance->ndfParams.getDistribution() == CTrueIR::SBasicNDFParams::EDistribution::GGX) + bxdf_type = "bxdf::reflection::SGGXAnisotropic"; + else + bxdf_type = "bxdf::reflection::SBeckmannAnisotropic"; + } + + const auto etaNode = ir->getObjectPool().deref(cook_torrance->orientedRealEta); + const auto eta = etaNode->getParameter(0).scale; + const auto etak = etaNode->getParameter(1).scale; // TODO: double check how eta is stored + fresnel_create = R"===( + bxdf.fresnel = cook_torrance_t::fresnel_type::create()===" + std::to_string(eta) + ", " + std::to_string(etak) + R"===(); +)==="; + } +} + } From 16d53c2d5782b7b14fddc0fe41cdc77298ed12b4 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 5 Jun 2026 14:53:22 +0700 Subject: [PATCH 23/26] added missing factorcombiner cases for quotient, eval, generate and choiceTarget --- .../CReferenceUnidirectionalPathTracing.cpp | 211 +++++++++++++++++- 1 file changed, 207 insertions(+), 4 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 35452229d9..2e292fbeb1 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -26,6 +26,7 @@ struct OrientedMaterial; // loop through layers in IR and construct materials map? maybe just node map is fine core::vector> nodeStack; core::unordered_set> visitedNodes; + core::unordered_map, TraversalNodeInfo> nodeInfos; auto compileBSDFRootNode = [&](CTrueIR::typed_pointer_type rootHandle) -> void { nodeStack.clear(); visitedNodes.clear(); @@ -324,8 +325,9 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() } sstr << "spectral_t retval = "; + const std::string op = (combiner->getState().type == CTrueIR::CFactorCombiner::Type::Mul) ? " * " : " + "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? - sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << "child" << static_cast(i) << (i < childCount - 1 ? op : ""); sstr << R"===(; return retval; } @@ -579,8 +581,9 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput } sstr << "spectral_t retval = "; + const std::string op = (combiner->getState().type == CTrueIR::CFactorCombiner::Type::Mul) ? " * " : " + "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? - sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << "child" << static_cast(i) << (i < childCount - 1 ? op : ""); sstr << R"===(; return retval; } @@ -795,8 +798,9 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() } sstr << "scalar_t retval = "; + const std::string op = (combiner->getState().type == CTrueIR::CFactorCombiner::Type::Mul) ? " * " : " + "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? - sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << "child" << static_cast(i) << (i < childCount - 1 ? op : ""); sstr << R"===(; return retval; } @@ -998,6 +1002,51 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO cache.chosenLobe = 1; return OrientedMaterial<)===" << childRestHash << R"===(>::generate(inter, xi, xi_extra, cache.child1); } +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) +{ +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + if (i < childCount - 1) + sstr << R"===( + { + scalar_t dummy; + scalar_t prob = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, )===" << static_cast(i) << R"===(, dummy); + if (u.x < prob) + { + cache.chosenLobe = )===" << static_cast(i) << R"===(; + return OrientedMaterial<)===" << childHash << R"===(>::generate(inter, xi, xi_extra, cache.child)===" << static_cast(i) << R"===(); + } + } +)==="; + else + sstr << R"===( + { + cache.chosenLobe = )===" << static_cast(i) << R"===(; + return OrientedMaterial<)===" << childHash << R"===(>::generate(inter, xi, xi_extra, cache.child)===" << static_cast(i) << R"===(); + } +)==="; + } + } + sstr << R"===( +} )==="; break; } @@ -1286,6 +1335,69 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie )===" << combineRestWithRetValCode; break; } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) +{ + uint8_t chosenLobe = cache.chosenLobe; + scalar_t choiceSum; + scalar_t choiceProb = OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, chosenLobe, choiceSum); + + quotient_weight_t retval; +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + if (i < childCount - 1) + sstr << R"===( + if (chosenLobe == )===" << static_cast(i) << R"===( + retval = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, cache.child)===" << static_cast(i) << R"===(); +)==="; + else + sstr << R"===( + else + retval = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, cache.child)===" << static_cast(i) << R"===(); +)==="; + } + } + + sstr << R"===( + if (retval.weight() < bit_cast(numeric_limits::infinity)) + { + const scalar_t chosenPdf = retval.weight() * choiceProb; + value_weight_t rest = value_weight_t::create(0.0,0.0); +)==="; + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + if (chosenLobe != )===" << static_cast(i) << R"===( + { + value_weight_t child = OrientedMaterial<)===" << childHash << R"===(>::quotientAndWeight(_sample, inter, cache.child)===" << static_cast(i) << R"===(); + if (OrientedMaterial<)===" << childHash << R"===(>::canGenerate()) + rest.weight += child.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, )===" << static_cast(i) << R"===(, choiceSum); + } +)==="; + } + } + + sstr << combineRestWithRetValCode; + break; + } case CTrueIR::INode::EFinalType::CWeightedContributor: { const auto* contrib = dynamic_cast(node); @@ -1549,6 +1661,44 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe retval.weight /= targetSum; return retval; +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) +{ + value_weight_t retval = value_weight_t::create(0.0,0.0); + scalar_t targetSum; +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + { + value_weight_t lobe = OrientedMaterial<)===" << childHash << R"===(>::evalAndWeight(_sample, inter); + retval.value += lobe.value(); + if (OrientedMaterial<)===" << childHash << R"===(>::canGenerate()) + retval.weight += lobe.weight() * OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(inter, )===" << static_cast(i) << R"===(, targetSum); + } +)==="; + } + } + + sstr << R"===( + retval.weight /= targetSum; + return retval; )==="; break; } @@ -1803,8 +1953,9 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::emission() } sstr << "spectral_t retval = "; + const std::string op = (combiner->getState().type == CTrueIR::CFactorCombiner::Type::Mul) ? " * " : " + "; for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? - sstr << "child" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + sstr << "child" << static_cast(i) << (i < childCount - 1 ? op : ""); sstr << R"===(; return retval; } @@ -2154,6 +2305,7 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NB return 1.0 / (1.0 + weightBtdf / weightBrdf); else return 1.0 / (1.0 + weightBrdf / weightBtdf); +} )==="; break; } @@ -2185,6 +2337,56 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NB return 1.0 / (1.0 + weightRest / weightProduct); else return 1.0 / (1.0 + weightProduct / weightRest); +} +)==="; + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto hashString = getHashAs4UintsString(node, ir); + sstr << R"===( +static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NBL_CONST_REF_ARG(aniso_interaction_t) inter, uint8_t chosenLobe, NBL_REF_ARG(scalar_t) choiceSum) +{ + spectral_t lumaContrib = inter.getLuminosityContributionHint(); +)==="; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + const auto childHash = getHashAs4UintsString(child, ir); + sstr << R"===( + scalar_t weightChild)===" << static_cast(i) << R"===( = hlsl::dot(lumaContrib, OrientedMaterial<)===" << childHash << R"===(>::albedo()); +)==="; + } + } + + sstr << "choiceSum = "; + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + sstr << "weightChild" << static_cast(i) << (i < childCount - 1 ? " + " : ""); + + for (uint8_t i = 0; i < childCount; i++) // TODO: check for invalid children? + { + if (i < childCount - 1) + sstr << R"===( + if (chosenLobe == )===" << static_cast(i) << R"===() + return weightChild)===" << static_cast(i) << R"===( / choiceSum; +)==="; + else + sstr << R"===( + else + return weightChild)===" << static_cast(i) << R"===( / choiceSum; +)==="; + } + + sstr << R"===( +} )==="; break; } @@ -2221,6 +2423,7 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NB return 1.0 / (1.0 + (weightCoated + weightBtdf) / weightBottom); else return 1.0 / (1.0 + (weightBtdf + weightBottom) / weightCoated); +} )==="; // TODO: next node? break; From eba148fbb7f5df8d0e3fca9f9c60b8ec817335bd Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 5 Jun 2026 17:07:29 +0700 Subject: [PATCH 24/26] changed to map nodes and use traversal node struct --- .../CReferenceUnidirectionalPathTracing.h | 34 ++- .../CReferenceUnidirectionalPathTracing.cpp | 264 ++++++++++++++---- 2 files changed, 238 insertions(+), 60 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index 97bc5fc389..c30216083d 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -22,23 +22,31 @@ class CReferenceUnidirectionalPathTracing final : public IBackend core::smart_refctd_ptr compile(const CTrueIR* ir, const std::span materials); private: + struct TraversalNodeInfo + { + const CTrueIR::INode* node; + bool isTransmission; + }; + + void traverseIRNode(const CTrueIR::INode* node, const CTrueIR* ir, core::vector>& nodeStack, core::unordered_map, TraversalNodeInfo>& nodeInfos); + std::string getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator = ",") const; bool isNodeTypeContributor(CTrueIR::INode::EFinalType type) const; void getMaterialDeclarationCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getCacheDefineCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - - void getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getAOVThroughputHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - - void getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); - void getChoiceTargetHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir); + void getCacheDefineCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + + void getAlbedoHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getNormalHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getAOVThroughputHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getTransparencyHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getGenerateHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getQuotientWeightHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getEvalWeightHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getEmissionHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + + void getCanGenerateHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); + void getChoiceTargetHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); void getCookTorranceBxDFHLSLCode(const CTrueIR::CCookTorrance* cook_torrance, const CTrueIR* ir, std::string& bxdf_type, std::string& fresnel_create); }; diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 2e292fbeb1..aff986347f 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -25,11 +25,11 @@ struct OrientedMaterial; // loop through layers in IR and construct materials map? maybe just node map is fine core::vector> nodeStack; - core::unordered_set> visitedNodes; + //core::unordered_set> visitedNodes; core::unordered_map, TraversalNodeInfo> nodeInfos; auto compileBSDFRootNode = [&](CTrueIR::typed_pointer_type rootHandle) -> void { nodeStack.clear(); - visitedNodes.clear(); + nodeInfos.clear(); nodeStack.push_back(rootHandle); const auto& pool = ir->getObjectPool(); @@ -44,37 +44,22 @@ struct OrientedMaterial; continue; getMaterialDeclarationCode(code, node, ir); - - const auto childCount = node->getChildCount(); - if (childCount) - { - for (auto childIx = 0; childIx < childCount; childIx++) - { - const auto childHandle = node->getChildHandle(childIx); - if (const auto child = pool.deref(childHandle); child) - { - const auto [unused, inserted] = visitedNodes.insert(childHandle); - if (inserted) - nodeStack.push_back(childHandle); - } - } - } + traverseIRNode(node, ir, nodeStack, nodeInfos); } - for (const auto& nodeHandle : visitedNodes) + for (const auto& nodeInfo : std::views::values(nodeInfos)) { - const auto* node = pool.deref(nodeHandle); - getCacheDefineCode(code, node, ir); - getAlbedoHLSLCode(code, node, ir); - getNormalHLSLCode(code, node, ir); - getAOVThroughputHLSLCode(code, node, ir); - getTransparencyHLSLCode(code, node, ir); - getGenerateHLSLCode(code, node, ir); - getEvalWeightHLSLCode(code, node, ir); - getQuotientWeightHLSLCode(code, node, ir); - getEmissionHLSLCode(code, node, ir); - getCanGenerateHLSLCode(code, node, ir); - getChoiceTargetHLSLCode(code, node, ir); + getCacheDefineCode(code, nodeInfo, ir); + getAlbedoHLSLCode(code, nodeInfo, ir); + getNormalHLSLCode(code, nodeInfo, ir); + getAOVThroughputHLSLCode(code, nodeInfo, ir); + getTransparencyHLSLCode(code, nodeInfo, ir); + getGenerateHLSLCode(code, nodeInfo, ir); + getEvalWeightHLSLCode(code, nodeInfo, ir); + getQuotientWeightHLSLCode(code, nodeInfo, ir); + getEmissionHLSLCode(code, nodeInfo, ir); + getCanGenerateHLSLCode(code, nodeInfo, ir); + getChoiceTargetHLSLCode(code, nodeInfo, ir); } }; @@ -100,6 +85,173 @@ struct OrientedMaterial; return res; } +void CReferenceUnidirectionalPathTracing::traverseIRNode(const CTrueIR::INode* node, const CTrueIR* ir, + core::vector>& nodeStack, + core::unordered_map, TraversalNodeInfo>& nodeInfos) +{ + auto addChildToTraverse = [&](CTrueIR::typed_pointer_type handle, const TraversalNodeInfo& info) -> void { + const auto [unused, inserted] = nodeInfos.insert({ handle, info }); + if (inserted) + nodeStack.push_back(handle); + }; + + switch (node->getFinalType()) + { + case CTrueIR::INode::EFinalType::COrientedLayer: + { + const auto* layer = dynamic_cast(node); + if (!layer) + break; + + if (auto childBrdf = ir->getObjectPool().deref(layer->brdfTop); childBrdf) + { + TraversalNodeInfo info = { + .node = childBrdf, + .isTransmission = false + }; + addChildToTraverse(layer->brdfTop, info); + } + if (auto childBtdf = ir->getObjectPool().deref(layer->firstTransmission); childBtdf) + { + TraversalNodeInfo info = { + .node = childBtdf, + .isTransmission = true + }; + addChildToTraverse(layer->firstTransmission, info); + } + break; + } + case CTrueIR::INode::EFinalType::CContributorSum: + { + const auto* sum = dynamic_cast(node); + if (!sum) + break; + + if (auto childProduct = ir->getObjectPool().deref(sum->product); childProduct) + { + TraversalNodeInfo info = { + .node = childProduct, + .isTransmission = false + }; + addChildToTraverse(sum->product, info); + } + if (auto childRest = ir->getObjectPool().deref(sum->rest); childRest) + { + TraversalNodeInfo info = { + .node = childRest, + .isTransmission = false + }; + addChildToTraverse(sum->rest, info); + } + break; + } + case CTrueIR::INode::EFinalType::CFactorCombiner: + { + const auto* combiner = dynamic_cast(node); + if (!combiner) + break; + + const auto childCount = combiner->getChildCount(); + + for (uint8_t i = 0; i < childCount; i++) + { + if (auto child = ir->getObjectPool().deref(combiner->getChildHandle(i)); child) + { + TraversalNodeInfo info = { + .node = child, + .isTransmission = false + }; + addChildToTraverse(combiner->getChildHandle(i), info); + } + } + break; + } + case CTrueIR::INode::EFinalType::CWeightedContributor: + { + const auto* contrib = dynamic_cast(node); + if (!contrib) + break; + + if (auto childContrib = ir->getObjectPool().deref(contrib->contributor); childContrib) + { + TraversalNodeInfo info = { + .node = childContrib, + .isTransmission = false + }; + addChildToTraverse(contrib->contributor, info); + } + if (auto childFactor = ir->getObjectPool().deref(contrib->factor); childFactor) + { + TraversalNodeInfo info = { + .node = childFactor, + .isTransmission = false + }; + addChildToTraverse(contrib->factor, info); + } + break; + } + case CTrueIR::INode::EFinalType::CCorellatedTransmission: + { + const auto* transmission = dynamic_cast(node); + if (!transmission) + break; + + if (auto child = ir->getObjectPool().deref(transmission->btdf); child) + { + TraversalNodeInfo info = { + .node = child, + .isTransmission = true + }; + addChildToTraverse(transmission->btdf, info); + } + if (auto child = ir->getObjectPool().deref(transmission->brdfBottom); child) + { + TraversalNodeInfo info = { + .node = child, + .isTransmission = false + }; + addChildToTraverse(transmission->brdfBottom, info); + } + if (auto child = ir->getObjectPool().deref(transmission->coated); child) + { + TraversalNodeInfo info = { + .node = child, + .isTransmission = true // TODO: double check this + }; + addChildToTraverse(transmission->coated, info); + } + if (auto child = ir->getObjectPool().deref(transmission->next); child) + { + TraversalNodeInfo info = { + .node = child, + .isTransmission = false + }; + addChildToTraverse(transmission->next, info); + } + break; + } + // these ones don't have children/have children that needs to traverse + case CTrueIR::INode::EFinalType::CSpectralVariable: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CEmitter: + [[fallthrough]] + case CTrueIR::INode::EFinalType::COrenNayar: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CCookTorrance: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CDeltaTransmission: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CBeer: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CFresnel: + [[fallthrough]] + case CTrueIR::INode::EFinalType::CThinInfiniteScatterCorrection: + [[fallthrough]] + default: + break; + } +} + std::string CReferenceUnidirectionalPathTracing::getHashAs4UintsString(const CTrueIR::INode* node, const CTrueIR* ir, const std::string& separator) const { // break up hash into 8 pieces of uint32_t @@ -153,8 +305,9 @@ struct OrientedMaterial<)===" << hashString << R"===(> } -void CReferenceUnidirectionalPathTracing::getCacheDefineCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getCacheDefineCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; const auto hashString = getHashAs4UintsString(node, ir); const auto nodeType = node->getFinalType(); @@ -239,8 +392,9 @@ struct gen_cache<)===" << hashString << R"===(> } } -void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getAlbedoHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -452,8 +606,9 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::albedo() } } -void CReferenceUnidirectionalPathTracing::getNormalHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getNormalHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -495,8 +650,9 @@ static spectral_t OrientedMaterial<)===" << hashString << R"===(>::normal(NBL_CO } } -void CReferenceUnidirectionalPathTracing::getAOVThroughputHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getAOVThroughputHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -712,8 +868,9 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::aovThroughput() } } -void CReferenceUnidirectionalPathTracing::getTransparencyHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getTransparencyHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -929,8 +1086,9 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::transparency() } } -void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getGenerateHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -1130,14 +1288,16 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO break; // TODO: config type alias from where (also allow aniso) - // TODO: also might be btdf + std::string bxdf_type = "bxdf::reflection::SOrenNayar"; + if (nodeInfo.isTransmission) + bxdf_type = "bxdf::transmission::SOrenNayar"; const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - using oren_nayar_t = bxdf::reflection::SOrenNayar; + using oren_nayar_t = )===" << bxdf_type << R"===(; using creation_t = typename oren_nayar_t::creation_type; creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; @@ -1202,7 +1362,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO } } -void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { const std::string combineRestWithRetValCode = R"===( retval.weight += rest.weight(); @@ -1228,6 +1388,7 @@ void CReferenceUnidirectionalPathTracing::getQuotientWeightHLSLCode(std::ostring return retval; )==="; + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -1507,14 +1668,16 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie break; // TODO: config type alias from where (also allow aniso) - // TODO: also might be btdf + std::string bxdf_type = "bxdf::reflection::SOrenNayar"; + if (nodeInfo.isTransmission) + bxdf_type = "bxdf::transmission::SOrenNayar"; const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) { - using oren_nayar_t = bxdf::reflection::SOrenNayar; + using oren_nayar_t = )===" << bxdf_type << R"===(; using creation_t = typename oren_nayar_t::creation_type; creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; @@ -1578,8 +1741,9 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie } } -void CReferenceUnidirectionalPathTracing::getEvalWeightHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getEvalWeightHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -1796,14 +1960,17 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe break; // TODO: config type alias from where (also allow aniso) - // TODO: also might be btdf + + std::string bxdf_type = "bxdf::reflection::SOrenNayar"; + if (nodeInfo.isTransmission) + bxdf_type = "bxdf::transmission::SOrenNayar"; const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); sstr << R"===( static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) { - using oren_nayar_t = bxdf::reflection::SOrenNayar; + using oren_nayar_t = )===" << bxdf_type << R"===(; using creation_t = typename oren_nayar_t::creation_type; creation_t params; params.A = )===" << roughness.data()[0].scale << R"===(; @@ -1867,8 +2034,9 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe } } -void CReferenceUnidirectionalPathTracing::getEmissionHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getEmissionHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -2073,8 +2241,9 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::emission() } } -void CReferenceUnidirectionalPathTracing::getCanGenerateHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getCanGenerateHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: @@ -2273,8 +2442,9 @@ static bool OrientedMaterial<)===" << hashString << R"===(>::canGenerate() } } -void CReferenceUnidirectionalPathTracing::getChoiceTargetHLSLCode(std::ostringstream& sstr, const CTrueIR::INode* node, const CTrueIR* ir) +void CReferenceUnidirectionalPathTracing::getChoiceTargetHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir) { + const auto* node = nodeInfo.node; switch (node->getFinalType()) { case CTrueIR::INode::EFinalType::COrientedLayer: From 30a7711c54e89b9dc56bb8f88964a4dcc3ec6333 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 8 Jun 2026 12:06:59 +0700 Subject: [PATCH 25/26] oren nayar anisotropic config and put into common function --- .../CReferenceUnidirectionalPathTracing.h | 3 +- .../CReferenceUnidirectionalPathTracing.cpp | 50 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h index c30216083d..4f8ebdcc42 100644 --- a/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h +++ b/include/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.h @@ -48,7 +48,8 @@ class CReferenceUnidirectionalPathTracing final : public IBackend void getCanGenerateHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); void getChoiceTargetHLSLCode(std::ostringstream& sstr, const TraversalNodeInfo& nodeInfo, const CTrueIR* ir); - void getCookTorranceBxDFHLSLCode(const CTrueIR::CCookTorrance* cook_torrance, const CTrueIR* ir, std::string& bxdf_type, std::string& fresnel_create); + void getOrenNayarBxDFHLSLCode(const TraversalNodeInfo& nodeInfo, const CTrueIR* ir, std::string& bxdf_type); + void getCookTorranceBxDFHLSLCode(const TraversalNodeInfo& nodeInfo, const CTrueIR* ir, std::string& bxdf_type, std::string& fresnel_create); }; } diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index aff986347f..386d92ea86 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -1287,10 +1287,9 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO if (!oren_nayar) break; - // TODO: config type alias from where (also allow aniso) - std::string bxdf_type = "bxdf::reflection::SOrenNayar"; - if (nodeInfo.isTransmission) - bxdf_type = "bxdf::transmission::SOrenNayar"; + // TODO: config type alias from where + std::string bxdf_type; + getOrenNayarBxDFHLSLCode(nodeInfo, ir, bxdf_type); const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); @@ -1322,7 +1321,7 @@ static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CO std::string bxdf_type; std::string fresnel_create; - getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); + getCookTorranceBxDFHLSLCode(nodeInfo, ir, bxdf_type, fresnel_create); sstr << R"===( static sample_t OrientedMaterial<)===" << hashString << R"===(>::generate(NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(rand_t) xi, NBL_REF_ARG(rand_t) xi_extra, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) @@ -1667,10 +1666,9 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie if (!oren_nayar) break; - // TODO: config type alias from where (also allow aniso) - std::string bxdf_type = "bxdf::reflection::SOrenNayar"; - if (nodeInfo.isTransmission) - bxdf_type = "bxdf::transmission::SOrenNayar"; + // TODO: config type alias from where + std::string bxdf_type; + getOrenNayarBxDFHLSLCode(nodeInfo, ir, bxdf_type); const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); @@ -1701,7 +1699,7 @@ static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotie std::string bxdf_type; std::string fresnel_create; - getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); + getCookTorranceBxDFHLSLCode(nodeInfo, ir, bxdf_type, fresnel_create); sstr << R"===( static quotient_weight_t OrientedMaterial<)===" << hashString << R"===(>::quotientAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter, NBL_REF_ARG(gen_cache<)===" << hashString << R"===(>) cache) @@ -1959,11 +1957,10 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe if (!oren_nayar) break; - // TODO: config type alias from where (also allow aniso) + // TODO: config type alias from where - std::string bxdf_type = "bxdf::reflection::SOrenNayar"; - if (nodeInfo.isTransmission) - bxdf_type = "bxdf::transmission::SOrenNayar"; + std::string bxdf_type; + getOrenNayarBxDFHLSLCode(nodeInfo, ir, bxdf_type); const auto hashString = getHashAs4UintsString(node, ir); auto roughness = oren_nayar->ndfParams.getRougness(); @@ -1994,7 +1991,7 @@ static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWe std::string bxdf_type; std::string fresnel_create; - getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); + getCookTorranceBxDFHLSLCode(nodeInfo, ir, bxdf_type, fresnel_create); sstr << R"===( static value_weight_t OrientedMaterial<)===" << hashString << R"===(>::evalAndWeight(NBL_CONST_REF_ARG(sample_t) _sample, NBL_CONST_REF_ARG(aniso_interaction_t) inter) @@ -2611,11 +2608,28 @@ static scalar_t OrientedMaterial<)===" << hashString << R"===(>::choiceTarget(NB } } -void CReferenceUnidirectionalPathTracing::getCookTorranceBxDFHLSLCode(const CTrueIR::CCookTorrance* cook_torrance, const CTrueIR* ir, - std::string& bxdf_type, std::string& fresnel_create) +void CReferenceUnidirectionalPathTracing::getOrenNayarBxDFHLSLCode(const TraversalNodeInfo& nodeInfo, const CTrueIR* ir, std::string& bxdf_type) +{ + const auto* oren_nayar = dynamic_cast(nodeInfo.node); + + // config can be iso or aniso (doesn't really matter for oren nayar) + std::string config = "aniso_config_t"; + if (oren_nayar->ndfParams.definitelyIsotropic()) + config = "iso_config_t"; + + if (nodeInfo.isTransmission) + bxdf_type = "bxdf::transmission::SOrenNayar<" + config + ">"; + else + bxdf_type = "bxdf::reflection::SOrenNayar<" + config + ">"; +} + +void CReferenceUnidirectionalPathTracing::getCookTorranceBxDFHLSLCode(const TraversalNodeInfo& nodeInfo, const CTrueIR* ir, + std::string& bxdf_type, std::string& fresnel_create) { - if (cook_torrance->orientedRealEta) + const auto* cook_torrance = dynamic_cast(nodeInfo.node); + if (nodeInfo.isTransmission) { + assert(cook_torrance->orientedRealEta); // should exist/not be null // btdf if (cook_torrance->ndfParams.definitelyIsotropic()) { From babff91c65f8a90121c6b6d7558e4bd92d3f0dd9 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 8 Jun 2026 14:32:51 +0700 Subject: [PATCH 26/26] minor bug fixes for oren nayar --- .../CReferenceUnidirectionalPathTracing.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp index 386d92ea86..77fe869160 100644 --- a/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp +++ b/src/nbl/asset/material_compiler3/CReferenceUnidirectionalPathTracing.cpp @@ -318,13 +318,15 @@ void CReferenceUnidirectionalPathTracing::getCacheDefineCode(std::ostringstream& case CTrueIR::INode::EFinalType::COrenNayar: { // should be leaf here, so not going to try children - // TODO: config type alias from where (also allow aniso) - // TODO: also might be btdf + // TODO: config type alias from where + std::string bxdf_type; + getOrenNayarBxDFHLSLCode(nodeInfo, ir, bxdf_type); + sstr << R"===( template<> struct gen_cache<)===" << hashString << R"===(> { - using bxdf_t = bxdf::reflection::SOrenNayar; + using bxdf_t = )===" << bxdf_type << R"===(; typename bxdf_t::anisocache_type bxdf_cache; }; )==="; @@ -332,11 +334,9 @@ struct gen_cache<)===" << hashString << R"===(> } case CTrueIR::INode::EFinalType::CCookTorrance: { - const auto cook_torrance = dynamic_cast(node); - std::string bxdf_type; std::string fresnel_create; - getCookTorranceBxDFHLSLCode(cook_torrance, ir, bxdf_type, fresnel_create); + getCookTorranceBxDFHLSLCode(nodeInfo, ir, bxdf_type, fresnel_create); sstr << R"===( template<>