-
Notifications
You must be signed in to change notification settings - Fork 48
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
Port BxDF functions to HLSL #475
Changes from 1 commit
d3f4169
95cc93f
507b1a6
bcb9f77
8e61632
b9b29d2
6d7e989
6c24d2c
ef4f253
b89cad1
c964e09
bb088e9
5aac44b
01fd600
3671194
605f3c4
2a91a80
6ac724b
de66abf
3bcd088
2e65bbc
cc39ce3
9f18406
bfc2143
8a4eda4
f9da966
c80b0e9
321b252
b5d3a4c
47e3e4c
a9841d1
9af73f8
4ecbd7c
8eec0c0
e644e74
8135e46
4712763
a215ee3
9dd660f
255f8e8
42b19d7
95e9e2d
f01eeee
cbf8d71
1990c18
953b681
7011441
a09b8ef
d5e3189
b3a17c9
47c82ce
f037e69
5f70cca
67b22f0
9cfc8fb
0efa057
9720334
bb6ec81
52589d2
e2daa63
6853d83
a49760c
758a390
5e2bf89
915ef27
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,46 @@ | ||
// Copyright (C) 2018-2020 - 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_BRDF_SPECULAR_COMMON_INCLUDED_ | ||
#define _NBL_BUILTIN_HLSL_BXDF_BRDF_SPECULAR_COMMON_INCLUDED_ | ||
|
||
#include <nbl/builtin/hlsl/bxdf/common.hlsl> | ||
#include <nbl/builtin/hlsl/bxdf/ndf/common.hlsl> | ||
|
||
namespace nbl | ||
{ | ||
namespace hlsl | ||
{ | ||
namespace bxdf | ||
{ | ||
namespace brdf | ||
{ | ||
namespace specular | ||
{ | ||
|
||
template <class fresnel_t, class ndf_t, class Sample, class Interaction, class MicrofacetCache> | ||
struct CookTorrance : BxDFBase<float3, float, Sample, Interaction, MicrofacetCache> | ||
{ | ||
fresnel_t fresnel; | ||
ndf::ndf_traits<ndf_t> ndf; | ||
}; | ||
|
||
template <class IncomingRayDirInfo, class fresnel_t, class ndf_t> | ||
struct IsotropicCookTorrance : CookTorrance<fresnel_t, ndf_t, LightSample<IncomingRayDirInfo>, surface_interactions::Isotropic<IncomingRayDirInfo>, IsotropicMicrofacetCache> | ||
{ | ||
|
||
}; | ||
|
||
template <class IncomingRayDirInfo, class fresnel_t, class ndf_t> | ||
struct AnisotropicCookTorrance : CookTorrance<fresnel_t, ndf_t, LightSample<IncomingRayDirInfo>, surface_interactions::Anisotropic<IncomingRayDirInfo>, AnisotropicMicrofacetCache> | ||
{ | ||
|
||
}; | ||
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 sad that HLSL202x doesn't have SFINAE, because we could have just made isotropic and anisotropic the same struct and However we have inheritance, so we can make the base class Isotropic, and inherit to make the Anistropic and add that overload, not as clean but will do 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. but why? this completely messes up typedefs got from BxDFBase (always isotropic) 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, good observation. The thing is that an anisotropic BxDF should always be usable as an isotropic one (thanks to inheritance). Maybe the BxDFBase should be adjusted (sepearate typedefs for aniso and iso)? 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.
it kinda is, just pass the same values to |
||
|
||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -426,6 +426,32 @@ struct quotient_and_pdf | |
using quotient_and_pdf_scalar = quotient_and_pdf<float>; | ||
using quotient_and_pdf_rgb = quotient_and_pdf<float3>; | ||
|
||
|
||
// Utility class | ||
// Making it easier to conform your BxDFs to the concept | ||
template <class Spectrum, class Pdf, class Sample, class Interaction, class MicrofacetCache> | ||
struct BxDFBase | ||
{ | ||
// BxDFs must define such typenames: | ||
using spectrum_t = Spectrum; | ||
using pdf_t = Pdf; | ||
using q_pdf_t = quotient_and_pdf<spectrum_t>; | ||
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. improve my |
||
|
||
using sample_t = Sample; | ||
using interaction_t = Interaction; | ||
using cache_t = MicrofacetCache; | ||
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. sample should always be the same thing, cache should tell us the interaction (iso vs aniso) using sample_t = LightSample<ray_distribution_t>;
using interaction_t = MicrofacetCache::interaction_t<ray_distribution_t>;
using cache_t = MicrofacetCache; P.S. I'm not sure whether HLSL202x lets us define template aliases, please check add this into public:
template<class ray_distribution_t>
using interaction_t = surface_interactions::Anisotropic<ray_distribution_t>; if it doesn't then use similar trick on Isotropic 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 assumed it doesnt, i'll try to make sure 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. Move fast, break things, no docs = 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. yeah, HLSL supports templated |
||
|
||
/** | ||
* BxDFs (i.e. types derived from this base) must define following member functions: | ||
* | ||
* spectrum_t eval(in sample_t, in interaction_t, in cache_t); | ||
* | ||
* sample_t generate(in interaction_t, inout float3 u); | ||
* | ||
* q_pdf_t quotient_and_pdf(in sample_t, in interaction_t, in cache_t); | ||
*/ | ||
Comment on lines
+474
to
+475
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. @sunho can you suggest some function signatures for AOVs, I'm thinking using albedo_t = _albedo_t; // float3 default
using aov_transmittance_t = _aov_transmittance_t; // float3 default |
||
}; | ||
|
||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,6 +123,21 @@ float thindielectric_infinite_scatter(in float singleInterfaceReflectance) | |
return doubleInterfaceReflectance>0.9999 ? 1.0:((singleInterfaceReflectance-doubleInterfaceReflectance)/(1.0-doubleInterfaceReflectance)*2.0); | ||
} | ||
|
||
|
||
// Utility class | ||
template <class Spectrum> | ||
struct FresnelBase | ||
{ | ||
// Fresnels must define such typenames: | ||
using spectrum_t = Spectrum; | ||
|
||
/** | ||
* Fresnels must define following member functions: | ||
* | ||
* spectrum_t operator()(...); // TODO is there some paremeter list that can be universal for all fresnels ever needed? | ||
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. just the angle between a surface and a ray all the other stuff like IoR and so on will be member variables (this is why lambdas rule!) 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. so F0 in case of schlick would be a member as well right? 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.
Yes. ofc i remember, F0 is reflectance when the angle is 0 (dot product is 1) |
||
*/ | ||
}; | ||
|
||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
#ifndef _NBL_BUILTIN_HLSL_BXDF_NDF_COMMON_INCLUDED_ | ||
#define _NBL_BUILTIN_HLSL_BXDF_NDF_COMMON_INCLUDED_ | ||
|
||
#include <nbl/builtin/hlsl/bxdf/geom/smith/common.hlsl> | ||
|
||
namespace nbl | ||
{ | ||
|
@@ -56,6 +57,154 @@ float microfacet_to_light_measure_transform(in float NDFcos_already_in_reflectiv | |
|
||
} | ||
|
||
|
||
// Utility class | ||
template <class Scalar = float> | ||
struct NDFBase | ||
{ | ||
// NDFs must define such typenames: | ||
using scalar_t = Scalar; | ||
|
||
/** | ||
* NDFs must define such member functions: | ||
* | ||
* // Note that generation is always anisotropic, | ||
* // hence both interaction and microfacet cache must be anisotropic ones. | ||
* template <class IncomingrayDirInfo> | ||
* float3 generateH(in surface_interactions::Anisotropic<IncomingrayDirInfo>, inout float3 u, out AnisotropicMicrofacetCache); | ||
* | ||
* // isotropic NDF evaluators: | ||
* scalar_t D(in float NdotH2); | ||
* scalar_t Lambda(in float NdotX2); | ||
* | ||
* // anisotropic NDF evaluators: | ||
* scalar_t D(in float TdotH2, in float BdotH2, in float NdotH2); | ||
* scalar_t Lambda(in float TdotX2, in float BdotX2, in float NdotX2); | ||
*/ | ||
}; | ||
|
||
|
||
// forward declaration so we can explicitly specialize, e.g. for GGX where optimized forms of the functions provided by the trait exist | ||
template<class ndf_t> | ||
struct ndf_traits; | ||
|
||
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. this header needs to be renamed to |
||
namespace impl | ||
{ | ||
template<class ndf_t> | ||
struct ndf_traits | ||
{ | ||
using scalar_t = ndf_t::scalar_t; | ||
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. how much of all this will the GGX specialization also use? |
||
|
||
scalar_t G1(in float NdotX2) const { return scalar_t(1) / (scalar_t(1) + ndf.Lambda(NdotX2)); } | ||
scalar_t G2(in float NdotV2, in float NdotL2) const { return scalar_t(1) / (scalar_t(1) + ndf.Lambda(NdotV2) + ndf.Lambda(NdotL2)); } | ||
|
||
scalar_t G2_over_G1(in float NdotV2, in float NdotL2) const | ||
{ | ||
const scalar_t lambdaV_plus_one = ndf.Lambda(NdotV2) + scalar_t(1); | ||
return lambdaV_plus_one / (ndf.Lambda(NdotL2) + lambdaV_plus_one); | ||
} | ||
|
||
// | ||
// dHdL functions | ||
// | ||
// For BRDFs only: | ||
scalar_t dHdL(in float NDFcos, in float maxNdotV) | ||
{ | ||
return microfacet_to_light_measure_transform(NDFcos, maxNdotV); | ||
} | ||
// For all BxDFs: | ||
scalar_t dHdL(in float NDFcos, in float absNdotV, in bool transmitted, in float VdotH, in float LdotH, in float VdotHLdotH, in float orientedEta) | ||
{ | ||
return microfacet_to_light_measure_transform(NDFcos, absNdotV, transmitted, VdotH, LdotH, VdotHLdotH, orientedEta); | ||
} | ||
|
||
// | ||
// VNDF functions | ||
// | ||
// Statics: | ||
static scalar_t VNDF_static(in scalar_t d, in scalar_t lambda_V, in float maxNdotV, out onePlusLambda_V) | ||
{ | ||
return geom_smith::VNDF_pdf_wo_clamps(d, lambda_V, maxNdotV, onePlusLambda_V); | ||
} | ||
static scalar_t VNDF_static(in scalar_t d, in scalar_t lambda_V, in float absNdotV, in bool transmitted, in float VdotH, in float LdotH, in float VdotHLdotH, in float orientedEta, in float reflectance, out float onePlusLambda_V) | ||
{ | ||
return geom_smith::VNDF_pdf_wo_clamps(d, lambda_V.absNdotV, transmitted, VdotH, LdotH, VdotHLdotH, orientedEta, reflectance, onePlusLambda_V); | ||
} | ||
static scalar_t VNDF_static(in scalar_t d, in scalar_t G1_over_2NdotV) | ||
{ | ||
return geom_smith::VNDF_pdf_wo_clamps(d, G1_over_2NdotV); | ||
} | ||
|
||
static scalar_t VNDF_fromLambda_impl(in scalar_t d, in scalar_t lambda, in float maxNdotV) | ||
{ | ||
float dummy; | ||
return VNDF_static(d, lambda, maxNdotV, dummy); | ||
} | ||
static scalar_t VNDF_fromG1_over_2NdotV_impl(in scalar_t d, in scalar_t G1_over_2NdotV) | ||
{ | ||
return VNDF_static(d, G1_over_2NdotV); | ||
} | ||
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. inline as much as possible and get rid of the forwarding 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 do you mean by forwarding? 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. function with same parameters being called with no change just because its layering one API to another |
||
|
||
|
||
|
||
// VNDF isotropic variants | ||
scalar_t VNDF(in float NdotH2, in float NdotV2, in float maxNdotV) | ||
{ | ||
const float d = ndf.D(NdotH2); | ||
const float lambda = ndf.Lambda(NdotV2); | ||
return VNDF_fromLambda_impl(d, lambda, maxNdotV); | ||
} | ||
scalar_t VNDF(in float NdotH2, in float G1_over_2NdotV) | ||
{ | ||
const float d = ndf.D(NdotH2); | ||
return VNDF_fromG1_over_2NdotV_impl(d, G1_over_2NdotV); | ||
} | ||
scalar_t VNDF( | ||
in float NdotH2, in float NdotV2, | ||
in float absNdotV, in bool transmitted, in float VdotH, in float LdotH, in float VdotHLdotH, in float orientedEta, in float reflectance, out float onePlusLambda_V) | ||
{ | ||
const float d = ndf.D(NdotH2); | ||
const float lambda = ndf.Lambda(NdotV2); | ||
|
||
return VNDF_static(d, lambda, absNdotV, transmitted, VdotH, LdotH, VdotHLdotH, orientedEta, reflectance, onePlusLambda_V); | ||
} | ||
|
||
// VNDF anisotropic variants | ||
scalar_t VNDF( | ||
in float TdotH2, in float BdotH2, in float NdotH2, | ||
in float TdotV2, in float BdotV2, in float NdotV2, | ||
in float maxNdotV) | ||
{ | ||
const float d = ndf.D(TdotH2, BdotH2, NdotH2); | ||
const float lambda = ndf.Lambda(TdotV2, BdotV2, NdotV2); | ||
return VNDF_fromLambda_impl(d, lambda, maxNdotV); | ||
} | ||
scalar_t VNDF( | ||
in float TdotH2, in float BdotH2, in float NdotH2, | ||
in float G1_over_2NdotV) | ||
{ | ||
const float d = ndf.D(TdotH2, BdotH2, NdotH2); | ||
return VNDF_fromG1_over_2NdotV_impl(d, G1_over_2NdotV); | ||
} | ||
scalar_t VNDF( | ||
in float TdotH2, in float BdotH2, in float NdotH2, | ||
in float TdotV2, in float BdotV2, in float NdotV2, | ||
in float absNdotV, in bool transmitted, in float VdotH, in float LdotH, in float VdotHLdotH, in float orientedEta, in float reflectance, out float onePlusLambda_V) | ||
{ | ||
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. if it makes sense, delcare parameter structs in the |
||
const float d = ndf.D(TdotH2, BdotH2, NdotH2); | ||
const float lambda = ndf.Lambda(TdotV2, BdotV2, NdotV2); | ||
|
||
return VNDF_static(d, lambda, absNdotV, transmitted, VdotH, LdotH, VdotHLdotH, orientedEta, reflectance, onePlusLambda_V); | ||
} | ||
|
||
ndf_t ndf; | ||
}; | ||
} | ||
|
||
// default specialization | ||
template<class ndf_t> | ||
struct ndf_traits : impl::ndf_traits<ndf_t> {}; | ||
|
||
} | ||
} | ||
} | ||
|
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 we making
Sample
,Interaction
andMicrofacetCache
template parameters, I think only the RayDirDistribution ought to be one (which then goes into the interaction and sample)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.
but u dont know if u want isotropic or anisotropic interaction at this point
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.
btw could we make the
MicrofacetCache
's have ausing
typedef for thesurface_interaction
(iso vs aniso) it wants?