-
Notifications
You must be signed in to change notification settings - Fork 65
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?
Conversation
#ifndef __HLSL_VERSION | ||
namespace std | ||
{ | ||
template<typename T, uint16_t N> | ||
struct hash<nbl::hlsl::vector<T,N> > | ||
{ | ||
size_t operator()(const nbl::hlsl::vector<T,N>& v) const noexcept | ||
{ | ||
size_t seed = 0; | ||
NBL_UNROLL for (uint16_t i = 0; i < N; i++) | ||
nbl::core::hash_combine(seed, v[i]); | ||
return seed; | ||
} | ||
}; | ||
|
||
template<typename T> | ||
struct hash<nbl::hlsl::vector<T,1> > | ||
{ | ||
size_t operator()(const nbl::hlsl::vector<T,1>& v) const noexcept | ||
{ | ||
std::hash<T> hasher; | ||
return hasher(v.x); | ||
} | ||
}; | ||
} | ||
#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.
are you sure having this specialization globally is a good idea ?
What do you use it for ?
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.
Also used in the bucket bxdf test, for hash map buckets
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.
then define it in that example, nowhere else
N ndf; | ||
F fresnel; | ||
}; | ||
|
||
template<class Config, class N, class F> | ||
NBL_PARTIAL_REQ_TOP(config_concepts::MicrofacetConfiguration<Config> && ndf::NDF<N> && fresnel::Fresnel<F>) | ||
struct SCookTorrance<Config, N, F, true NBL_PARTIAL_REQ_BOT(config_concepts::MicrofacetConfiguration<Config> && ndf::NDF<N> && fresnel::Fresnel<F>) > | ||
{ |
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.
any chance at inheriting from a common base for both BRDF and BSDF, so that we don't have so much duplicate code (BRDF and BSDF only differ in how they factor the reflectance into the generation and pdf)
|
||
template<class Query NBL_FUNC_REQUIRES(ggx_concepts::DG1BrdfQuery<Query>) | ||
scalar_type DG1(NBL_CONST_REF_ARG(Query) query) | ||
scalar_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query) | ||
{ | ||
return scalar_type(0.5) * query.getNdf() * query.getG1over2NdotV(); | ||
} | ||
|
||
template<class Query, class MicrofacetCache NBL_FUNC_REQUIRES(ggx_concepts::DG1BsdfQuery<Query> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
scalar_type DG1(NBL_CONST_REF_ARG(Query) query, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
scalar_type NG = query.getNdf() * query.getG1over2NdotV(); | ||
scalar_type factor = scalar_type(0.5); | ||
if (cache.isTransmission()) | ||
{ | ||
const scalar_type VdotH_etaLdotH = (cache.getVdotH() + query.getOrientedEta() * cache.getLdotH()); | ||
// VdotHLdotH is negative under transmission, so this factor is negative | ||
factor *= -scalar_type(2.0) * cache.getVdotHLdotH() / (VdotH_etaLdotH * VdotH_etaLdotH); | ||
} | ||
return NG * factor; | ||
return query.getNdf() * query.getG1(); | ||
} |
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.
this seems silly to keep around
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.
your query its just multiplying its two members
static scalar_type G1_wo_numerator_devsh_part(scalar_type absNdotX, scalar_type devsh_part) | ||
{ | ||
// numerator is 2 * NdotX | ||
return scalar_type(1.0) / (absNdotX + devsh_part); |
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.
why are the two methods needed?
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.
I'd think you only need G1_wo_numerator_devsh_part(scalar_type absNdotX, scalar_type devsh_part)
scalar_type getDevshV() NBL_CONST_MEMBER_FUNC { return devsh_v; } | ||
scalar_type getDevshL() NBL_CONST_MEMBER_FUNC { return devsh_l; } |
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.
its fine to have a query like this but we need a concept and template everything on it
} | ||
|
||
vector<scalar_type, 2> A; | ||
vector<scalar_type, 2> A; // TODO: remove? |
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.
yes!
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) | ||
{ | ||
using quant_query_type = typename N::quant_query_type; | ||
using dg1_query_type = typename N::dg1_query_type; | ||
|
||
scalar_type dummy; | ||
quant_query_type qq = ndf.template createQuantQuery<isocache_type>(cache, dummy); | ||
dg1_query_type dq = ndf.template createDG1Query<isotropic_interaction_type, isocache_type>(interaction, cache); | ||
quant_type DG1 = ndf.template DG1<sample_type, isotropic_interaction_type>(dq, qq, _sample, interaction); | ||
return DG1.projectedLightMeasure; | ||
} |
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.
the isotropic methods need enable_if
because you need to check if the NDF used is isotropic or not
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
BxDFClampMode _clamp = query.getClampMode(); | ||
assert(_clamp != BxDFClampMode::BCM_NONE); | ||
return scalar_type(4.0) * interaction.getNdotV(_clamp) * _sample.getNdotL(_clamp) * correlated_wo_numerator<LS, Interaction>(query, _sample, interaction); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
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) |
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.
the cook_torrance_base::Eval
calling D
and correlated
separately misses an optimization opportunity fo GGX to not put a 4 NdotV NdotL factor in the lightProjectedMeasure of the return value
We need to figure out how to leverage it on
BxDFClampMode _clamp = query.getClampMode(); | ||
assert(_clamp != BxDFClampMode::BCM_NONE); |
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.
its weird for the query to tell us about clamping dynamically, I'd possibly prefer constexpr
return w2 * w2 * atab * numbers::inv_pi<scalar_type>; | ||
} |
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.
kill the burley method, I have some ideas to make GGX spin by employing a covariance matrix of sorts(don't implement yet, just throw the Desmos link in the comment)
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
BxDFClampMode _clamp = query.getClampMode(); | ||
assert(_clamp != BxDFClampMode::BCM_NONE); | ||
return scalar_type(4.0) * interaction.getNdotV(_clamp) * _sample.getNdotL(_clamp) * correlated_wo_numerator<LS, Interaction>(query, _sample, interaction); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
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) | ||
{ |
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.
same problem as burley, these are identical for isotropic and anisotropic once you have the query that provides you with the anisotropic terms.
Even correlated_Wo_numerator
is identical
//reprojection onto hemisphere | ||
//TODO try it wothout the max(), not sure if -t1*t1-t2*t2>-1.0 | ||
vector3_type H = t1*T1 + t2*T2 + sqrt<scalar_type>(max<scalar_type>(0.0, 1.0-t1*t1-t2*t2))*V; | ||
//unstretch |
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.
find out, you might have to be careful about catastropic cancellation making small values near 0 negative
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.
if it was in the original code, thats probably why it was there
template<typename T, bool IsAnisotropic, MicrofacetTransformTypes reflect_refract NBL_STRUCT_CONSTRAINABLE> | ||
struct GGX; | ||
|
||
// partial spec for brdf | ||
template<typename T> | ||
NBL_PARTIAL_REQ_TOP(concepts::FloatingPointScalar<T>) | ||
struct GGX<T,false,MTT_REFLECT NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScalar<T>) > | ||
{ | ||
using scalar_type = T; | ||
using base_type = impl::GGXCommon<T,false>; | ||
using quant_type = SDualMeasureQuant<scalar_type>; | ||
using vector2_type = vector<T, 2>; | ||
using vector3_type = vector<T, 3>; | ||
|
||
using dg1_query_type = typename base_type::dg1_query_type; | ||
using g2g1_query_type = typename base_type::g2g1_query_type; | ||
using quant_query_type = impl::SGGXQuantQuery<scalar_type>; | ||
|
||
template<class MicrofacetCache NBL_FUNC_REQUIRES(ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
quant_query_type createQuantQuery(NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) | ||
{ | ||
quant_query_type dummy; // brdfs don't make use of this | ||
return dummy; | ||
} | ||
template<class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
dg1_query_type createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
dg1_query_type dg1_query; | ||
dg1_query.ndf = __base.template D<MicrofacetCache>(cache); | ||
scalar_type clampedNdotV = interaction.getNdotV(BxDFClampMode::BCM_MAX); | ||
dg1_query.G1 = scalar_type(2.0) * clampedNdotV * __base.G1_wo_numerator(clampedNdotV, interaction.getNdotV2()); | ||
return dg1_query; | ||
} | ||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
g2g1_query_type createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
g2g1_query_type g2_query; | ||
g2_query.devsh_l = __base.devsh_part(_sample.getNdotL2()); | ||
g2_query.devsh_v = __base.devsh_part(interaction.getNdotV2()); | ||
g2_query._clamp = BxDFClampMode::BCM_MAX; | ||
return g2_query; | ||
} | ||
|
||
vector<T, 3> generateH(const vector3_type localV, const vector2_type u) | ||
{ | ||
return impl::GGXGenerateH<scalar_type>::__call(__base.A, localV, u); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
scalar_type d = __base.template D<MicrofacetCache>(cache); | ||
return createDualMeasureQuantity<T>(d, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type dg1 = __base.DG1(query); | ||
return createDualMeasureQuantity<T>(dg1, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
quant_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type g = __base.template correlated<LS, Interaction>(query, _sample, interaction); | ||
return createDualMeasureQuantity<T>(g, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
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) | ||
{ | ||
return __base.template G2_over_G1<LS, Interaction, MicrofacetCache>(query, _sample, interaction, cache); | ||
} | ||
|
||
base_type __base; | ||
}; | ||
|
||
template<typename T> | ||
NBL_PARTIAL_REQ_TOP(concepts::FloatingPointScalar<T>) | ||
struct GGX<T,true,MTT_REFLECT NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScalar<T>) > | ||
{ | ||
using scalar_type = T; | ||
using base_type = impl::GGXCommon<T,true>; | ||
using quant_type = SDualMeasureQuant<scalar_type>; | ||
using vector2_type = vector<T, 2>; | ||
using vector3_type = vector<T, 3>; | ||
|
||
using dg1_query_type = typename base_type::dg1_query_type; | ||
using g2g1_query_type = typename base_type::g2g1_query_type; | ||
using quant_query_type = impl::SGGXQuantQuery<scalar_type>; | ||
|
||
template<class MicrofacetCache NBL_FUNC_REQUIRES(AnisotropicMicrofacetCache<MicrofacetCache>) | ||
quant_query_type createQuantQuery(NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) | ||
{ | ||
quant_query_type dummy; // brdfs don't make use of this | ||
return dummy; | ||
} | ||
template<class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
dg1_query_type createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
dg1_query_type dg1_query; | ||
dg1_query.ndf = __base.template D<MicrofacetCache>(cache); | ||
scalar_type clampedNdotV = interaction.getNdotV(BxDFClampMode::BCM_MAX); | ||
dg1_query.G1 = scalar_type(2.0) * clampedNdotV * __base.G1_wo_numerator(clampedNdotV, interaction.getTdotV2(), interaction.getBdotV2(), interaction.getNdotV2()); | ||
return dg1_query; | ||
} | ||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
g2g1_query_type createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
g2g1_query_type g2_query; | ||
g2_query.devsh_l = __base.devsh_part(_sample.getTdotL2(), _sample.getBdotL2(), _sample.getNdotL2()); | ||
g2_query.devsh_v = __base.devsh_part(interaction.getTdotV2(), interaction.getBdotV2(), interaction.getNdotV2()); | ||
g2_query._clamp = BxDFClampMode::BCM_MAX; | ||
return g2_query; | ||
} | ||
|
||
vector<T, 3> generateH(const vector3_type localV, const vector2_type u) | ||
{ | ||
return impl::GGXGenerateH<scalar_type>::__call(__base.A, localV, u); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
scalar_type d = __base.template D<MicrofacetCache>(cache); | ||
return createDualMeasureQuantity<T>(d, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type dg1 = __base.DG1(query); | ||
return createDualMeasureQuantity<T>(dg1, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
quant_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type g = __base.template correlated<LS, Interaction>(query, _sample, interaction); | ||
return createDualMeasureQuantity<T>(g, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
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) | ||
{ | ||
return __base.template G2_over_G1<LS, Interaction, MicrofacetCache>(query, _sample, interaction, cache); | ||
} | ||
|
||
base_type __base; | ||
}; | ||
|
||
// partial for bsdf | ||
template<typename T, MicrofacetTransformTypes reflect_refract> | ||
NBL_PARTIAL_REQ_TOP(concepts::FloatingPointScalar<T>) | ||
struct GGX<T,false,reflect_refract NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScalar<T>) > | ||
{ | ||
using scalar_type = T; | ||
using base_type = impl::GGXCommon<T,false>; | ||
using quant_type = SDualMeasureQuant<scalar_type>; | ||
using vector2_type = vector<T, 2>; | ||
using vector3_type = vector<T, 3>; | ||
|
||
using dg1_query_type = typename base_type::dg1_query_type; | ||
using g2g1_query_type = typename base_type::g2g1_query_type; | ||
using quant_query_type = impl::SGGXQuantQuery<scalar_type>; | ||
|
||
template<class MicrofacetCache NBL_FUNC_REQUIRES(ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
quant_query_type createQuantQuery(NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) | ||
{ | ||
quant_query_type quant_query; | ||
quant_query.VdotHLdotH = cache.getVdotHLdotH(); | ||
quant_query.VdotH_etaLdotH = cache.getVdotH() + orientedEta * cache.getLdotH(); | ||
return quant_query; | ||
} | ||
template<class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
dg1_query_type createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
dg1_query_type dg1_query; | ||
dg1_query.ndf = __base.template D<MicrofacetCache>(cache); | ||
scalar_type clampedNdotV = interaction.getNdotV(BxDFClampMode::BCM_ABS); | ||
dg1_query.G1 = scalar_type(2.0) * clampedNdotV * __base.G1_wo_numerator(clampedNdotV, interaction.getNdotV2()); | ||
return dg1_query; | ||
} | ||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
g2g1_query_type createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
g2g1_query_type g2_query; | ||
g2_query.devsh_l = __base.devsh_part(_sample.getNdotL2()); | ||
g2_query.devsh_v = __base.devsh_part(interaction.getNdotV2()); | ||
g2_query._clamp = BxDFClampMode::BCM_ABS; | ||
return g2_query; | ||
} | ||
|
||
vector<T, 3> generateH(const vector3_type localV, const vector2_type u) | ||
{ | ||
return impl::GGXGenerateH<scalar_type>::__call(__base.A, localV, u); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
scalar_type d = __base.template D<MicrofacetCache>(cache); | ||
return createDualMeasureQuantity<T, reflect_refract>(d, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type dg1 = __base.DG1(query); | ||
return createDualMeasureQuantity<T, reflect_refract>(dg1, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
quant_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type g = __base.template correlated<LS, Interaction>(query, _sample, interaction); | ||
return createDualMeasureQuantity<T, reflect_refract>(g, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction> && ReadableIsotropicMicrofacetCache<MicrofacetCache>) | ||
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) | ||
{ | ||
return __base.template G2_over_G1<LS, Interaction, MicrofacetCache>(query, _sample, interaction, cache); | ||
} | ||
|
||
base_type __base; | ||
}; | ||
|
||
template<typename T, MicrofacetTransformTypes reflect_refract> | ||
NBL_PARTIAL_REQ_TOP(concepts::FloatingPointScalar<T>) | ||
struct GGX<T,true,reflect_refract NBL_PARTIAL_REQ_BOT(concepts::FloatingPointScalar<T>) > | ||
{ | ||
using scalar_type = T; | ||
using base_type = impl::GGXCommon<T,true>; | ||
using quant_type = SDualMeasureQuant<scalar_type>; | ||
using vector2_type = vector<T, 2>; | ||
using vector3_type = vector<T, 3>; | ||
|
||
using dg1_query_type = typename base_type::dg1_query_type; | ||
using g2g1_query_type = typename base_type::g2g1_query_type; | ||
using quant_query_type = impl::SGGXQuantQuery<scalar_type>; | ||
|
||
template<class MicrofacetCache NBL_FUNC_REQUIRES(AnisotropicMicrofacetCache<MicrofacetCache>) | ||
quant_query_type createQuantQuery(NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) | ||
{ | ||
quant_query_type quant_query; | ||
quant_query.VdotHLdotH = cache.getVdotHLdotH(); | ||
quant_query.VdotH_etaLdotH = cache.getVdotH() + orientedEta * cache.getLdotH(); | ||
return quant_query; | ||
} | ||
template<class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
dg1_query_type createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
dg1_query_type dg1_query; | ||
dg1_query.ndf = __base.template D<MicrofacetCache>(cache); | ||
scalar_type clampedNdotV = interaction.getNdotV(BxDFClampMode::BCM_ABS); | ||
dg1_query.G1 = scalar_type(2.0) * clampedNdotV * __base.G1_wo_numerator(clampedNdotV, interaction.getTdotV2(), interaction.getBdotV2(), interaction.getNdotV2()); | ||
return dg1_query; | ||
} | ||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
g2g1_query_type createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
g2g1_query_type g2_query; | ||
g2_query.devsh_l = __base.devsh_part(_sample.getTdotL2(), _sample.getBdotL2(), _sample.getNdotL2()); | ||
g2_query.devsh_v = __base.devsh_part(interaction.getTdotV2(), interaction.getBdotV2(), interaction.getNdotV2()); | ||
g2_query._clamp = BxDFClampMode::BCM_ABS; | ||
return g2_query; | ||
} | ||
|
||
vector<T, 3> generateH(const vector3_type localV, const vector2_type u) | ||
{ | ||
return impl::GGXGenerateH<scalar_type>::__call(__base.A, localV, u); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) | ||
{ | ||
scalar_type d = __base.template D<MicrofacetCache>(cache); | ||
return createDualMeasureQuantity<T, reflect_refract>(d, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type dg1 = __base.DG1(query); | ||
return createDualMeasureQuantity<T, reflect_refract>(dg1, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction>) | ||
quant_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type g = __base.template correlated<LS, Interaction>(query, _sample, interaction); | ||
return createDualMeasureQuantity<T, reflect_refract>(g, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query.getVdotHLdotH(), quant_query.getVdotH_etaLdotH()); | ||
} | ||
|
||
template<class LS, class Interaction, class MicrofacetCache NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Anisotropic<Interaction> && AnisotropicMicrofacetCache<MicrofacetCache>) | ||
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) | ||
{ | ||
return __base.template G2_over_G1<LS, Interaction, MicrofacetCache>(query, _sample, interaction, cache); | ||
} | ||
|
||
base_type __base; | ||
}; | ||
|
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.
same as burley, I think all 4 could be rolled into one class, cause IsBSDF
is just a matter of a few enable_if
and NBL_IF_CONSTEXPR
and you can detect anisotropy from the NDF
return createDualMeasureQuantity<T>(d, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); | ||
} | ||
|
||
template<class LS, class Interaction NBL_FUNC_REQUIRES(LightSample<LS> && surface_interactions::Isotropic<Interaction>) | ||
quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) | ||
{ | ||
scalar_type dg1 = __base.DG1(query); | ||
return createDualMeasureQuantity<T>(dg1, interaction.getNdotV(BxDFClampMode::BCM_MAX), _sample.getNdotL(BxDFClampMode::BCM_MAX)); |
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.
we should somehow use our knowledge of factors in GGX that cancel out to make the dual measure quantity faster.
static this_t create(scalar_type A, NBL_CONST_REF_ARG(spectral_type) eta, NBL_CONST_REF_ARG(spectral_type) etak) | ||
{ | ||
this_t retval; | ||
retval.__base.ndf.__base.A = vector2_type(A, A); | ||
retval.__base.ndf.__base.a2 = A*A; | ||
retval.__base.fresnel.ior = ior0; | ||
retval.__base.fresnel.iork = ior1; | ||
retval.__base.fresnel.iork2 = ior1*ior1; | ||
retval.__base.fresnel.eta = eta; | ||
retval.__base.fresnel.etak2 = etak * etak; | ||
retval.__base.fresnel.etaLen2 = eta * eta + retval.__base.fresnel.etak2; | ||
return retval; | ||
} |
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.
why are you assuming the fresnel used ?
spectral_type ior0; | ||
spectral_type ior1; |
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.
you need to pass the fresnel already set up
return create(params.A, params.ior0, params.ior1); | ||
return create(params.A, params.eta, params.etak); | ||
} | ||
|
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.
why do all these still exist and aren't just typedefs for Cook Torrance ?
sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) | ||
{ | ||
return __base.generate(anisotropic_interaction_type::create(interaction), u); | ||
return __base.template generate<vector2_type>(anisotropic_interaction_type::create(interaction), u); | ||
} | ||
sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) | ||
{ | ||
return __base.generate(interaction, u); | ||
return __base.template generate<vector2_type>(interaction, u); | ||
} |
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.
why not just typedef instead of writing pointless passthrough class ?
{ | ||
quant_type G2 = ndf.template correlated<sample_type, isotropic_interaction_type>(gq, qq, _sample, interaction); | ||
DG *= G2.microfacetMeasure; | ||
DG *= ndf.template correlated<sample_type, isotropic_interaction_type>(gq, _sample, interaction); |
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.
lower the gq
creation as well
{ | ||
quant_type G2 = ndf.template correlated<sample_type, anisotropic_interaction_type>(gq, qq, _sample, interaction); | ||
DG *= G2.microfacetMeasure; | ||
DG *= ndf.template correlated<sample_type, anisotropic_interaction_type>(gq, _sample, interaction); |
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.
lower the gq
creation as well
Description
Continues #899 , #916 and #919
Testing
TODO list: