-
Notifications
You must be signed in to change notification settings - Fork 66
Bxdf fixes cook torrance #930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
5218545
f7525af
c50db68
c49bedb
319c954
4eeacf1
e7bc784
72226bb
f34b348
ad13044
d8d2116
238b08e
8bc707f
9fb28cf
4cb8a0a
392dc31
02de86e
4a7f532
80c4f67
6233bd1
ce5fbac
47e814b
c983975
0f2ee0b
b5f02e6
a111415
9655049
a1743d2
e6d663b
340cee3
a3733b1
3e3589b
4bdf199
4faecc3
407da2f
638b8b5
c587820
d438360
5f49f11
627074b
3896231
91b39d5
2a3cda3
c9f9366
fd128e6
882375e
b22d570
c0586f5
9eeb248
26c76e4
58e2a0b
2a08728
b993e47
f3cb6ff
7389c9a
ec5913b
bccdb0b
1e9e407
dab51c3
53ab934
804014f
260f7a3
fd54ac4
5caf006
7508b82
2b4a9c1
d3fa872
5765e87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,340 @@ | ||||||||||||||||||||||||||||||||||
// Copyright (C) 2018-2025 - 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_BUILTIN_HLSL_BXDF_COOK_TORRANCE_INCLUDED_ | ||||||||||||||||||||||||||||||||||
#define _NBL_BUILTIN_HLSL_BXDF_COOK_TORRANCE_INCLUDED_ | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#include "nbl/builtin/hlsl/bxdf/common.hlsl" | ||||||||||||||||||||||||||||||||||
#include "nbl/builtin/hlsl/bxdf/config.hlsl" | ||||||||||||||||||||||||||||||||||
#include "nbl/builtin/hlsl/bxdf/ndf.hlsl" | ||||||||||||||||||||||||||||||||||
#include "nbl/builtin/hlsl/bxdf/fresnel.hlsl" | ||||||||||||||||||||||||||||||||||
#include "nbl/builtin/hlsl/bxdf/ndf/microfacet_to_light_transform.hlsl" | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
namespace nbl | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
namespace hlsl | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
namespace bxdf | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
namespace impl | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
template<typename T, typename U> | ||||||||||||||||||||||||||||||||||
struct __implicit_promote; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<typename T> | ||||||||||||||||||||||||||||||||||
struct __implicit_promote<T,T> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
static T __call(const T v) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return v; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<typename T> | ||||||||||||||||||||||||||||||||||
struct __implicit_promote<T,vector<typename vector_traits<T>::scalar_type, 1> > | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
static T __call(const vector<typename vector_traits<T>::scalar_type, 1> v) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return hlsl::promote<T>(v[0]); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class N, class F, bool IsBSDF> | ||||||||||||||||||||||||||||||||||
struct quant_query_helper; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class N, class F> | ||||||||||||||||||||||||||||||||||
struct quant_query_helper<N, F, true> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
using quant_query_type = typename N::quant_query_type; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class C> | ||||||||||||||||||||||||||||||||||
static quant_query_type __call(NBL_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(C) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return ndf.template createQuantQuery<C>(cache, fresnel.orientedEta.value[0]); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class N, class F> | ||||||||||||||||||||||||||||||||||
struct quant_query_helper<N, F, false> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
using quant_query_type = typename N::quant_query_type; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class C> | ||||||||||||||||||||||||||||||||||
static quant_query_type __call(NBL_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(C) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
typename N::scalar_type dummy; | ||||||||||||||||||||||||||||||||||
return ndf.template createQuantQuery<C>(cache, dummy); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F, bool IsBSDF> | ||||||||||||||||||||||||||||||||||
struct check_TIR_helper; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F> | ||||||||||||||||||||||||||||||||||
struct check_TIR_helper<F, false> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
template<class MicrofacetCache> | ||||||||||||||||||||||||||||||||||
static bool __call(NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F> | ||||||||||||||||||||||||||||||||||
struct check_TIR_helper<F, true> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
template<class MicrofacetCache> | ||||||||||||||||||||||||||||||||||
static bool __call(NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return ComputeMicrofacetNormal<typename F::scalar_type>::isValidMicrofacet(cache.isTransmission(), cache.getVdotL(), cache.getAbsNdotH(), fresnel.getRefractionOrientedEta()); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F, bool IsBSDF NBL_STRUCT_CONSTRAINABLE> | ||||||||||||||||||||||||||||||||||
struct getOrientedFresnel; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F> | ||||||||||||||||||||||||||||||||||
struct getOrientedFresnel<F, false> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
static F __call(NBL_CONST_REF_ARG(F) fresnel, typename F::scalar_type NdotV) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
// expect conductor fresnel | ||||||||||||||||||||||||||||||||||
return fresnel; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class F> | ||||||||||||||||||||||||||||||||||
NBL_PARTIAL_REQ_TOP(fresnel::TwoSidedFresnel<F>) | ||||||||||||||||||||||||||||||||||
struct getOrientedFresnel<F, true NBL_PARTIAL_REQ_BOT(fresnel::TwoSidedFresnel<F>) > | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
using scalar_type = typename F::scalar_type; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
static F __call(NBL_CONST_REF_ARG(F) fresnel, scalar_type NdotV) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return fresnel.getReorientedFresnel(NdotV); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// N (NDF), F (fresnel) | ||||||||||||||||||||||||||||||||||
template<class Config, class N, class F NBL_PRIMARY_REQUIRES(config_concepts::MicrofacetConfiguration<Config> && ndf::NDF<N> && fresnel::Fresnel<F>) | ||||||||||||||||||||||||||||||||||
struct SCookTorrance | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
MICROFACET_BXDF_CONFIG_TYPE_ALIASES(Config); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
using this_t = SCookTorrance<Config, N, F>; | ||||||||||||||||||||||||||||||||||
using quant_type = typename N::quant_type; | ||||||||||||||||||||||||||||||||||
using ndf_type = N; | ||||||||||||||||||||||||||||||||||
using fresnel_type = F; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
NBL_CONSTEXPR_STATIC_INLINE bool IsAnisotropic = ndf_type::IsAnisotropic; | ||||||||||||||||||||||||||||||||||
NBL_CONSTEXPR_STATIC_INLINE bool IsBSDF = ndf_type::NDFSurfaceType != ndf::MTT_REFLECT; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class Interaction, class MicrofacetCache> | ||||||||||||||||||||||||||||||||||
spectral_type __eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
fresnel_type _f = impl::getOrientedFresnel<fresnel_type, IsBSDF>::__call(fresnel, interaction.getNdotV()); | ||||||||||||||||||||||||||||||||||
const bool notTIR = impl::check_TIR_helper<fresnel_type, IsBSDF>::template __call<MicrofacetCache>(_f, cache); | ||||||||||||||||||||||||||||||||||
if ((IsBSDF && notTIR) || (!IsBSDF && _sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min)) | ||||||||||||||||||||||||||||||||||
Comment on lines
+138
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. its a bit cleaner to write bool valid;
fresnel_type _f = fresnel;
NBL_IF_CONSTEXPR(IsBSDF)
{
_f = ..special stuff here...;
valid = impl::check_TIR_helper<fresnel_type, IsBSDF>::template __call<MicrofacetCache>(_f, cache);
}
else
valid = _sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min;
if (!valid)
return hlsl::promote<spectral_type>(0.0); |
||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
using quant_query_type = typename ndf_type::quant_query_type; | ||||||||||||||||||||||||||||||||||
using g2g1_query_type = typename ndf_type::g2g1_query_type; | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. push to alias to where its actually needed/used |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
scalar_type dummy; | ||||||||||||||||||||||||||||||||||
quant_query_type qq = ndf.template createQuantQuery<MicrofacetCache>(cache, dummy); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
quant_type D = ndf.template D<sample_type, Interaction, MicrofacetCache>(qq, _sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
scalar_type DG = D.projectedLightMeasure; | ||||||||||||||||||||||||||||||||||
if (D.microfacetMeasure < bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity)) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
g2g1_query_type gq = ndf.template createG2G1Query<sample_type, Interaction>(_sample, interaction); | ||||||||||||||||||||||||||||||||||
DG *= ndf.template correlated<sample_type, Interaction>(gq, _sample, interaction); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
Comment on lines
+148
to
+153
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm actually since Eval is not Quotient, it should return 0 whenever PDF would have been INF, and therefore whenever Eval is inf, you can just return 0 |
||||||||||||||||||||||||||||||||||
NBL_IF_CONSTEXPR(IsBSDF) | ||||||||||||||||||||||||||||||||||
return impl::__implicit_promote<spectral_type, typename fresnel_type::vector_type>::__call(_f(hlsl::abs(cache.getVdotH()))) * DG; | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
return impl::__implicit_promote<spectral_type, typename fresnel_type::vector_type>::__call(_f(cache.getVdotH())) * DG; | ||||||||||||||||||||||||||||||||||
Comment on lines
+154
to
+157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rewrite to float clampedVdotH = cache.getVdotH();
NBL_IF_CONSTEXPR(IsBSDF)
clampedVdotH = hlsl::abs(clampedVdotH);
return impl::__implicit_promote<spectral_type, typename fresnel_type::vector_type>::__call(_f(clampedVdotH)) * DG; |
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
return hlsl::promote<spectral_type>(0.0); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsAnisotropic> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsAnisotropic, spectral_type> eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return __eval<isotropic_interaction_type, isocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_CONST_REF_ARG(anisocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return __eval<anisotropic_interaction_type, anisocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsBSDF> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsBSDF, sample_type> generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u, NBL_REF_ARG(anisocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
ray_dir_info_type localV_raydir = interaction.getV().transform(interaction.getToTangentSpace()); | ||||||||||||||||||||||||||||||||||
const vector3_type localV = interaction.getTangentSpaceV(); | ||||||||||||||||||||||||||||||||||
const vector3_type localH = ndf.generateH(localV, u); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
cache = anisocache_type::createForReflection(localV, localH); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see what sets the same problem arises with the next create function Nabla/include/nbl/builtin/hlsl/bxdf/common.hlsl Lines 725 to 740 in 804014f
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw in the If I computed Correctly. |
||||||||||||||||||||||||||||||||||
struct reflect_wrapper | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
vector3_type operator()() NBL_CONST_MEMBER_FUNC | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return r(VdotH); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
bxdf::Reflect<scalar_type> r; | ||||||||||||||||||||||||||||||||||
scalar_type VdotH; | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
reflect_wrapper r; | ||||||||||||||||||||||||||||||||||
r.r = bxdf::Reflect<scalar_type>::create(localV, localH); | ||||||||||||||||||||||||||||||||||
r.VdotH = cache.getVdotH(); | ||||||||||||||||||||||||||||||||||
Comment on lines
+180
to
+191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. write a comment that we're doing all these gymnastics to have reflect use an externally computed |
||||||||||||||||||||||||||||||||||
ray_dir_info_type localL = localV_raydir.template reflect<reflect_wrapper>(r); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the whole point of the
Note that we can do reflections and refractions in any space we like, so instead of bringing V to tangent and L back out of it, one can just bring (this is why we get our reflection wrapper to override the computation of This is not only 1 transformation instead of 2, but also a muuch cheaper transformation (always a 3x3 matrix mul with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know that creating a sample from worldspace L requires 3 dot products with TBN which is same as creating a sample from tangentspace L (TBN dot products already given) and transforming it into worldspace HOWEVER:
Also the |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// fail if samples have invalid paths | ||||||||||||||||||||||||||||||||||
if (localL.getDirection().z < scalar_type(0.0)) // NdotL<0 | ||||||||||||||||||||||||||||||||||
localL.makeInvalid(); // should check if sample direction is invalid | ||||||||||||||||||||||||||||||||||
Comment on lines
+194
to
+196
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can check this before reflecting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw a compiler's Common Subexpression Elimination pass should re-use the already computed may want to leave that as a comment before the if-statement |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return sample_type::createFromTangentSpace(localL, interaction.getFromTangentSpace()); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
Comment on lines
+172
to
+199
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw you're not checking at all that the this in turn for a rough NDF will result in some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. after you throw away |
||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<IsBSDF> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && IsBSDF, sample_type> generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(anisocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
fresnel_type _f = impl::getOrientedFresnel<fresnel_type, IsBSDF>::__call(fresnel, interaction.getNdotV()); | ||||||||||||||||||||||||||||||||||
fresnel::OrientedEtaRcps<monochrome_type> rcpEta = _f.getOrientedEtaRcps(); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
ray_dir_info_type V = interaction.getV(); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't need this till much later |
||||||||||||||||||||||||||||||||||
const vector3_type localV = interaction.getTangentSpaceV(); | ||||||||||||||||||||||||||||||||||
const vector3_type upperHemisphereV = ieee754::flipSignIfRHSNegative<vector3_type>(localV, hlsl::promote<vector3_type>(interaction.getNdotV())); | ||||||||||||||||||||||||||||||||||
Comment on lines
+203
to
+208
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assign |
||||||||||||||||||||||||||||||||||
const vector3_type localH = ndf.generateH(upperHemisphereV, u.xy); | ||||||||||||||||||||||||||||||||||
const vector3_type H = hlsl::mul(interaction.getFromTangentSpace(), localH); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const scalar_type VdotH = hlsl::dot(V.getDirection(), H); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. compute this as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You can assert it, VNDF sampling should guarantee this |
||||||||||||||||||||||||||||||||||
const scalar_type reflectance = _f(hlsl::abs(VdotH))[0]; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
scalar_type rcpChoiceProb; | ||||||||||||||||||||||||||||||||||
scalar_type z = u.z; | ||||||||||||||||||||||||||||||||||
bool transmitted = math::partitionRandVariable(reflectance, z, rcpChoiceProb); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
Refract<scalar_type> r = Refract<scalar_type>::create(V.getDirection(), H); | ||||||||||||||||||||||||||||||||||
bxdf::ReflectRefract<scalar_type> rr; | ||||||||||||||||||||||||||||||||||
rr.refract = r; | ||||||||||||||||||||||||||||||||||
ray_dir_info_type L = V.reflectRefract(rr, transmitted, rcpEta.value[0]); | ||||||||||||||||||||||||||||||||||
Comment on lines
+219
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use a wrapper same as reflect to override |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const vector3_type T = interaction.getT(); | ||||||||||||||||||||||||||||||||||
const vector3_type B = interaction.getB(); | ||||||||||||||||||||||||||||||||||
const vector3_type _N = interaction.getN(); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// fail if samples have invalid paths | ||||||||||||||||||||||||||||||||||
const vector3_type Ldir = L.getDirection(); | ||||||||||||||||||||||||||||||||||
const scalar_type LdotH = hlsl::dot(Ldir, H); | ||||||||||||||||||||||||||||||||||
if ((ComputeMicrofacetNormal<scalar_type>::isTransmissionPath(VdotH, LdotH) != transmitted) || (LdotH * hlsl::dot(_N, Ldir) < scalar_type(0.0))) | ||||||||||||||||||||||||||||||||||
L.makeInvalid(); // should check if sample direction is invalid | ||||||||||||||||||||||||||||||||||
Comment on lines
+229
to
+232
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you actually want to make the isotropic part of the continues https://github.com/Devsh-Graphics-Programming/Nabla/pull/930/files?diff=split&w=1#r2356451287 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're also checking the wrong thing, VNDF sampling guarantees that So what you should really be checking is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all the above means that the
and
for sure, then
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what you should assert() though after you pass the
|
||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
cache = anisocache_type::create(VdotH, Ldir, H, T, B, _N, transmitted); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use this instead Nabla/include/nbl/builtin/hlsl/bxdf/common.hlsl Lines 725 to 730 in 804014f
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return sample_type::create(L, T, B, _N); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as for the BRDF generation, |
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsAnisotropic>, typename D=bool_constant<!IsBSDF> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsAnisotropic && D::value && !IsBSDF, sample_type> generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u, NBL_REF_ARG(isocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
anisocache_type aniso_cache; | ||||||||||||||||||||||||||||||||||
sample_type s = generate(anisotropic_interaction_type::create(interaction), u, aniso_cache); | ||||||||||||||||||||||||||||||||||
cache = aniso_cache.iso_cache; | ||||||||||||||||||||||||||||||||||
return s; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsAnisotropic>, typename D=bool_constant<IsBSDF> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsAnisotropic && D::value && IsBSDF, sample_type> generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(isocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
anisocache_type aniso_cache; | ||||||||||||||||||||||||||||||||||
sample_type s = generate(anisotropic_interaction_type::create(interaction), u, aniso_cache); | ||||||||||||||||||||||||||||||||||
cache = aniso_cache.iso_cache; | ||||||||||||||||||||||||||||||||||
return s; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
Comment on lines
+238
to
+253
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you could have just had one templated on |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class Interaction, class MicrofacetCache> | ||||||||||||||||||||||||||||||||||
scalar_type __pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
using quant_query_type = typename ndf_type::quant_query_type; | ||||||||||||||||||||||||||||||||||
using dg1_query_type = typename ndf_type::dg1_query_type; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
dg1_query_type dq = ndf.template createDG1Query<Interaction, MicrofacetCache>(interaction, cache); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
fresnel_type _f = impl::getOrientedFresnel<fresnel_type, IsBSDF>::__call(fresnel, interaction.getNdotV()); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you only need to reorient fresnels for BSDFs, see https://github.com/Devsh-Graphics-Programming/Nabla/pull/930/files#r2401699310 |
||||||||||||||||||||||||||||||||||
quant_query_type qq = impl::quant_query_helper<ndf_type, fresnel_type, IsBSDF>::template __call<MicrofacetCache>(ndf, _f, cache); | ||||||||||||||||||||||||||||||||||
quant_type DG1 = ndf.template DG1<sample_type, Interaction>(dq, qq, _sample, interaction); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
NBL_IF_CONSTEXPR(IsBSDF) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
const scalar_type reflectance = _f(hlsl::abs(cache.getVdotH()))[0]; | ||||||||||||||||||||||||||||||||||
return hlsl::mix(reflectance, scalar_type(1.0) - reflectance, cache.isTransmission()) * DG1.projectedLightMeasure; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return DG1.projectedLightMeasure; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsAnisotropic> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsAnisotropic, scalar_type> pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
if (IsBSDF || (_sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min)) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
scalar_type _pdf = __pdf<isotropic_interaction_type, isocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
return hlsl::mix(scalar_type(0.0), _pdf, _pdf < bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity)); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
return scalar_type(0.0); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_CONST_REF_ARG(anisocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
if (IsBSDF || (_sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min)) | ||||||||||||||||||||||||||||||||||
Comment on lines
+280
to
+290
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. checks are not complete for a BSDF (same problem as I'd really abstract the whole There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
scalar_type _pdf = __pdf<anisotropic_interaction_type, anisocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
return hlsl::mix(scalar_type(0.0), _pdf, _pdf < bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity)); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
return scalar_type(0.0); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
template<class Interaction, class MicrofacetCache> | ||||||||||||||||||||||||||||||||||
quotient_pdf_type __quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
scalar_type _pdf = __pdf<Interaction, MicrofacetCache>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
fresnel_type _f = impl::getOrientedFresnel<fresnel_type, IsBSDF>::__call(fresnel, interaction.getNdotV()); | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only BSDFs need to re-orient |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
spectral_type quo = hlsl::promote<spectral_type>(0.0); | ||||||||||||||||||||||||||||||||||
const bool notTIR = impl::check_TIR_helper<fresnel_type, IsBSDF>::template __call<MicrofacetCache>(_f, cache); | ||||||||||||||||||||||||||||||||||
if (notTIR) | ||||||||||||||||||||||||||||||||||
Comment on lines
+306
to
+307
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
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); | ||||||||||||||||||||||||||||||||||
Comment on lines
+310
to
+311
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
an NDF is smooth if PDF = INF |
||||||||||||||||||||||||||||||||||
NBL_IF_CONSTEXPR(IsBSDF) | ||||||||||||||||||||||||||||||||||
quo = hlsl::promote<spectral_type>(G2_over_G1); | ||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||
quo = _f(cache.getVdotH()) * G2_over_G1; | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assert that the |
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// set pdf=0 when quo=0 because we don't want to give high weight to sampling strategy that yields 0 contribution | ||||||||||||||||||||||||||||||||||
_pdf = hlsl::mix(_pdf, scalar_type(0.0), hlsl::all(quo < hlsl::promote<spectral_type>(numeric_limits<scalar_type>::min))); | ||||||||||||||||||||||||||||||||||
Comment on lines
+318
to
+319
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. quotient will never be 0 after the |
||||||||||||||||||||||||||||||||||
return quotient_pdf_type::create(quo, _pdf); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
template<typename C=bool_constant<!IsAnisotropic> > | ||||||||||||||||||||||||||||||||||
enable_if_t<C::value && !IsAnisotropic, quotient_pdf_type> quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return __quotient_and_pdf<isotropic_interaction_type, isocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_CONST_REF_ARG(anisocache_type) cache) | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
return __quotient_and_pdf<anisotropic_interaction_type, anisocache_type>(_sample, interaction, cache); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
ndf_type ndf; | ||||||||||||||||||||||||||||||||||
fresnel_type fresnel; // always front-facing | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah just add a method to create a reoriented-self-copy to the fresnels.
Btw why did you make a struct with a specialization instead of
fresnel_type _f = fresnel; NBL_IF_CONSTEXPR(IsBSDF) _f = ..special stuff here...;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not
constexpr
in hlsl