-
Notifications
You must be signed in to change notification settings - Fork 67
Iridescent fresnel, bxdfs #918
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
| // TODO: will probably merge with __call at some point | ||
| static void __polarized(const T orientedEta, const T orientedEtak, const T cosTheta, NBL_REF_ARG(T) Rp, NBL_REF_ARG(T) Rs) | ||
| { | ||
| T cosTheta_2 = cosTheta * cosTheta; | ||
| T sinTheta2 = hlsl::promote<T>(1.0) - cosTheta_2; | ||
| const T eta = orientedEta; | ||
| const T eta2 = eta*eta; | ||
| const T etak = orientedEtak; | ||
| const T etak2 = etak*etak; | ||
|
|
||
| const T etaLen2 = eta2 + etak2; | ||
| assert(hlsl::all(etaLen2 > hlsl::promote<T>(hlsl::exp2<scalar_type>(-numeric_limits<scalar_type>::digits)))); | ||
| T t1 = etaLen2 * cosTheta_2; | ||
| const T etaCosTwice = eta * cosTheta * scalar_type(2.0); | ||
|
|
||
| const T rs_common = etaLen2 + cosTheta_2; | ||
| Rs = (rs_common - etaCosTwice) / (rs_common + etaCosTwice); | ||
| const T rp_common = t1 + hlsl::promote<T>(1.0); | ||
| Rp = (rp_common - etaCosTwice) / (rp_common + etaCosTwice); | ||
| } |
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.
make a new struct for this e.g. ThinFilmConductor, its separate functionality, same for the dielectric
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 will note that it's the same calculation all the way until the end where the regular fresnel just returns (Rs + Rp) * 0.5 instead of inout Rs, Rp
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 return complex_t<T> and treat Rs as Real and Rp as imag, or make a struct to hold Polarized Reflectance and DRY the code
| template<class Config NBL_PRIMARY_REQUIRES(config_concepts::MicrofacetConfiguration<Config>) | ||
| struct SIridescent | ||
| { | ||
| using this_t = SIridescent<Config>; | ||
| NBL_BXDF_CONFIG_ALIAS(scalar_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(vector2_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(vector3_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(ray_dir_info_type, Config); | ||
|
|
||
| NBL_BXDF_CONFIG_ALIAS(isotropic_interaction_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(anisotropic_interaction_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(sample_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(spectral_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(quotient_pdf_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(isocache_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(anisocache_type, Config); | ||
|
|
||
| using ndf_type = ndf::GGX<scalar_type, false>; | ||
| using fresnel_type = fresnel::Iridescent<spectral_type>; | ||
| using measure_transform_type = ndf::SDualMeasureQuant<scalar_type,true,ndf::MTT_REFLECT>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = BxDFClampMode::BCM_MAX; | ||
|
|
||
| struct SCreationParams | ||
| { | ||
| scalar_type A; | ||
| scalar_type thickness; // thin-film thickness in nm | ||
| spectral_type ior0; | ||
| spectral_type ior1; | ||
| spectral_type ior2; | ||
| spectral_type iork2; | ||
| }; | ||
| using creation_type = SCreationParams; | ||
|
|
||
| struct SIridQuery | ||
| { | ||
| using scalar_type = scalar_type; | ||
|
|
||
| scalar_type getDevshV() NBL_CONST_MEMBER_FUNC { return devsh_v; } | ||
| scalar_type getDevshL() NBL_CONST_MEMBER_FUNC { return devsh_l; } | ||
|
|
||
| scalar_type devsh_v; | ||
| scalar_type devsh_l; | ||
| }; | ||
| using query_type = SIridQuery; | ||
|
|
||
| static this_t create(scalar_type A, scalar_type thickness, NBL_CONST_REF_ARG(spectral_type) ior0, NBL_CONST_REF_ARG(spectral_type) ior1, NBL_CONST_REF_ARG(spectral_type) ior2, NBL_CONST_REF_ARG(spectral_type) iork2) | ||
| { | ||
| this_t retval; | ||
| retval.__base.ndf.A = vector2_type(A, A); | ||
| retval.__base.ndf.a2 = A*A; | ||
| retval.__base.ndf.one_minus_a2 = scalar_type(1.0) - A*A; | ||
| retval.__base.fresnel.Dinc = thickness; | ||
| retval.__base.fresnel.ior1 = ior0; | ||
| retval.__base.fresnel.ior2 = ior1; | ||
| retval.__base.fresnel.ior3 = ior2; | ||
| retval.__base.fresnel.iork3 = iork2; | ||
| return retval; | ||
| } | ||
| static this_t create(NBL_CONST_REF_ARG(creation_type) params) | ||
| { | ||
| return create(params.A, params.thickness, params.ior0, params.ior1, params.ior2, params.iork2); | ||
| } | ||
|
|
||
| query_type createQuery(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) | ||
| { | ||
| query_type query; | ||
| ndf_type ggx_ndf = __base.getNDF(); | ||
| query.devsh_v = ggx_ndf.devsh_part(interaction.getNdotV2()); | ||
| query.devsh_l = ggx_ndf.devsh_part(_sample.getNdotL2()); | ||
| return query; | ||
| } | ||
|
|
||
| spectral_type eval(NBL_CONST_REF_ARG(query_type) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||
| { | ||
| if (_sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min) | ||
| { | ||
| struct SGGXG2XQuery | ||
| { | ||
| using scalar_type = scalar_type; | ||
|
|
||
| scalar_type getDevshV() NBL_CONST_MEMBER_FUNC { return devsh_v; } | ||
| scalar_type getDevshL() NBL_CONST_MEMBER_FUNC { return devsh_l; } | ||
| BxDFClampMode getClampMode() NBL_CONST_MEMBER_FUNC { return _clamp; } | ||
|
|
||
| scalar_type devsh_v; | ||
| scalar_type devsh_l; | ||
| BxDFClampMode _clamp; | ||
| }; | ||
|
|
||
| SGGXG2XQuery g2_query; | ||
| g2_query.devsh_v = query.getDevshV(); | ||
| g2_query.devsh_l = query.getDevshL(); | ||
| g2_query._clamp = _clamp; | ||
|
|
||
| measure_transform_type dualMeasure = __base.template __DG<SGGXG2XQuery>(g2_query, _sample, interaction, cache); | ||
| dualMeasure.maxNdotL = _sample.getNdotL(_clamp); | ||
| scalar_type DG = dualMeasure.getProjectedLightMeasure(); | ||
| fresnel_type f = __base.getFresnel(); | ||
| f.absCosTheta = cache.getLdotH(); | ||
| return f() * DG; | ||
| } | ||
| else | ||
| return hlsl::promote<spectral_type>(0.0); | ||
| } | ||
|
|
||
| sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u, NBL_REF_ARG(isocache_type) cache) | ||
| { | ||
| SGGXAnisotropic<Config> ggx_aniso = SGGXAnisotropic<Config>::create(__base.ndf.A.x, __base.ndf.A.y, __base.fresnel.ior3/__base.fresnel.ior2, __base.fresnel.iork3/__base.fresnel.ior2); | ||
| anisocache_type anisocache; | ||
| sample_type s = ggx_aniso.generate(anisotropic_interaction_type::create(interaction), u, anisocache); | ||
| cache = anisocache.iso_cache; | ||
| return s; | ||
| } | ||
|
|
||
| scalar_type pdf(NBL_CONST_REF_ARG(query_type) query, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||
| { | ||
| struct SGGXDG1Query | ||
| { | ||
| using scalar_type = scalar_type; | ||
|
|
||
| scalar_type getNdf() NBL_CONST_MEMBER_FUNC { return ndf; } | ||
| scalar_type getG1over2NdotV() NBL_CONST_MEMBER_FUNC { return G1_over_2NdotV; } | ||
|
|
||
| scalar_type ndf; | ||
| scalar_type G1_over_2NdotV; | ||
| }; | ||
|
|
||
| SGGXDG1Query dg1_query; | ||
| ndf_type ggx_ndf = __base.getNDF(); | ||
| dg1_query.ndf = __base.__D(cache); | ||
|
|
||
| const scalar_type devsh_v = query.getDevshV(); | ||
| dg1_query.G1_over_2NdotV = ggx_ndf.G1_wo_numerator_devsh_part(interaction.getNdotV(_clamp), devsh_v); | ||
|
|
||
| measure_transform_type dualMeasure = __base.template __DG1<SGGXDG1Query>(dg1_query); | ||
| return dualMeasure.getMicrofacetMeasure(); | ||
| } | ||
|
|
||
| quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(query_type) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_CONST_REF_ARG(isocache_type) cache) | ||
| { | ||
| scalar_type _pdf = pdf(query, interaction, cache); | ||
|
|
||
| spectral_type quo = hlsl::promote<spectral_type>(0.0); | ||
| if (_sample.getNdotL() > numeric_limits<scalar_type>::min && interaction.getNdotV() > numeric_limits<scalar_type>::min) | ||
| { | ||
| struct SGGXG2XQuery | ||
| { | ||
| using scalar_type = scalar_type; | ||
|
|
||
| scalar_type getDevshV() NBL_CONST_MEMBER_FUNC { return devsh_v; } | ||
| scalar_type getDevshL() NBL_CONST_MEMBER_FUNC { return devsh_l; } | ||
| BxDFClampMode getClampMode() NBL_CONST_MEMBER_FUNC { return _clamp; } | ||
|
|
||
| scalar_type devsh_v; | ||
| scalar_type devsh_l; | ||
| BxDFClampMode _clamp; | ||
| }; | ||
|
|
||
| ndf_type ggx_ndf = __base.getNDF(); | ||
|
|
||
| SGGXG2XQuery g2_query; | ||
| g2_query.devsh_v = query.getDevshV(); | ||
| g2_query.devsh_l = query.getDevshL(); | ||
| g2_query._clamp = _clamp; | ||
| const scalar_type G2_over_G1 = ggx_ndf.template G2_over_G1<SGGXG2XQuery, sample_type, isotropic_interaction_type, isocache_type>(g2_query, _sample, interaction, cache); | ||
|
|
||
| fresnel_type f = __base.getFresnel(); | ||
| f.absCosTheta = cache.getLdotH(); | ||
| const spectral_type reflectance = f(); | ||
| quo = reflectance * G2_over_G1; | ||
| } | ||
|
|
||
| return quotient_pdf_type::create(quo, _pdf); | ||
| } | ||
|
|
||
| SCookTorrance<Config, ndf_type, fresnel_type, measure_transform_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.
you could have just added a Delta NDF, and then used a CookTorrance with Iridescent Fresnel
| vector_type iork3; | ||
| vector_type eta12; // outside (usually air 1.0) -> thin-film IOR | ||
| vector_type eta23; // thin-film -> base material IOR | ||
| vector_type etak23; // thin-film -> complex component, k==0 makes dielectric |
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.
what are the pros and const of specializing and not having this member when you don't support Transmission
| } | ||
|
|
||
| T operator()() | ||
| T operator()(const scalar_type clampedCosTheta /* LdotH */) |
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 remove the LdotH comment, fresnels are always evaluated with VdotH
| using monochrome_type = vector<scalar_type, 1>; | ||
| using vector_type = T; // assert dim==3? | ||
|
|
||
| static this_t create(scalar_type Dinc, vector_type ior1, vector_type ior2, vector_type ior3, vector_type iork3) |
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.
make a creation struct, too many parameters to a function with same type, easy to mess up
| struct colorspace_base | ||
| { | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_R = 580.0f; | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_G = 550.0f; | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_B = 450.0f; | ||
| // default CIE RGB primaries wavelengths | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_R = 700.0f; | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_G = 546.1f; | ||
| NBL_CONSTEXPR_STATIC_INLINE float32_t wavelength_B = 435.8f; | ||
| }; |
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.
don't even, each colorspace just needs to provide them, end of
| // 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_TRANSMISSION_IRIDESCENT_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_BXDF_TRANSMISSION_IRIDESCENT_INCLUDED_ | ||
|
|
||
| #include "nbl/builtin/hlsl/bxdf/transmission/ggx.hlsl" | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace bxdf | ||
| { | ||
| namespace transmission | ||
| { | ||
|
|
||
| template<class Config NBL_PRIMARY_REQUIRES(config_concepts::MicrofacetConfiguration<Config>) | ||
| struct SIridescent | ||
| { | ||
| using this_t = SIridescent<Config>; | ||
| NBL_BXDF_CONFIG_ALIAS(scalar_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(vector2_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(vector3_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(matrix3x3_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(monochrome_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(ray_dir_info_type, Config); | ||
|
|
||
| NBL_BXDF_CONFIG_ALIAS(isotropic_interaction_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(anisotropic_interaction_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(sample_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(spectral_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(quotient_pdf_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(isocache_type, Config); | ||
| NBL_BXDF_CONFIG_ALIAS(anisocache_type, Config); | ||
| using brdf_type = reflection::SGGXIsotropic<Config>; | ||
|
|
||
| using ndf_type = ndf::GGX<scalar_type, false>; | ||
| using fresnel_type = fresnel::Iridescent<spectral_type>; | ||
| using measure_transform_type = ndf::SDualMeasureQuant<scalar_type,true,ndf::MTT_REFLECT_REFRACT>; | ||
|
|
||
| NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = BxDFClampMode::BCM_ABS; | ||
|
|
||
| struct SCreationParams |
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 special BSDF and BRDF not even needed for this
|
In this PR also resolve all left over comments from #930 |
No description provided.