22
33#include " Raytracing/Geometry.h"
44#include " Raytracing/GaussianShading.h"
5+ #include " Raytracing/LightSampling.h"
56#include " Raytracing/MisHeuristic.h"
67#include " Raytracing/Queues.h"
78#include " Raytracing/RgbToSpectrum.h"
@@ -50,66 +51,31 @@ NR_GPU inline glm::vec3 shadeBsdfLobe(
5051 state.packedCounters += 1u << CounterDiffuseShift;
5152 }
5253 state.throughput *= bsdfSample.weight ;
53- state.lastBsdfPdfBits = __float_as_uint (bsdfSample.pdf );
54+ state.lastBsdfPdfBits = __float_as_uint (
55+ bsdf.transmission <= 0 .0f ? bsdfSample.pdf : 0 .0f );
5456
5557 // Direct light sampling.
5658 {
5759 LightSample lightSample{};
58- const uint32_t pl = params.scene .pointLightCount ;
59- const uint32_t sl = params.scene .spotLightCount ;
60- const uint32_t rl = params.scene .rectLightCount ;
61- const uint32_t dl = params.scene .directionalLightCount ;
6260 const float analyticWeight = analyticLightSelectionWeight (params.scene );
6361 const float environmentWeight = bsdf.transmission <= 0 .0f
6462 ? fmaxf (params.scene .environment ->importanceWeight , 0 .0f ) : 0 .0f ;
6563 const float totalWeight = analyticWeight + environmentWeight;
6664 if (totalWeight > 0 .0f )
6765 {
68- float target = randomFloat (lightRng) * totalWeight;
66+ const float target = randomFloat (lightRng) * totalWeight;
6967 float selectedWeight = 0 .0f ;
7068 bool environmentSelected = false ;
7169 float sampledEnvironmentPdf = 0 .0f ;
72- for (uint32_t i = 0 ; i < pl && selectedWeight == 0 .0f ; ++i) {
73- const float w = params.scene .pointLights [i].selectionWeight ();
74- if (target < w) {
75- selectedWeight = w;
76- lightSample = params.scene .pointLights [i].sampleLi (
77- position, lightRng, wl,
78- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
79- params.scene .d65 );
80- } else target -= w;
81- }
82- for (uint32_t i = 0 ; i < sl && selectedWeight == 0 .0f ; ++i) {
83- const float w = params.scene .spotLights [i].selectionWeight ();
84- if (target < w) {
85- selectedWeight = w;
86- lightSample = params.scene .spotLights [i].sampleLi (
87- position, lightRng, wl,
88- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
89- params.scene .d65 );
90- } else target -= w;
91- }
92- for (uint32_t i = 0 ; i < rl && selectedWeight == 0 .0f ; ++i) {
93- const float w = params.scene .rectLights [i].selectionWeight ();
94- if (target < w) {
95- selectedWeight = w;
96- lightSample = params.scene .rectLights [i].sampleLi (
97- position, lightRng, wl,
98- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
99- params.scene .d65 );
100- } else target -= w;
101- }
102- for (uint32_t i = 0 ; i < dl && selectedWeight == 0 .0f ; ++i) {
103- const float w = params.scene .directionalLights [i].selectionWeight ();
104- if (target < w) {
105- selectedWeight = w;
106- lightSample = params.scene .directionalLights [i].sampleLi (
107- position, lightRng, wl,
108- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
109- params.scene .d65 );
110- } else target -= w;
70+ if (target < analyticWeight && analyticWeight > 0 .0f )
71+ {
72+ const AnalyticLightSample analytic = sampleAnalyticLight (
73+ params.scene , position, lightRng, wl);
74+ selectedWeight = analytic.selectionPdf * analyticWeight;
75+ lightSample = analytic.light ;
11176 }
112- if (selectedWeight == 0 .0f && environmentWeight > 0 .0f ) {
77+ else if (environmentWeight > 0 .0f )
78+ {
11379 const EnvironmentSample environmentSample =
11480 params.scene .environment ->sampleDirection (lightRng);
11581 if (environmentSample.pdf > 0 .0f ) {
@@ -166,8 +132,8 @@ NR_GPU_KERNEL void shadeKernel(const KernelParams params)
166132 params.scene .renderSettings .gaussianShadingMode == GaussianShadingMode::DirectColor;
167133 const bool mayWriteShadowQueue = params.scene .meshInstanceCount > 0 ||
168134 (!gaussianDirectColor &&
169- (params.scene .pointLightCount > 0 || params. scene . spotLightCount > 0 ||
170- params. scene . rectLightCount > 0 || params.scene .directionalLightCount > 0 ));
135+ (params.scene .analyticLightAliasCount > 0
136+ || params.scene .environment -> importanceWeight > 0 . 0f ));
171137 bool continuePath = false ;
172138 PathRayWorkItem continuation{};
173139 if (inRange)
@@ -246,63 +212,61 @@ NR_GPU_KERNEL void shadeKernel(const KernelParams params)
246212 // ── NEE: sample analytic lights ────────────────────────
247213 {
248214 LightSample lightSample{};
249- const uint32_t pl = params.scene .pointLightCount ;
250- const uint32_t sl = params.scene .spotLightCount ;
251- const uint32_t rl = params.scene .rectLightCount ;
252- const uint32_t dl = params.scene .directionalLightCount ;
253215 const float analyticWeight = analyticLightSelectionWeight (params.scene );
254- const float environmentWeight = 0 .0f ; // env sampled by scattered ray
216+ const float environmentWeight = fmaxf (
217+ params.scene .environment ->importanceWeight , 0 .0f );
255218 const float totalWeight = analyticWeight + environmentWeight;
256219 if (totalWeight > 0 .0f )
257220 {
258- float target = randomFloat (lightRng) * totalWeight;
221+ const float target = randomFloat (lightRng) * totalWeight;
259222 float selectedWeight = 0 .0f ;
260- for (uint32_t i = 0 ; i < pl && selectedWeight == 0 .0f ; ++i) {
261- const float w = params.scene .pointLights [i].selectionWeight ();
262- if (target < w) { selectedWeight = w;
263- lightSample = params.scene .pointLights [i].sampleLi (
264- gaussianPos, lightRng, wl,
265- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
266- params.scene .d65 ); } else target -= w;
267- }
268- for (uint32_t i = 0 ; i < sl && selectedWeight == 0 .0f ; ++i) {
269- const float w = params.scene .spotLights [i].selectionWeight ();
270- if (target < w) { selectedWeight = w;
271- lightSample = params.scene .spotLights [i].sampleLi (
272- gaussianPos, lightRng, wl,
273- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
274- params.scene .d65 ); } else target -= w;
275- }
276- for (uint32_t i = 0 ; i < rl && selectedWeight == 0 .0f ; ++i) {
277- const float w = params.scene .rectLights [i].selectionWeight ();
278- if (target < w) { selectedWeight = w;
279- lightSample = params.scene .rectLights [i].sampleLi (
280- gaussianPos, lightRng, wl,
281- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
282- params.scene .d65 ); } else target -= w;
223+ bool environmentSelected = false ;
224+ float sampledEnvironmentPdf = 0 .0f ;
225+ if (target < analyticWeight && analyticWeight > 0 .0f )
226+ {
227+ const AnalyticLightSample analytic = sampleAnalyticLight (
228+ params.scene , gaussianPos, lightRng, wl);
229+ selectedWeight = analytic.selectionPdf * analyticWeight;
230+ lightSample = analytic.light ;
283231 }
284- for (uint32_t i = 0 ; i < dl && selectedWeight == 0 .0f ; ++i) {
285- const float w = params.scene .directionalLights [i].selectionWeight ();
286- if (target < w) { selectedWeight = w;
287- lightSample = params.scene .directionalLights [i].sampleLi (
288- gaussianPos, lightRng, wl,
289- params.scene .spectrumTableScale , params.scene .spectrumTableCoeffs ,
290- params.scene .d65 ); } else target -= w;
232+ else if (environmentWeight > 0 .0f )
233+ {
234+ const EnvironmentSample environmentSample =
235+ params.scene .environment ->sampleDirection (lightRng);
236+ if (environmentSample.pdf > 0 .0f )
237+ {
238+ selectedWeight = environmentWeight;
239+ environmentSelected = true ;
240+ sampledEnvironmentPdf = environmentSample.pdf ;
241+ lightSample.direction = environmentSample.direction ;
242+ lightSample.distance = 1e16f;
243+ lightSample.radiance = params.scene .environment ->radiance (
244+ params.scene .textures , params.scene .textureCount ,
245+ environmentSample.direction , false , wl,
246+ params.scene .spectrumTableScale ,
247+ params.scene .spectrumTableCoeffs , params.scene .d65 );
248+ }
291249 }
292250 if (selectedWeight > 0 .0f && lightSample.radiance .maxComponent () > 0 .0f )
293251 {
294252 const float selectionPdf = selectedWeight / totalWeight;
295253 const SampledSpectrum brdf = albedo * inv4Pi;
254+ if (environmentSelected)
255+ {
256+ const float lightPdf = selectionPdf * sampledEnvironmentPdf;
257+ lightSample.radiance *= powerHeuristic (lightPdf, inv4Pi)
258+ / fmaxf (lightPdf, 1e-20f );
259+ }
260+ else
261+ {
262+ lightSample.radiance *= 1 .0f / selectionPdf;
263+ }
296264 shadow.origin = gaussianPos + lightSample.direction * 0 .001f ;
297265 shadow.direction = lightSample.direction ;
298266 shadow.tMin = 0 .001f ;
299267 shadow.tMax = lightSample.distance - 0 .002f ;
300- // Analytic lights are only reachable through NEE: they are
301- // not emissive geometry that the scattered ray can hit.
302- // Therefore there is no competing sampling technique and
303- // no MIS term. Compensate only for selecting one light.
304- shadow.contribution = state.throughput * brdf * lightSample.radiance
305- / fmaxf (selectionPdf, 1e-20f );
268+ shadow.contribution =
269+ state.throughput * brdf * lightSample.radiance ;
306270 shadow.rngState = shadowRng;
307271 shadow.sampleIndex = hit.sampleIndex ;
308272 params.queues .shadowQueue [index] = shadow;
@@ -311,9 +275,7 @@ NR_GPU_KERNEL void shadeKernel(const KernelParams params)
311275 }
312276
313277 state.throughput *= albedo;
314- // Gaussian scattering does not perform environment NEE. A zero PDF
315- // tells the miss path not to MIS-downweight its environment sample.
316- state.lastBsdfPdfBits = __float_as_uint (0 .0f );
278+ state.lastBsdfPdfBits = __float_as_uint (inv4Pi);
317279
318280 state.depth ++;
319281 continuePath = true ;
0 commit comments