You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// plan on ignoring every transmission through the microfacets within the statistical pixel footprint as given by the VNDF except the perfectly specular one.
27
27
// The energy loss from that leads to pathologies like the glGTF Specular+Diffuse model, comparison: https://x.com/DS2LightingMod/status/1961502201228267595
28
28
//
29
-
// There's an implicit Top and Bottom on the layer stack, but thats only for the purpose of interpreting the Etas (predivided ratios of Indices of Refraction).
30
-
// We don't track the IoRs per layer because that would deprive us of the option to model each layer interface as a mixture of materials (metalness workflow).
31
-
//
32
-
// If you don't plan on ignoring the actual convolution of incoming light by the VNDF, such an assumption only speeds up the Importance Sampling slightly as
29
+
// If you don't plan on ignoring the actual convolution of incoming light by the BSDF, such an assumption only speeds up the Importance Sampling slightly as
33
30
// on the way back through a layer we don't consume another 2D random variable, instead transforming the ray deterministically. This however would require one
34
31
// to keep a stack of cached interactions with each layer, and its just simpler to run local path tracing through layers which can account for multiple scattering
35
32
// through a medium layer, etc.
36
33
//
34
+
// Our Frontend is built around the IR, which wants to perform the following canonicalization of a BSDF Layer (not including emission):
// Where `l(w_i,w_o)` is a Contributor Node BxDF such as Oren Nayar or Cook-Torrance, which is doesn't model absorption and is usually Monochrome.
39
+
// These are assumed to be 100% valid BxDFs with White Furnace Test <= 1 and obeying Helmholtz Reciprocity. This is why you can't multiply two "Contributor Nodes" together.
40
+
// We make an attempt to implement Energy Normalized versions of `l_i` but not always, so there might be energy loss due to single scattering assumptions.
41
+
//
42
+
// This convention greatly simplifies the Layering of BSDFs as when we model two layers combined we need only consider the Sum terms which are Products of a BTDF contibutor
43
+
// in convolution with the layer below or above. For emission this is equivalent to convolving the emission with BTDFs producing a custom emission profile.
44
+
// Some of these combinations can be approximated or solved outright without resolving to frequency space approaches or path tracing within the layers.
45
+
//
46
+
// To obtain a valid BxDF for the canonical expression, each product of weights also needs to exhibit Helmholtz Reciprocity:
// Which means that direction dependant weight nodes need to know the underlying contributor they are weighting to determine their semantics, e.g. a Fresnel on:
51
+
// - Cook Torrance will use the Microfacet Normal for any calculation as that is symmetric between `w_o` and `w_i`
52
+
// - Diffuse will use both `NdotV` and `NdotL` (also known as `theta_i` and `theta_o`) symmetrically
53
+
// - A BTDF will use the compliments (`1-x`) of the Fresnels
54
+
//
55
+
// We cannot derive BTDF factors from top and bottom BRDF as the problem is underconstrained, we don't know which factor models absorption and which part transmission.
56
+
//
57
+
// Helmholtz Reciprocity allows us to use completely independent BRDFs per hemisphere, when `w_i` and `w_o` are in the same hemisphere (reflection).
58
+
// Note that transmission only occurs when `w_i` and `w_o` are in opposite hemispheres and the reciprocity forces one BTDF.
59
+
//
60
+
// There's an implicit Top and Bottom on the layer stack, but thats only for the purpose of interpreting the Etas (predivided ratios of Indices of Refraction),
61
+
// both the Top and Bottom BRDF treat the Eta as being the speed of light in the medium above over the speed of light in the medium below.
62
+
// This means that for modelling air-vs-glass you use the same Eta for the Top BRDF, the middle BTDF and Bottom BRDF.
63
+
// We don't track the IoRs per layer because that would deprive us of the option to model each layer interface as a mixture of materials (metalness workflow).
64
+
//
65
+
// The backend can expand the Top BRDF, Middle BTDF, Bottom BRDF into 4 separate instruction streams for Front-Back BRDF and BTDF. This is because we can
66
+
// throw away the first or last BRDF+BTDF in the stack, as well as use different pre-computed Etas if we know the sign of `cos(theta_i)` as we interact with each layer.
67
+
// Whether the backend actually generates a separate instruction stream depends on the impact of Instruction Cache misses due to not sharing streams for layers.
68
+
//
69
+
// Also note that a single null BTDF in the stack splits it into the two separate stacks, one per original interaction orientation.
70
+
//
71
+
// I've considered expressing the layers using only a BTDF and BRDF (same top and bottom hemisphere) but that would lead to more layers in for materials,
72
+
// requiring the placing of a mirror then vantablack layer for most one-sided materials, and most importantly disallow the expression of certain front-back correlations.
73
+
//
37
74
// Because we implement Schussler et. al 2017 we also ensure that signs of dot products with shading normals are identical to smooth normals.
38
75
// However the smooth normals are not identical to geometric normals, we reserve the right to use the "normal pull up trick" to make them consistent.
39
76
// Schussler can't help with disparity of Smooth Normal and Geometric Normal, it turns smooth surfaces into glistening "disco balls" really outlining the
@@ -459,9 +496,11 @@ class CFrontendIR : public CNodePool
//! Special nodes meant to be used as `CMul::rhs`, as for the `N`, they use the normal used by the Leaf ContributorLeafs in its MUL node relative subgraph.
463
-
//! However if the Leaf BXDF is Cook Torrance, the microfacet `H` normal will be used instead.
464
-
//! If there are two BxDFs with different normals, these nodes get split and duplicated into two in our Final IR.
499
+
//! Special nodes meant to be used as `CMul::rhs`, their behaviour depends on the IContributor in its MUL node relative subgraph.
500
+
//! If you use a different contributor node type or normal for shading, these nodes get split and duplicated into two in our Final IR.
501
+
//! Due to the Helmholtz Reciprocity handling outlined in the comments for the entire front-end you can usually count on these nodes
502
+
//! getting applied once using `VdotH` for Cook-Torrance BRDF, twice using `VdotN` and `LdotN` for Diffuse BRDF, and using their
// if you want to reuse the same parameter but want to flip the interfaces around
506
545
uint8_t reciprocateEtas : 1 = false;
@@ -512,7 +551,7 @@ class CFrontendIR : public CNodePool
512
551
};
513
552
// @kept_secret TODO: Thin Film Interference Fresnel
514
553
//! Basic BxDF nodes
515
-
// Every BxDF leaf node is supposed to pass WFT test, color and extinction is added on later via multipliers
554
+
// Every BxDF leaf node is supposed to pass WFT test and must not create energy, color and extinction is added on later via multipliers
516
555
classIBxDF : publicIContributor
517
556
{
518
557
public:
@@ -547,10 +586,10 @@ class CFrontendIR : public CNodePool
547
586
// Delta Transmission is the only Special Delta Distribution Node, because of how useful it is for compiling Anyhit shaders, the rest can be done easily with:
548
587
// - Delta Reflection -> Any Cook Torrance BxDF with roughness=0 attached as BRDF
549
588
// - Smooth Conductor -> above multiplied with Conductor-Fresnel
550
-
// - Smooth Dielectric -> Any Cook Torrance BxDF with roughness=0 attached as BRDF on both sides (bottom side having a reciprocated Eta) of a Layer and BTDF multiplied with Dielectric-Fresnel (no imaginary component)
551
-
// - Thindielectric -> Any Cook Torrance BxDF multiplied with Dielectric-Fresnel as BRDF in both sides and a Delta Transmission BTDF
552
-
// - Plastic -> Can layer the above over Diffuse BRDF, but its faster to cook a mixture of Diffuse and Smooth Conductor BRDFs, weighing the diffuse by Fresnel complements.
553
-
//If one wants to emulate non-linear diffuse TIR color shifts, abuse `CThinInfiniteScatterCorrection`
589
+
// - Smooth Dielectric -> Any Cook Torrance BxDF with roughness=0 attached as BRDF on both sides of a Layer and BTDF multiplied with Dielectric-Fresnel (no imaginary component)
590
+
// - Thindielectric -> Any Cook Torrance BxDF multiplied with Dielectric-Fresnel as BRDF in both sides and a Delta Transmission BTDF with `CThinInfiniteScatterCorrection` on the fresnel
591
+
// - Plastic -> Similar to layering the above over Diffuse BRDF, its of uttmost importance that the BTDF is Delta Transmission.
592
+
//If one wants to emulate non-linear diffuse TIR color shifts, abuse `CThinInfiniteScatterCorrection`.
554
593
classCDeltaTransmissionfinal : public IBxDF
555
594
{
556
595
public:
@@ -566,7 +605,8 @@ class CFrontendIR : public CNodePool
args.logger.log("Oriented Real Eta node of correct type must be attached, but is %u of type %s",ELL_ERROR,orientedRealEta,args.pool->getTypeName(orientedRealEta).data());
43
43
returntrue;
44
44
}
45
-
if (!args.pool->deref(orientedImagEta))
45
+
if (constauto imagEta = args.pool->deref(orientedImagEta); imagEta)
46
+
{
47
+
if (args.isBTDF)
48
+
{
49
+
constauto knotCount = imagEta->getKnotCount();
50
+
// TODO: check all knots have a scale of 0
51
+
}
52
+
}
53
+
else
46
54
{
47
55
args.logger.log("Oriented Imaginary Eta node of correct type must be attached, but is %u of type %s",ELL_ERROR,orientedImagEta,args.pool->getTypeName(orientedImagEta).data());
0 commit comments