@@ -146,6 +146,7 @@ void main(ParameterBlock<Scene> scene, ParameterBlock<SSMMBinding> params) {
146146
147147 float3 sample_dirs [SSMM_MAX_SPP ];
148148 float3 sample_weights [SSMM_MAX_SPP ];
149+ bool sample_delta [SSMM_MAX_SPP ];
149150 float4 vmfs [SSMM_MAX_SPP ];
150151
151152 mc_state_t curr = mc_state_new (); // zero current state
@@ -170,6 +171,7 @@ void main(ParameterBlock<Scene> scene, ParameterBlock<SSMMBinding> params) {
170171 mc_state_shuffle (tent, (WaveGetLaneIndex () + 1 ) % WaveGetLaneCount ());
171172 sample_dirs[s] = float3 (0 );
172173 sample_weights[s] = float3 (0 );
174+ sample_delta[s] = false ;
173175
174176 read_neighbour_state (params. gbuffer, scene. camera. position, resolution, tent,
175177 sp. pos, normal, int2 (pixel), mv, rng);
@@ -183,24 +185,29 @@ void main(ParameterBlock<Scene> scene, ParameterBlock<SSMMBinding> params) {
183185 float3 direction = float3 (0 );
184186 float3 position = float3 (0 );
185187 bool bsdf_sample = false ;
188+ float3 throughput = float3 (0 );
186189 do {
187190 if (vmfs[s]. w == 0 || rng. next_float () < merian_ssmm_bsdf_p) {
188- let wo_local = bsdf. sample (wi_local, rng);
189- if (! wo_local . hasValue)
191+ let bs_opt = bsdf. sample_eval (wi_local, rng);
192+ if (! bs_opt . hasValue)
190193 break ;
191- direction = frame. to_world (wo_local. value);
194+ const ShadingFunctionSample bs = bs_opt. value;
195+ direction = frame. to_world (bs. wo);
192196 if (dot (direction, normal) <= 1e-3 || dot (direction, geonormal) <= 1e-3 )
193197 break ;
194198
195- pdf = bsdf. pdf (wi_local, wo_local. value);
199+ sample_delta[s] = bs. lobe == BSDFLobe:: Delta;
200+ // a delta weight is already f / p
201+ pdf = sample_delta[s] ? 1.0 : bs. pdf;
202+ throughput =
203+ sample_delta[s] ? bs. weight : bsdf. eval (wi_local, bs. wo, rng);
196204 bsdf_sample = true ;
197205 } else {
198206 direction = vmf_sample_tokuyosh (vmfs[s]. xyz, vmfs[s]. w, rng. next_float2 ());
199207 pdf = vmf_pdf_tokuyoshi (direction, vmfs[s]. xyz, vmfs[s]. w);
208+ throughput = bsdf. eval (wi_local, frame. to_local (direction), rng);
200209 }
201210
202- const float3 throughput = bsdf. eval (wi_local, frame. to_local (direction), rng);
203-
204211 RayDesc ray ;
205212 // Pull back the ray such that it cannot excape through corners (and to
206213 // prevent self collision)
@@ -209,7 +216,7 @@ void main(ParameterBlock<Scene> scene, ParameterBlock<SSMMBinding> params) {
209216 ray. TMin = SCENE_RAY_TMIN;
210217 ray. TMax = SCENE_RAY_TMAX;
211218 const ShadingPoint next_sp = scene. trace_and_get_shading_point (
212- ray, 0xffu , RenderContext (uint16_t (1 ), 1.0f ));
219+ ray, 0xffu , RenderContext (uint16_t (1 )));
213220
214221 position = next_sp. pos;
215222 directContrib = throughput * next_sp. emission / pdf;
@@ -236,16 +243,22 @@ void main(ParameterBlock<Scene> scene, ParameterBlock<SSMMBinding> params) {
236243 if (all (sample_weights[s] == float3 (0 )))
237244 continue ;
238245
239- const float bsdf_pdf = bsdf. pdf (wi_local, frame. to_local (sample_dirs[s]));
240- float sum_pdf = 0 ;
241- for (int t = 0 ; t < merian_ssmm_spp; t++ ) {
242- sum_pdf += vmfs[t]. w > 0
243- ? vmf_pdf_tokuyoshi (sample_dirs[s], vmfs[t]. xyz, vmfs[t]. w)
244- : bsdf_pdf;
245- }
246+ float sum_pdf ;
247+ if (sample_delta[s]) {
248+ // only the BSDF strategy, shared by the whole group, reaches a delta direction
249+ sum_pdf = merian_ssmm_bsdf_p * merian_ssmm_smis_group_size ;
250+ } else {
251+ const float bsdf_pdf = bsdf. pdf (wi_local, frame. to_local (sample_dirs[s]));
252+ sum_pdf = 0 ;
253+ for (int t = 0 ; t < merian_ssmm_spp; t++ ) {
254+ sum_pdf += vmfs[t]. w > 0
255+ ? vmf_pdf_tokuyoshi (sample_dirs[s], vmfs[t]. xyz, vmfs[t]. w)
256+ : bsdf_pdf;
257+ }
246258
247- sum_pdf = merian_ssmm_bsdf_p * merian_ssmm_smis_group_size * bsdf_pdf +
248- (1 - merian_ssmm_bsdf_p) * sum_pdf;
259+ sum_pdf = merian_ssmm_bsdf_p * merian_ssmm_smis_group_size * bsdf_pdf +
260+ (1 - merian_ssmm_bsdf_p) * sum_pdf;
261+ }
249262
250263 if (sum_pdf > 0 ) {
251264 const float3 con = sample_weights[s] / sum_pdf;
0 commit comments