Skip to content
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

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
d3f4169
Add files via upload
nahiim Nov 7, 2022
95cc93f
Update animtation.hlsl
nahiim Nov 7, 2022
507b1a6
Update keyframe.hlsl
nahiim Nov 7, 2022
bcb9f77
Update node.hlsl
nahiim Nov 7, 2022
8e61632
Create algorithm.hlsl
devshgraphicsprogramming Nov 7, 2022
b9b29d2
Add files via upload
nahiim Nov 7, 2022
6d7e989
Delete animtation.hlsl
nahiim Nov 7, 2022
6c24d2c
Update node.hlsl
nahiim Nov 7, 2022
ef4f253
Add files via upload
nahiim Nov 7, 2022
b89cad1
Delete node.hlsl
nahiim Nov 7, 2022
c964e09
Add files via upload
nahiim Nov 7, 2022
bb088e9
Update keyframe.hlsl
nahiim Nov 7, 2022
5aac44b
Create scanning_append.hlsl
devshgraphicsprogramming Nov 7, 2022
01fd600
Create common.hlsl
devshgraphicsprogramming Nov 8, 2022
3671194
Create transmission.hlsl
devshgraphicsprogramming Nov 8, 2022
605f3c4
Create reflection.hlsl
devshgraphicsprogramming Nov 8, 2022
2a91a80
Add `quotient_and_pdf` struct and `transmit/reflect` to RayDirInfo co…
devshgraphicsprogramming Nov 8, 2022
6ac724b
Transmission need not know about `nbl::hlsl::reflect`
devshgraphicsprogramming Nov 8, 2022
de66abf
Implement some of Microfacet Caches, missing valid by construction
devshgraphicsprogramming Nov 8, 2022
3bcd088
Implement anisotropic cache valid by construction
devshgraphicsprogramming Nov 8, 2022
2e65bbc
brdf
nahiim Nov 9, 2022
cc39ce3
geom smith
nahiim Nov 9, 2022
9f18406
fixed minor math blunder
nahiim Nov 9, 2022
bfc2143
...
nahiim Nov 9, 2022
8a4eda4
add 3rdparty/dxc/dxc submodule
AnastaZIuk Nov 10, 2022
f9da966
update 3rdparty/dxc/dxc submodule with dxcompiler target fix
AnastaZIuk Nov 10, 2022
c80b0e9
Shapes and ieee754
nahiim Nov 10, 2022
321b252
numeric_limits
nahiim Nov 10, 2022
b5d3a4c
colorspace_EOTF
nahiim Nov 11, 2022
47e3e4c
update dxc submodule with adding clang library correction, add dxc to…
AnastaZIuk Nov 11, 2022
a9841d1
make DXC compile with Nabla's BS via external project
AnastaZIuk Nov 11, 2022
9af73f8
Merge branch 'hlsl' of github.com:Devsh-Graphics-Programming/Nabla in…
AnastaZIuk Nov 11, 2022
4ecbd7c
colorspace completed
nahiim Nov 11, 2022
8eec0c0
fixed typos
nahiim Nov 12, 2022
e644e74
Create HLSL_NABLA_COMPILE_TEST target for compile-testing Nabla's new…
AnastaZIuk Nov 12, 2022
8135e46
Find a way to clean environment for clear DXC compilation, make sure …
AnastaZIuk Nov 13, 2022
4712763
link dxcompiler library to Nabla
AnastaZIuk Nov 13, 2022
a215ee3
add dxc as dependency of HLSL_NABLA_COMPILE_TEST
AnastaZIuk Nov 13, 2022
9dd660f
math
nahiim Nov 14, 2022
255f8e8
maths
nahiim Nov 14, 2022
42b19d7
Merge remote-tracking branch 'origin/hlsl' into local_hlsl
nahiim Nov 14, 2022
95e9e2d
Merge remote-tracking branch 'origin/dxcIntegration' into local_hlsl
nahiim Nov 14, 2022
f01eeee
minor fixes
nahiim Nov 15, 2022
cbf8d71
automated HLSL compilation
nahiim Nov 15, 2022
1990c18
complex and constants
nahiim Nov 17, 2022
953b681
math completed
nahiim Nov 21, 2022
7011441
shapes completed
nahiim Nov 23, 2022
a09b8ef
create random/xoroshiro.hlsl
nahiim Nov 24, 2022
d5e3189
porting hlsl/utils
nahiim Nov 29, 2022
b3a17c9
add hlsl/utils/culling
nahiim Dec 2, 2022
47c82ce
add morton, normal_encode, normal_decode, culling
nahiim Dec 6, 2022
f037e69
utils
nahiim Dec 7, 2022
5f70cca
surface_transform finishing
nahiim Dec 8, 2022
67b22f0
add utils/transform
nahiim Dec 9, 2022
9cfc8fb
update transform.hlsl
nahiim Dec 10, 2022
0efa057
utils, loader, property_pool, blit
nahiim Dec 31, 2022
9720334
Seems like all BRDF functions are ported to HLSL and compiling ok
Crisspl Mar 11, 2023
bb6ec81
ported bsdf functions to HLSL
Crisspl Mar 17, 2023
52589d2
Reworked & renamed bxdf functions to _quotient_and_pdf convention
Crisspl Mar 21, 2023
e2daa63
HLSL BxDF concepts design: common bxdf classes
Crisspl Mar 22, 2023
6853d83
HLSL BxDF concepts design: some work done on NDFs
Crisspl Mar 28, 2023
a49760c
Typo and missing create() for blinnphong
Crisspl Mar 29, 2023
758a390
Fresnels
Crisspl Mar 29, 2023
5e2bf89
Diffuse BxDFs
Crisspl Mar 29, 2023
915ef27
Generic CookTorrance BRDF implementation
Crisspl Mar 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions include/nbl/builtin/hlsl/bxdf/brdf/specular/common.hlsl
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>

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 and MicrofacetCache template parameters, I think only the RayDirDistribution ought to be one (which then goes into the interaction and sample)

Copy link
Collaborator Author

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

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 a using typedef for the surface_interaction (iso vs aniso) it wants?

{
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>
{

};

Choose a reason for hiding this comment

The 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 enable_if-ed the anisotropic interaction overload

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

Copy link
Collaborator Author

@Crisspl Crisspl Mar 23, 2023

Choose a reason for hiding this comment

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

but why? this completely messes up typedefs got from BxDFBase (always isotropic)

Choose a reason for hiding this comment

The 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)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The thing is that an anisotropic BxDF should always be usable as an isotropic one (thanks to inheritance).

it kinda is, just pass the same values to ax and ay, it's just going longer way to compute the result. Which should be assumed, since you've intentionally chosen anisotropic (more generic) variant


}
}
}
}
}

#endif
3 changes: 1 addition & 2 deletions include/nbl/builtin/hlsl/bxdf/bsdf/specular/beckmann.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,12 @@ quotient_and_pdf_scalar beckmann_cos_quotient_and_pdf(in LightSample<IncomingRay
return beckmann_cos_quotient_and_pdf_wo_clamps(ndf, transmitted, _sample.NdotL2, absNdotV, interaction.NdotV_squared, _cache.VdotH, _cache.LdotH, VdotHLdotH, reflectance, orientedEta, a2);
}


quotient_and_pdf_scalar beckmann_aniso_dielectric_cos_quotient_and_pdf_wo_clamps(in float ndf, in bool transmitted, in float NdotL2, in float TdotL2, in float BdotL2, in float absNdotV, in float TdotV2, in float BdotV2, in float NdotV2, in float VdotH, in float LdotH, in float VdotHLdotH, in float reflectance, in float orientedEta, in float ax2, in float ay2)
{
float onePlusLambda_V;
const float pdf = beckmann_pdf_wo_clamps(transmitted,reflectance, ndf,absNdotV,TdotV2,BdotV2,NdotV2, VdotH,LdotH,VdotHLdotH, ax2,ay2,orientedEta,onePlusLambda_V);

return quotient_and_pdf_scalar::create( geom_smith::beckmann::G2_over_G1(onePlusLambda_V, TdotL2, BdotL2, NdotL2, ax2, ay2), pdf );
return quotient_and_pdf_scalar::create( geom_smith::beckmann::G2_over_G1(onePlusLambda_V, TdotL2, BdotL2, NdotL2, ax2, ay2 + d.x), pdf );
}
template <class IncomingRayDirInfo>
quotient_and_pdf_scalar beckmann_aniso_dielectric_cos_quotient_and_pdf(in LightSample<IncomingRayDirInfo> _sample, in surface_interactions::Anisotropic<IncomingRayDirInfo> interaction, in AnisotropicMicrofacetCache _cache, in float eta, in float ax, in float ay)
Expand Down
26 changes: 26 additions & 0 deletions include/nbl/builtin/hlsl/bxdf/common.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Choose a reason for hiding this comment

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

improve my quotient_and_pdf to take a pdf_t


using sample_t = Sample;
using interaction_t = Interaction;
using cache_t = MicrofacetCache;

Choose a reason for hiding this comment

The 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 AnisotropicMicrofacetCache and see if DXC chokes on this when actually used:

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure whether HLSL202x lets us define template aliases

i assumed it doesnt, i'll try to make sure
its a pity hlsl2021 has no spec XD the only way to check things is to write code and see what dxc spits out

Choose a reason for hiding this comment

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

Move fast, break things, no docs = the Nabla DirectX way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah, HLSL supports templated using statements for typedefs/aliases


/**
* 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

Choose a reason for hiding this comment

The 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

};

}
}
}
Expand Down
15 changes: 15 additions & 0 deletions include/nbl/builtin/hlsl/bxdf/fresnel.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Choose a reason for hiding this comment

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

just the angle between a surface and a ray cosTheta

all the other stuff like IoR and so on will be member variables (this is why lambdas rule!)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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?
btw do you remember what f0 actually was?

Choose a reason for hiding this comment

The 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? btw do you remember what f0 actually was?

Yes.

ofc i remember, F0 is reflectance when the angle is 0 (dot product is 1)

*/
};

}
}
}
Expand Down
4 changes: 4 additions & 0 deletions include/nbl/builtin/hlsl/bxdf/geom/smith/common.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ float G1(in float lambda)
return 1.0 / (1.0 + lambda);
}

float G2(in float lambda_V, in float lambda_L)
{
return 1.0 / (1.0 + lambda_V + lambda_L);
}


float VNDF_pdf_wo_clamps(in float ndf, in float lambda_V, in float maxNdotV, out float onePlusLambda_V)
Expand Down
149 changes: 149 additions & 0 deletions include/nbl/builtin/hlsl/bxdf/ndf/common.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;

Choose a reason for hiding this comment

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

this header needs to be renamed to ndf.hlsl and be a level up, then in this very place you need to include all the other NDFs so their specializations have a chance to appear before the default one

namespace impl
{
template<class ndf_t>
struct ndf_traits
{
using scalar_t = ndf_t::scalar_t;

Choose a reason for hiding this comment

The 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);
}

Choose a reason for hiding this comment

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

inline as much as possible and get rid of the forwarding

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

what do you mean by forwarding?

Choose a reason for hiding this comment

The 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)
{

Choose a reason for hiding this comment

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

if it makes sense, delcare parameter structs in the bxdf namespace for the ndf functions and gather some of these inputs together, right now its tedious to read and typo prone (many parameters have the same type, you'll die)

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> {};

}
}
}
Expand Down