Skip to content

Commit 5819d39

Browse files
now the code is DRY
1 parent 6b6f746 commit 5819d39

File tree

4 files changed

+132
-234
lines changed

4 files changed

+132
-234
lines changed

examples_tests/42.FragmentShaderPathTracer/common.glsl

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,124 @@ nbl_glsl_LightSample nbl_glsl_light_generate_and_remainder_and_pdf(out vec3 rema
533533
return nbl_glsl_createLightSample(L,interaction);
534534
}
535535

536+
uint getBSDFLightIDAndDetermineNormal(out vec3 normal, in uint objectID, in vec3 intersection);
537+
bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nbl_glsl_xoroshiro64star_state_t scramble_state)
538+
{
539+
const MutableRay_t _mutable = ray._mutable;
540+
const uint objectID = _mutable.objectID;
541+
542+
// interaction stuffs
543+
const ImmutableRay_t _immutable = ray._immutable;
544+
const vec3 intersection = _immutable.origin+_immutable.direction*_mutable.intersectionT;
545+
546+
uint bsdfLightIDs;
547+
nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
548+
{
549+
nbl_glsl_IsotropicViewSurfaceInteraction isotropic;
550+
bsdfLightIDs = getBSDFLightIDAndDetermineNormal(isotropic.N,objectID,intersection);
551+
552+
isotropic.V.dir = -_immutable.direction;
553+
//isotropic.V.dPosdScreen = screw that
554+
isotropic.NdotV = dot(isotropic.V.dir,isotropic.N);
555+
isotropic.NdotV_squared = isotropic.NdotV*isotropic.NdotV;
556+
557+
interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
558+
}
559+
560+
//
561+
vec3 throughput = ray._payload.throughput;
562+
563+
// add emissive and finish MIS
564+
const uint lightID = bitfieldExtract(bsdfLightIDs,16,16);
565+
if (lightID != INVALID_ID_16BIT) // has emissive
566+
{
567+
float lightPdf;
568+
ray._payload.accumulation += nbl_glsl_light_deferred_eval_and_prob(lightPdf,lights[lightID],ray)*throughput/(1.0+lightPdf*lightPdf*ray._payload.otherTechniqueHeuristic);
569+
}
570+
571+
// check if we even have a BSDF at all
572+
uint bsdfID = bitfieldExtract(bsdfLightIDs, 0, 16);
573+
if (bsdfID != INVALID_ID_16BIT)
574+
{
575+
BSDFNode bsdf = bsdfs[bsdfID];
576+
#ifdef KILL_DIFFUSE_SPECULAR_PATHS
577+
if (BSDFNode_isNotDiffuse(bsdf))
578+
{
579+
if (ray._payload.hasDiffuse)
580+
return true;
581+
}
582+
else
583+
ray._payload.hasDiffuse = true;
584+
#endif
585+
586+
const bool isBSDF = BSDFNode_isBSDF(bsdf);
587+
//rand
588+
mat2x3 epsilon = rand3d(depth,_sample,scramble_state);
589+
590+
// thresholds
591+
const float bsdfPdfThreshold = 0.0001;
592+
const float lumaContributionThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3(1.0)/255.0)); // OETF smallest perceptible value
593+
const vec3 throughputCIE_Y = transpose(nbl_glsl_sRGBtoXYZ)[1]*throughput;
594+
const float monochromeEta = dot(throughputCIE_Y,BSDFNode_getEta(bsdf)[0])/(throughputCIE_Y.r+throughputCIE_Y.g+throughputCIE_Y.b);
536595

537-
bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nbl_glsl_xoroshiro64star_state_t scramble_state);
596+
// do NEE
597+
const float neeSkipProbability = BSDFNode_getNEESkipProb(bsdf);
598+
float rcpChoiceProb;
599+
if (nbl_glsl_partitionRandVariable(neeSkipProbability, epsilon[0].z, rcpChoiceProb))
600+
{
601+
vec3 neeContrib; float lightPdf, t;
602+
nbl_glsl_LightSample nee_sample = nbl_glsl_light_generate_and_remainder_and_pdf(
603+
neeContrib, lightPdf, t,
604+
intersection, interaction,
605+
isBSDF, epsilon[0], depth
606+
);
607+
// We don't allow non watertight transmitters in this renderer
608+
bool validPath = nee_sample.NdotL>0.0;
609+
// but if we allowed non-watertight transmitters (single water surface), it would make sense just to apply this line by itself
610+
nbl_glsl_AnisotropicMicrofacetCache _cache;
611+
validPath = validPath && nbl_glsl_calcAnisotropicMicrofacetCache(_cache, interaction, nee_sample, monochromeEta);
612+
if (validPath)
613+
{
614+
float bsdfPdf;
615+
neeContrib *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,nee_sample,interaction,bsdf,monochromeEta,_cache)*throughput;
616+
const float oc = bsdfPdf*rcpChoiceProb;
617+
neeContrib /= 1.0/oc+oc/(lightPdf*lightPdf); // MIS weight
618+
if (bsdfPdf<FLT_MAX && getLuma(neeContrib)>lumaContributionThreshold && traceRay(t,intersection+nee_sample.L*t*getStartTolerance(depth),nee_sample.L)==-1)
619+
ray._payload.accumulation += neeContrib;
620+
}
621+
}
622+
623+
// sample BSDF
624+
float bsdfPdf; vec3 bsdfSampleL;
625+
{
626+
nbl_glsl_AnisotropicMicrofacetCache _cache;
627+
nbl_glsl_LightSample bsdf_sample = nbl_glsl_bsdf_cos_generate(interaction,epsilon[1],bsdf,monochromeEta,_cache);
628+
// the value of the bsdf divided by the probability of the sample being generated
629+
throughput *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,bsdf_sample,interaction,bsdf,monochromeEta,_cache);
630+
//
631+
bsdfSampleL = bsdf_sample.L;
632+
}
633+
634+
// additional threshold
635+
const float lumaThroughputThreshold = lumaContributionThreshold;
636+
if (bsdfPdf>bsdfPdfThreshold && getLuma(throughput)>lumaThroughputThreshold)
637+
{
638+
ray._payload.throughput = throughput;
639+
ray._payload.otherTechniqueHeuristic = (1.0-neeSkipProbability)/bsdfPdf; // numerically stable, don't touch
640+
ray._payload.otherTechniqueHeuristic *= ray._payload.otherTechniqueHeuristic;
641+
642+
// trace new ray
643+
ray._immutable.origin = intersection+bsdfSampleL*(1.0/*kSceneSize*/)*getStartTolerance(depth);
644+
ray._immutable.direction = bsdfSampleL;
645+
#if POLYGON_METHOD==2
646+
ray._immutable.normalAtOrigin = interaction.isotropic.N;
647+
ray._immutable.wasBSDFAtOrigin = isBSDF;
648+
#endif
649+
return true;
650+
}
651+
}
652+
return false;
653+
}
538654

539655
void main()
540656
{

examples_tests/42.FragmentShaderPathTracer/litBySphere.frag

Lines changed: 4 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -52,113 +52,9 @@ vec3 nbl_glsl_light_generate_and_pdf(out float pdf, out float newRayMaxT, in vec
5252
return vec3(0.0,0.0,0.0);
5353
}
5454

55-
56-
bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nbl_glsl_xoroshiro64star_state_t scramble_state)
55+
uint getBSDFLightIDAndDetermineNormal(out vec3 normal, in uint objectID, in vec3 intersection)
5756
{
58-
const MutableRay_t _mutable = ray._mutable;
59-
60-
Sphere sphere = spheres[_mutable.objectID];
61-
62-
// interaction stuffs
63-
const vec3 intersection = ray._immutable.origin+ray._immutable.direction*_mutable.intersectionT;
64-
nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
65-
{
66-
nbl_glsl_IsotropicViewSurfaceInteraction isotropic;
67-
68-
isotropic.V.dir = -ray._immutable.direction;
69-
//isotropic.V.dPosdScreen = screw that
70-
isotropic.N = Sphere_getNormal(sphere,intersection);
71-
isotropic.NdotV = dot(isotropic.V.dir,isotropic.N);
72-
isotropic.NdotV_squared = isotropic.NdotV*isotropic.NdotV;
73-
74-
interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
75-
}
76-
77-
//
78-
const uint bsdfLightIDs = sphere.bsdfLightIDs;
79-
80-
//
81-
vec3 throughput = ray._payload.throughput;
82-
83-
// add emissive and finish MIS
84-
const uint lightID = bitfieldExtract(bsdfLightIDs,16,16);
85-
if (lightID!=INVALID_ID_16BIT) // has emissive
86-
{
87-
float lightPdf;
88-
ray._payload.accumulation += nbl_glsl_light_deferred_eval_and_prob(lightPdf,lights[lightID],ray)*throughput/(1.0+lightPdf*lightPdf*ray._payload.otherTechniqueHeuristic);
89-
}
90-
91-
// check if we even have a BSDF at all
92-
uint bsdfID = bitfieldExtract(bsdfLightIDs,0,16);
93-
if (bsdfID!=INVALID_ID_16BIT)
94-
{
95-
BSDFNode bsdf = bsdfs[bsdfID];
96-
#ifdef KILL_DIFFUSE_SPECULAR_PATHS
97-
if (BSDFNode_isNotDiffuse(bsdf))
98-
{
99-
if (ray._payload.hasDiffuse)
100-
return true;
101-
}
102-
else
103-
ray._payload.hasDiffuse = true;
104-
#endif
105-
106-
//rand
107-
mat2x3 epsilon = rand3d(depth,_sample,scramble_state);
108-
109-
// thresholds
110-
const float bsdfPdfThreshold = 0.0001;
111-
const float lumaContributionThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3(1.0)/255.0)); // OETF smallest perceptible value
112-
const vec3 throughputCIE_Y = transpose(nbl_glsl_sRGBtoXYZ)[1]*throughput;
113-
const float monochromeEta = dot(throughputCIE_Y,BSDFNode_getEta(bsdf)[0])/(throughputCIE_Y.r+throughputCIE_Y.g+throughputCIE_Y.b);
114-
115-
// do NEE
116-
const float neeSkipProbability = BSDFNode_getNEESkipProb(bsdf);
117-
float rcpChoiceProb;
118-
if (nbl_glsl_partitionRandVariable(neeSkipProbability,epsilon[0].z,rcpChoiceProb))
119-
{
120-
vec3 neeContrib; float lightPdf, t;
121-
nbl_glsl_LightSample nee_sample = nbl_glsl_light_generate_and_remainder_and_pdf(neeContrib,lightPdf,t,intersection,interaction,false,epsilon[0],depth);
122-
// We don't allow non watertight transmitters in this renderer
123-
bool validPath = nee_sample.NdotL>0.0;
124-
// but if we allowed non-watertight transmitters (single water surface), it would make sense just to apply this line by itself
125-
nbl_glsl_AnisotropicMicrofacetCache _cache;
126-
validPath = validPath && nbl_glsl_calcAnisotropicMicrofacetCache(_cache,interaction,nee_sample,monochromeEta);
127-
if (validPath)
128-
{
129-
float bsdfPdf;
130-
neeContrib *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,nee_sample,interaction,bsdf,monochromeEta,_cache)*throughput;
131-
const float oc = bsdfPdf*rcpChoiceProb;
132-
neeContrib /= 1.0/oc+oc/(lightPdf*lightPdf); // MIS weight
133-
if (bsdfPdf<FLT_MAX && getLuma(neeContrib)>lumaContributionThreshold && traceRay(t,intersection+nee_sample.L*t*getStartTolerance(depth),nee_sample.L)==-1)
134-
ray._payload.accumulation += neeContrib;
135-
}
136-
}
137-
138-
// sample BSDF
139-
float bsdfPdf; vec3 bsdfSampleL;
140-
{
141-
nbl_glsl_AnisotropicMicrofacetCache _cache;
142-
nbl_glsl_LightSample bsdf_sample = nbl_glsl_bsdf_cos_generate(interaction,epsilon[1],bsdf,monochromeEta,_cache);
143-
// the value of the bsdf divided by the probability of the sample being generated
144-
throughput *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,bsdf_sample,interaction,bsdf,monochromeEta,_cache);
145-
//
146-
bsdfSampleL = bsdf_sample.L;
147-
}
148-
149-
// additional threshold
150-
const float lumaThroughputThreshold = lumaContributionThreshold;
151-
if (bsdfPdf>bsdfPdfThreshold && getLuma(throughput)>lumaThroughputThreshold)
152-
{
153-
ray._payload.throughput = throughput;
154-
ray._payload.otherTechniqueHeuristic = (1.0-neeSkipProbability)/bsdfPdf; // numerically stable, don't touch
155-
ray._payload.otherTechniqueHeuristic *= ray._payload.otherTechniqueHeuristic;
156-
157-
// trace new ray
158-
ray._immutable.origin = intersection+bsdfSampleL*(1.0/*kSceneSize*/)*getStartTolerance(depth);
159-
ray._immutable.direction = bsdfSampleL;
160-
return true;
161-
}
162-
}
163-
return false;
57+
Sphere sphere = spheres[objectID];
58+
normal = Sphere_getNormal(sphere,intersection);
59+
return sphere.bsdfLightIDs;
16460
}

examples_tests/42.FragmentShaderPathTracer/litByTriangle.frag

Lines changed: 10 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#extension GL_GOOGLE_include_directive : require
77

88
#define SPHERE_COUNT 8
9-
#define POLYGON_METHOD 0 // 0 area sampling, 1 solid angle sampling, 2 approximate projected solid angle sampling
9+
#define POLYGON_METHOD 2 // 0 area sampling, 1 solid angle sampling, 2 approximate projected solid angle sampling
1010
#include "common.glsl"
1111

1212
#define TRIANGLE_COUNT 1
@@ -87,132 +87,18 @@ vec3 nbl_glsl_light_generate_and_pdf(out float pdf, out float newRayMaxT, in vec
8787
}
8888

8989

90-
bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nbl_glsl_xoroshiro64star_state_t scramble_state)
90+
uint getBSDFLightIDAndDetermineNormal(out vec3 normal, in uint objectID, in vec3 intersection)
9191
{
92-
const MutableRay_t _mutable = ray._mutable;
93-
94-
const uint objectID = _mutable.objectID;
95-
Sphere sphere = spheres[_mutable.objectID];
96-
97-
// interaction stuffs
98-
const ImmutableRay_t _immutable = ray._immutable;
99-
const vec3 intersection = _immutable.origin+_immutable.direction*_mutable.intersectionT;
100-
uint bsdfLightIDs;
101-
nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
92+
if (objectID<SPHERE_COUNT)
10293
{
103-
nbl_glsl_IsotropicViewSurfaceInteraction isotropic;
104-
105-
isotropic.V.dir = -_immutable.direction;
106-
//isotropic.V.dPosdScreen = screw that
107-
if (objectID<SPHERE_COUNT)
108-
{
109-
Sphere sphere = spheres[objectID];
110-
isotropic.N = Sphere_getNormal(sphere,intersection);
111-
bsdfLightIDs = sphere.bsdfLightIDs;
112-
}
113-
else
114-
{
115-
Triangle tri = triangles[objectID-SPHERE_COUNT];
116-
isotropic.N = normalize(Triangle_getNormalTimesArea(tri));
117-
bsdfLightIDs = tri.bsdfLightIDs;
118-
}
119-
isotropic.NdotV = dot(isotropic.V.dir,isotropic.N);
120-
isotropic.NdotV_squared = isotropic.NdotV*isotropic.NdotV;
121-
122-
interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
94+
Sphere sphere = spheres[objectID];
95+
normal = Sphere_getNormal(sphere,intersection);
96+
return sphere.bsdfLightIDs;
12397
}
124-
125-
//
126-
vec3 throughput = ray._payload.throughput;
127-
128-
// add emissive and finish MIS
129-
const uint lightID = bitfieldExtract(bsdfLightIDs,16,16);
130-
if (lightID!=INVALID_ID_16BIT) // has emissive
98+
else
13199
{
132-
float lightPdf;
133-
ray._payload.accumulation += nbl_glsl_light_deferred_eval_and_prob(lightPdf,lights[lightID],ray)*throughput/(1.0+lightPdf*lightPdf*ray._payload.otherTechniqueHeuristic);
134-
}
135-
136-
// check if we even have a BSDF at all
137-
uint bsdfID = bitfieldExtract(bsdfLightIDs,0,16);
138-
if (bsdfID!=INVALID_ID_16BIT)
139-
{
140-
BSDFNode bsdf = bsdfs[bsdfID];
141-
#ifdef KILL_DIFFUSE_SPECULAR_PATHS
142-
if (BSDFNode_isNotDiffuse(bsdf))
143-
{
144-
if (ray._payload.hasDiffuse)
145-
return true;
146-
}
147-
else
148-
ray._payload.hasDiffuse = true;
149-
#endif
150-
151-
const bool isBSDF = BSDFNode_isBSDF(bsdf);
152-
//rand
153-
mat2x3 epsilon = rand3d(depth,_sample,scramble_state);
154-
155-
// thresholds
156-
const float bsdfPdfThreshold = 0.0001;
157-
const float lumaContributionThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3(1.0)/255.0)); // OETF smallest perceptible value
158-
const vec3 throughputCIE_Y = transpose(nbl_glsl_sRGBtoXYZ)[1]*throughput;
159-
const float monochromeEta = dot(throughputCIE_Y,BSDFNode_getEta(bsdf)[0])/(throughputCIE_Y.r+throughputCIE_Y.g+throughputCIE_Y.b);
160-
161-
// do NEE
162-
const float neeSkipProbability = BSDFNode_getNEESkipProb(bsdf);
163-
float rcpChoiceProb;
164-
if (nbl_glsl_partitionRandVariable(neeSkipProbability,epsilon[0].z,rcpChoiceProb))
165-
{
166-
vec3 neeContrib; float lightPdf, t;
167-
nbl_glsl_LightSample nee_sample = nbl_glsl_light_generate_and_remainder_and_pdf(
168-
neeContrib,lightPdf,t,
169-
intersection,interaction,
170-
isBSDF,epsilon[0],depth
171-
);
172-
// We don't allow non watertight transmitters in this renderer
173-
bool validPath = nee_sample.NdotL>0.0;
174-
// but if we allowed non-watertight transmitters (single water surface), it would make sense just to apply this line by itself
175-
nbl_glsl_AnisotropicMicrofacetCache _cache;
176-
validPath = validPath && nbl_glsl_calcAnisotropicMicrofacetCache(_cache,interaction,nee_sample,monochromeEta);
177-
if (validPath)
178-
{
179-
float bsdfPdf;
180-
neeContrib *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,nee_sample,interaction,bsdf,monochromeEta,_cache)*throughput;
181-
const float oc = bsdfPdf*rcpChoiceProb;
182-
neeContrib /= 1.0/oc+oc/(lightPdf*lightPdf); // MIS weight
183-
if (bsdfPdf<FLT_MAX && getLuma(neeContrib)>lumaContributionThreshold && traceRay(t,intersection+nee_sample.L*t*getStartTolerance(depth),nee_sample.L)==-1)
184-
ray._payload.accumulation += neeContrib;
185-
}
186-
}
187-
188-
// sample BSDF
189-
float bsdfPdf; vec3 bsdfSampleL;
190-
{
191-
nbl_glsl_AnisotropicMicrofacetCache _cache;
192-
nbl_glsl_LightSample bsdf_sample = nbl_glsl_bsdf_cos_generate(interaction,epsilon[1],bsdf,monochromeEta,_cache);
193-
// the value of the bsdf divided by the probability of the sample being generated
194-
throughput *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,bsdf_sample,interaction,bsdf,monochromeEta,_cache);
195-
//
196-
bsdfSampleL = bsdf_sample.L;
197-
}
198-
199-
// additional threshold
200-
const float lumaThroughputThreshold = lumaContributionThreshold;
201-
if (bsdfPdf>bsdfPdfThreshold && getLuma(throughput)>lumaThroughputThreshold)
202-
{
203-
ray._payload.throughput = throughput;
204-
ray._payload.otherTechniqueHeuristic = (1.0-neeSkipProbability)/bsdfPdf; // numerically stable, don't touch
205-
ray._payload.otherTechniqueHeuristic *= ray._payload.otherTechniqueHeuristic;
206-
207-
// trace new ray
208-
ray._immutable.origin = intersection+bsdfSampleL*(1.0/*kSceneSize*/)*getStartTolerance(depth);
209-
ray._immutable.direction = bsdfSampleL;
210-
#if POLYGON_METHOD==2
211-
ray._immutable.normalAtOrigin = interaction.isotropic.N;
212-
ray._immutable.wasBSDFAtOrigin = isBSDF;
213-
#endif
214-
return true;
215-
}
100+
Triangle tri = triangles[objectID-SPHERE_COUNT];
101+
normal = normalize(Triangle_getNormalTimesArea(tri));
102+
return tri.bsdfLightIDs;
216103
}
217-
return false;
218104
}

0 commit comments

Comments
 (0)