Skip to content

Resampled Importance Sampling bxdfs#1027

Open
devshgraphicsprogramming wants to merge 50 commits intosampler-conceptsfrom
ris_bxdfs
Open

Resampled Importance Sampling bxdfs#1027
devshgraphicsprogramming wants to merge 50 commits intosampler-conceptsfrom
ris_bxdfs

Conversation

@devshgraphicsprogramming
Copy link
Member

Description

Testing

TODO list:

kevyuu and others added 24 commits March 14, 2026 10:44
…ession reciprocation (swapping of interface order)

Unfortunately I realized our THINDIELECTRIC correction is badly designed
Point Boost to the exact Wave one-line backport for emitted pragma newlines, remove the temporary local pragma workaround, and keep the remaining include-path fixes in Nabla.

This leaves the Wave pragma issue fixed at the dependency level while preserving the Nabla-side fixes for Windows backslash includes and single-leading-slash virtual includes.

Thanks to @Themperror for the additional pragma and include repros. Those made it straightforward to verify the dependency-level fix and drop the local workaround cleanly.
…dates

Fix remaining preprocess bugs and backport Wave pragma fix
…te-nsc-windows-x64-release-master

CI: Promote NSC channel to 66da590
@devshgraphicsprogramming devshgraphicsprogramming changed the title Ris bxdfs Resampled Importance Sampling bxdfs Mar 20, 2026
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.eval_and_weight(_sample, aniso, anisocache)), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.pdf(_sample, aniso, anisocache)), ::nbl::hlsl::is_same_v, typename T::scalar_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.quotient_and_pdf(_sample, aniso, anisocache)), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.quotient_and_weight(_sample, aniso, anisocache)), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets make all BxDFs have a cache type which goes from generate to quotient_and_weight but then microfacet_bxdf_common would be the weird one that puts a further constraint that the anisocache_type needs to fit some concept for Cook Torrance to be useful

and allow a 2nd cache type just for eval_and_weight (the two can obviously be identical in practice, e.g. our base impl for now)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could actually get rid of microfacex_bdf_common and the iso_microfacet concept (basically the entire block in namespace impl ehere)

and just check that {Isotropic}MicrofacetB{R|S}DF = {Isotropic}B{R|S}DF<T> && (Isotropic ? CreatableIsotropicMicrofacetCache<typedef T::cache_type>:AnisotropicMicrofacetCache<typedef T::cache_type>);

Comment on lines +155 to +205
if (!system || outputPath.empty())
return false;

const auto parent = outputPath.parent_path();
if (!parent.empty() && !system->isDirectory(parent))
{
if (!system->createDirectory(parent))
return false;
}

auto tempPath = outputPath;
tempPath += ".tmp";
system->deleteFile(tempPath);

smart_refctd_ptr<IFile> outputFile;
{
ISystem::future_t<smart_refctd_ptr<IFile>> future;
system->createFile(future, tempPath, IFileBase::ECF_WRITE);
if (!future.wait())
return false;

auto lock = future.acquire();
if (!lock)
return false;
lock.move_into(outputFile);
}
if (!outputFile)
return false;

if (!content.empty())
{
IFile::success_t success;
outputFile->write(success, content.data(), 0ull, content.size());
if (!success)
{
outputFile = nullptr;
system->deleteFile(tempPath);
return false;
}
}
outputFile = nullptr;

system->deleteFile(outputPath);
const auto moveError = system->moveFileOrDirectory(tempPath, outputPath);
if (moveError)
{
system->deleteFile(tempPath);
return false;
}

return true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AnastaZIuk do you think you could add an option to createFile flags (or pack the path+ IFileBase flaggs into a strcut) to create all the directories needed on the way to the path ?

cold be useful

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ay

struct Cache {};
using isocache_type = Cache;
using anisocache_type = Cache;
using evalcache_type = Cache;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be no evalcache_type, its still same cache as for quotient and generate

But having an evalAndWeight with an overload that takes it should be a Cook Torrance / Microfacet thing only

((NBL_CONCEPT_REQ_TYPE)(T::anisotropic_interaction_type))
((NBL_CONCEPT_REQ_TYPE)(T::sample_type))
((NBL_CONCEPT_REQ_TYPE)(T::anisocache_type))
((NBL_CONCEPT_REQ_TYPE)(T::evalcache_type))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't require a separate evaluation cache type

((NBL_CONCEPT_REQ_TYPE)(T::isotropic_interaction_type))
((NBL_CONCEPT_REQ_TYPE)(T::isocache_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.eval_and_weight(_sample, iso, isocache)), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.evalAndWeight(_sample, iso, evalcache)), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

evalAndWeight taking the anisocache or isocache should be an extra overload in the imcrofacet BxDF concepts

}
using g2g1_query_type = typename N::g2g1_query_type;
g2g1_query_type gq = ndf.template createG2G1Query<sample_type, Interaction>(_sample, interaction);
scalar_type G2_over_G1 = ndf.template G2_over_G1<sample_type, Interaction, MicrofacetCache>(gq, _sample, interaction, cache);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check how well this behaves as roughness ->0 we don't want to have NaNs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a check in ndfs for a<float_min

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're bypassing a bunch of things , so there's no check

scalar_type G2_over_G1(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC

you will in-fact assert in the constructor

enable_if_t<C::value && !IsAnisotropic, g2g1_query_type> createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) NBL_CONST_MEMBER_FUNC

of the query
assert(a2 >= numeric_limits<scalar_type>::min);

I mean the HLSL compiles to C++ and we have a unit test so you can go through it with a debugger I guess 🙃

I think if you know/check the PDF not being INF before setting G2_over_G1 you can guard against that

Comment on lines +975 to +985
#define NBL_CONCEPT_PARAM_3 (evalcache, typename T::evalcache_type)
NBL_CONCEPT_BEGIN(4)
#define bxdf NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0
#define _sample NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1
#define aniso NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2
#define evalcache NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_3
NBL_CONCEPT_END(
((NBL_CONCEPT_REQ_TYPE)(T::evalcache_type))
((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(bxdf_common, T))
((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(AnisotropicMicrofacetCache, typename T::anisocache_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((bxdf.evalAndWeight(_sample, aniso, evalcache)), ::nbl::hlsl::is_same_v, typename T::value_weight_type))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool but evalcache needs to be just microfacetCache and be of type T::cache_type

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no evalcache_type

((NBL_CONCEPT_REQ_TYPE)(T::object_handle_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((sqr.getSample()), ::nbl::hlsl::is_same_v, typename T::sample_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((sqr.getQuotientPdf()), ::nbl::hlsl::is_same_v, typename T::quotient_pdf_type))
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((sqr.getQuotientPdf()), ::nbl::hlsl::is_same_v, typename T::quotient_weight_type))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getQuotientPdf rename to getQuotientAndWeight

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants