@@ -14,40 +14,36 @@ Triangle triangles[TRIANGLE_COUNT] = {
14
14
Triangle_Triangle(mat3 (vec3 (- 1.8 ,0.35 ,0.3 ),vec3 (- 1.2 ,0.35 ,0.0 ),vec3 (- 1.5 ,0.8 ,- 0.3 )),INVALID_ID_16BIT,0u)
15
15
};
16
16
17
- bool traceRay(in ImmutableRay_t _immutable )
17
+ int traceRay(inout float intersectionT, in vec3 origin, in vec3 direction )
18
18
{
19
- const bool anyHit = bitfieldExtract(_immutable.typeDepthSampleIx, 31 , 1 ) != 0 ;
19
+ const bool anyHit = intersectionT != FLT_MAX ;
20
20
21
21
int objectID = - 1 ;
22
- float intersectionT = _immutable.maxT;
23
22
for (int i= 0 ; i< SPHERE_COUNT; i++ )
24
23
{
25
- float t = Sphere_intersect(spheres[i],_immutable. origin,_immutable. direction);
24
+ float t = Sphere_intersect(spheres[i],origin,direction);
26
25
bool closerIntersection = t> 0.0 && t< intersectionT;
27
26
28
27
objectID = closerIntersection ? i: objectID;
29
28
intersectionT = closerIntersection ? t: intersectionT;
30
29
31
30
// allowing early out results in a performance regression, WTF!?
32
- // if (anyHit && closerIntersection && anyHitProgram(_immutable) )
31
+ // if (anyHit && closerIntersection)
33
32
// break;
34
33
}
35
34
for (int i= 0 ; i< TRIANGLE_COUNT; i++ )
36
35
{
37
- float t = Triangle_intersect(triangles[i],_immutable. origin,_immutable. direction);
36
+ float t = Triangle_intersect(triangles[i],origin,direction);
38
37
bool closerIntersection = t> 0.0 && t< intersectionT;
39
38
40
39
objectID = closerIntersection ? (i+ SPHERE_COUNT): objectID;
41
40
intersectionT = closerIntersection ? t: intersectionT;
42
41
43
42
// allowing early out results in a performance regression, WTF!?
44
- // if (anyHit && closerIntersection && anyHitProgram(_immutable) )
43
+ // if (anyHit && closerIntersection)
45
44
// break;
46
45
}
47
- rayStack[stackPtr]._mutable.objectID = objectID;
48
- rayStack[stackPtr]._mutable.intersectionT = intersectionT;
49
- // hit
50
- return anyHit;
46
+ return objectID;
51
47
}
52
48
53
49
@@ -90,7 +86,7 @@ vec3 nbl_glsl_light_deferred_eval_and_prob(
90
86
}
91
87
92
88
93
- nbl_glsl_LightSample nbl_glsl_light_generate_and_remainder_and_pdf(out vec3 remainder, out float pdf, out float newRayMaxT, in vec3 origin, in nbl_glsl_AnisotropicViewSurfaceInteraction interaction, in bool isBSDF, in vec3 u, in int depth)
89
+ nbl_glsl_LightSample nbl_glsl_light_generate_and_remainder_and_pdf(out vec3 remainder, out float pdf, out float newRayMaxT, in vec3 origin, in nbl_glsl_AnisotropicViewSurfaceInteraction interaction, in bool isBSDF, in vec3 u, in uint depth)
94
90
{
95
91
// normally we'd pick from set of lights, using `u.z`
96
92
const Light light = lights[0 ];
@@ -135,13 +131,17 @@ nbl_glsl_LightSample nbl_glsl_light_generate_and_remainder_and_pdf(out vec3 rema
135
131
return nbl_glsl_createLightSample(L,interaction);
136
132
}
137
133
138
- void closestHitProgram(in ImmutableRay_t _immutable, inout nbl_glsl_xoroshiro64star_state_t scramble_state)
134
+
135
+ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nbl_glsl_xoroshiro64star_state_t scramble_state)
139
136
{
140
- const MutableRay_t mutable = rayStack[stackPtr] ._mutable;
137
+ const MutableRay_t _mutable = ray ._mutable;
141
138
142
- vec3 intersection = _immutable.origin+ _immutable.direction* mutable.intersectionT;
143
- const uint objectID = mutable.objectID;
144
-
139
+ const uint objectID = _mutable.objectID;
140
+ Sphere sphere = spheres[_mutable.objectID];
141
+
142
+ // interaction stuffs
143
+ const ImmutableRay_t _immutable = ray._immutable;
144
+ const vec3 intersection = _immutable.origin+ _immutable.direction* _mutable.intersectionT;
145
145
uint bsdfLightIDs;
146
146
nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
147
147
{
@@ -167,119 +167,106 @@ void closestHitProgram(in ImmutableRay_t _immutable, inout nbl_glsl_xoroshiro64s
167
167
interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
168
168
}
169
169
170
- const uint lightID = bitfieldExtract(bsdfLightIDs,16 ,16 );
170
+ //
171
+ vec3 throughput = ray._payload.throughput;
171
172
172
- vec3 throughput = rayStack[stackPtr]._payload.throughput;
173
- // finish MIS
173
+ // add emissive and finish MIS
174
+ const uint lightID = bitfieldExtract(bsdfLightIDs, 16 , 16 );
174
175
if (lightID!= INVALID_ID_16BIT) // has emissive
175
176
{
176
177
float lightPdf;
177
178
vec3 lightVal = nbl_glsl_light_deferred_eval_and_prob(
178
179
lightPdf,lights[lightID],_immutable.direction
179
180
#if TRIANGLE_METHOD== 0
180
- ,mutable .intersectionT
181
+ ,_mutable .intersectionT
181
182
#else
182
183
,_immutable.origin
183
184
#if TRIANGLE_METHOD== 2
184
185
,_immutable.normalAtOrigin,_immutable.wasBSDFAtOrigin
185
186
#endif
186
187
#endif
187
188
);
188
- rayStack[stackPtr] ._payload.accumulation += throughput * lightVal/ (1.0 + lightPdf* lightPdf* rayStack[stackPtr] ._payload.otherTechniqueHeuristic);
189
+ ray ._payload.accumulation += lightVal* throughput / (1.0 + lightPdf* lightPdf* ray ._payload.otherTechniqueHeuristic);
189
190
}
190
-
191
- const int sampleIx = bitfieldExtract(_immutable.typeDepthSampleIx,0 ,DEPTH_BITS_OFFSET);
192
- const int depth = bitfieldExtract(_immutable.typeDepthSampleIx,DEPTH_BITS_OFFSET,DEPTH_BITS_COUNT);
193
191
194
192
// check if we even have a BSDF at all
195
193
uint bsdfID = bitfieldExtract(bsdfLightIDs,0 ,16 );
196
- if (depth < MAX_DEPTH && bsdfID!= INVALID_ID_16BIT)
194
+ if (bsdfID!= INVALID_ID_16BIT)
197
195
{
198
- // common preload
199
196
BSDFNode bsdf = bsdfs[bsdfID];
200
- uint opType = BSDFNode_getType(bsdf);
201
-
202
197
#ifdef KILL_DIFFUSE_SPECULAR_PATHS
203
198
if (BSDFNode_isNotDiffuse(bsdf))
204
199
{
205
- if (rayStack[stackPtr] ._payload.hasDiffuse)
206
- return ;
200
+ if (ray ._payload.hasDiffuse)
201
+ return true ;
207
202
}
208
203
else
209
- rayStack[stackPtr] ._payload.hasDiffuse = true;
204
+ ray ._payload.hasDiffuse = true;
210
205
#endif
211
-
212
-
213
- const float bsdfGeneratorProbability = BSDFNode_getMISWeight(bsdf);
214
- mat2x3 epsilon = rand3d(depth,sampleIx,scramble_state);
215
-
216
- float rcpChoiceProb;
217
- const bool doNEE = nbl_glsl_partitionRandVariable(bsdfGeneratorProbability,epsilon[0 ].z,rcpChoiceProb);
218
-
219
-
220
- float maxT;
221
- // the probability of generating a sample w.r.t. the light generator only possible and used when it was generated with it!
222
- float lightPdf;
223
- nbl_glsl_LightSample _sample;
224
- nbl_glsl_AnisotropicMicrofacetCache _cache;
206
+
225
207
const bool isBSDF = BSDFNode_isBSDF(bsdf);
226
- if (doNEE)
208
+ // rand
209
+ mat2x3 epsilon = rand3d(depth,_sample,scramble_state);
210
+
211
+ // thresholds
212
+ const float bsdfPdfThreshold = 0.0001 ;
213
+ const float lumaContributionThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3 (1.0 )/ 255.0 )); // OETF smallest perceptible value
214
+ const vec3 throughputCIE_Y = transpose (nbl_glsl_sRGBtoXYZ)[1 ]* throughput;
215
+ const float monochromeEta = dot (throughputCIE_Y,BSDFNode_getEta(bsdf)[0 ])/ (throughputCIE_Y.r+ throughputCIE_Y.g+ throughputCIE_Y.b);
216
+
217
+ // do NEE
218
+ const float neeSkipProbability = BSDFNode_getNEESkipProb(bsdf);
219
+ float rcpChoiceProb;
220
+ if (nbl_glsl_partitionRandVariable(neeSkipProbability,epsilon[0 ].z,rcpChoiceProb))
227
221
{
228
- vec3 lightRemainder ;
229
- _sample = nbl_glsl_light_generate_and_remainder_and_pdf(
230
- lightRemainder ,lightPdf,maxT ,
222
+ vec3 neeContrib; float lightPdf, t ;
223
+ nbl_glsl_LightSample nee_sample = nbl_glsl_light_generate_and_remainder_and_pdf(
224
+ neeContrib ,lightPdf,t ,
231
225
intersection,interaction,
232
226
isBSDF,epsilon[0 ],depth
233
227
);
234
- throughput *= lightRemainder;
235
- }
236
-
237
- bool validPath = true;
238
- const vec3 throughputCIE_Y = transpose (nbl_glsl_sRGBtoXYZ)[1 ]* throughput;
239
- const float monochromeEta = dot (throughputCIE_Y,BSDFNode_getEta(bsdf)[0 ])/ (throughputCIE_Y.r+ throughputCIE_Y.g+ throughputCIE_Y.b);
240
- if (doNEE)
241
- {
242
- // if we allowed non-watertight transmitters (single water surface), it would make sense just to apply this line.
243
- validPath = nbl_glsl_calcAnisotropicMicrofacetCache(_cache,interaction,_sample,monochromeEta);
244
- // but we don't allow non watertight transmitters in this renderer
245
- validPath = validPath && _sample.NdotL> 0.0 ;
228
+ // We don't allow non watertight transmitters in this renderer
229
+ bool validPath = nee_sample.NdotL> 0.0 ;
230
+ // but if we allowed non-watertight transmitters (single water surface), it would make sense just to apply this line by itself
231
+ nbl_glsl_AnisotropicMicrofacetCache _cache;
232
+ validPath = validPath && nbl_glsl_calcAnisotropicMicrofacetCache(_cache,interaction,nee_sample,monochromeEta);
233
+ if (validPath)
234
+ {
235
+ float bsdfPdf;
236
+ neeContrib *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,nee_sample,interaction,bsdf,monochromeEta,_cache)* throughput;
237
+ const float oc = bsdfPdf* rcpChoiceProb;
238
+ neeContrib /= 1.0 / oc+ oc/ (lightPdf* lightPdf); // MIS weight
239
+ if (bsdfPdf< FLT_MAX && getLuma(neeContrib)> lumaContributionThreshold && traceRay(t,intersection+ nee_sample.L* t* getStartTolerance(depth),nee_sample.L)==-1 )
240
+ ray._payload.accumulation += neeContrib;
241
+ }
246
242
}
247
- else
243
+
244
+ // sample BSDF
245
+ float bsdfPdf; vec3 bsdfSampleL;
248
246
{
249
- maxT = FLT_MAX;
250
- _sample = nbl_glsl_bsdf_cos_generate(interaction,epsilon[0 ],bsdf,monochromeEta,_cache);
247
+ nbl_glsl_AnisotropicMicrofacetCache _cache;
248
+ nbl_glsl_LightSample bsdf_sample = nbl_glsl_bsdf_cos_generate(interaction,epsilon[1 ],bsdf,monochromeEta,_cache);
249
+ // the value of the bsdf divided by the probability of the sample being generated
250
+ throughput *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,bsdf_sample,interaction,bsdf,monochromeEta,_cache);
251
+ //
252
+ bsdfSampleL = bsdf_sample.L;
251
253
}
252
-
253
- // do a cool trick and always compute the bsdf parts this way! (no divergence)
254
- float bsdfPdf;
255
- // the value of the bsdf divided by the probability of the sample being generated
256
- if (validPath)
257
- throughput *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,_sample,interaction,bsdf,monochromeEta,_cache);
258
- else
259
- throughput = vec3 (0.0 );
260
254
261
- // OETF smallest perceptible value
262
- const float bsdfPdfThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3 (1.0 )/ 255.0 ));
263
- const float lumaThroughputThreshold = bsdfPdfThreshold;
255
+ // additional threshold
256
+ const float lumaThroughputThreshold = lumaContributionThreshold;
264
257
if (bsdfPdf> bsdfPdfThreshold && getLuma(throughput)> lumaThroughputThreshold)
265
258
{
266
- rayStack[stackPtr]._payload.throughput = throughput* rcpChoiceProb;
267
-
268
- float heuristicFactor = rcpChoiceProb- 1.0 ; // weightNonGenerator/weightGenerator
269
- heuristicFactor /= doNEE ? lightPdf: bsdfPdf; // weightNonGenerator/(weightGenerator*probGenerated)
270
- heuristicFactor *= heuristicFactor; // (weightNonGenerator/(weightGenerator*probGenerated))^2
271
- if (doNEE)
272
- heuristicFactor = 1.0 / (1.0 / bsdfPdf+ heuristicFactor* bsdfPdf); // numerically stable, don't touch
273
- rayStack[stackPtr]._payload.otherTechniqueHeuristic = heuristicFactor;
259
+ ray._payload.throughput = throughput;
260
+ ray._payload.otherTechniqueHeuristic = (1.0 - neeSkipProbability)/ bsdfPdf; // numerically stable, don't touch
261
+ ray._payload.otherTechniqueHeuristic *= ray._payload.otherTechniqueHeuristic;
274
262
275
263
// trace new ray
276
- rayStack[stackPtr]._immutable.origin = intersection+ _sample.L* (doNEE ? maxT: 1.0 /* kSceneSize*/ )* getStartTolerance(depth);
277
- rayStack[stackPtr]._immutable.maxT = maxT;
278
- rayStack[stackPtr]._immutable.direction = _sample.L;
279
- rayStack[stackPtr]._immutable.typeDepthSampleIx = bitfieldInsert(sampleIx,depth+ 2 ,DEPTH_BITS_OFFSET,DEPTH_BITS_COUNT)| (doNEE ? ANY_HIT_FLAG: 0 );
280
- rayStack[stackPtr]._immutable.normalAtOrigin = interaction.isotropic.N;
281
- rayStack[stackPtr]._immutable.wasBSDFAtOrigin = isBSDF;
282
- stackPtr++ ;
264
+ ray._immutable.origin = intersection+ bsdfSampleL* (1.0 /* kSceneSize*/ )* getStartTolerance(depth);
265
+ ray._immutable.direction = bsdfSampleL;
266
+ ray._immutable.normalAtOrigin = interaction.isotropic.N;
267
+ ray._immutable.wasBSDFAtOrigin = isBSDF;
268
+ return true;
283
269
}
284
270
}
271
+ return false;
285
272
}
0 commit comments