[Bf-blender-cvs] [07de832] master: Cycles: Use correct light sampling PDF for MIS calculation with Branched Path Tracing

Lukas Stockner noreply at git.blender.org
Sun Sep 25 23:16:18 CEST 2016


Commit: 07de832e22f5052d042605fdf3f8161a213c4f80
Author: Lukas Stockner
Date:   Sun Sep 25 22:11:50 2016 +0200
Branches: master
https://developer.blender.org/rB07de832e22f5052d042605fdf3f8161a213c4f80

Cycles: Use correct light sampling PDF for MIS calculation with Branched Path Tracing

The light sampling functions calculate light sampling PDF for the case that the light has been randomly selected out of all lights.
However, since BPT handles lamps and meshlights separately, this isn't the case. So, to avoid a wrong result, the code just included the 0.5 factor in the throughput.

In theory, however, the correction should be made to the sampling probability, which needs to be doubled. Now, for the regular calculation, that's no real difference since the throughput is divided by the pdf.
However, it does matter for the MIS calculation - it's unbiased both ways, but including the factor in the PDF instead of the throughput should give slightly better results.

Reviewers: sergey, brecht, dingto, juicyfruit

Differential Revision: https://developer.blender.org/D2258

===================================================================

M	intern/cycles/kernel/kernel_path_surface.h
M	intern/cycles/kernel/kernel_path_volume.h

===================================================================

diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 27acf81..45f0f1c 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -46,15 +46,17 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
 			float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
 			RNG lamp_rng = cmj_hash(*rng, i);
 
-			if(kernel_data.integrator.pdf_triangles != 0.0f)
-				num_samples_inv *= 0.5f;
-
 			for(int j = 0; j < num_samples; j++) {
 				float light_u, light_v;
 				path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
 
 				LightSample ls;
 				if(lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls)) {
+					/* The sampling probability returned by lamp_light_sample assumes that all lights were sampled.
+					 * However, this code only samples lamps, so if the scene also had mesh lights, the real probability is twice as high. */
+					if(kernel_data.integrator.pdf_triangles != 0.0f)
+						ls.pdf *= 2.0f;
+
 					if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
 						/* trace shadow ray */
 						float3 shadow;
@@ -73,9 +75,6 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
 			int num_samples = ceil_to_int(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
 			float num_samples_inv = num_samples_adjust/num_samples;
 
-			if(kernel_data.integrator.num_all_lights)
-				num_samples_inv *= 0.5f;
-
 			for(int j = 0; j < num_samples; j++) {
 				float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT);
 				float light_u, light_v;
@@ -87,6 +86,10 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
 
 				LightSample ls;
 				if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) {
+					/* Same as above, probability needs to be corrected since the sampling was forced to select a mesh light. */
+					if(kernel_data.integrator.num_all_lights)
+						ls.pdf *= 2.0f;
+
 					if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
 						/* trace shadow ray */
 						float3 shadow;
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 0bb8f1c..5ee1912 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -136,9 +136,6 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
 			float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
 			RNG lamp_rng = cmj_hash(*rng, i);
 
-			if(kernel_data.integrator.pdf_triangles != 0.0f)
-				num_samples_inv *= 0.5f;
-
 			for(int j = 0; j < num_samples; j++) {
 				/* sample random position on given light */
 				float light_u, light_v;
@@ -161,6 +158,9 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
 
 				/* todo: split up light_sample so we don't have to call it again with new position */
 				if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
+					if(kernel_data.integrator.pdf_triangles != 0.0f)
+						ls.pdf *= 2.0f;
+
 					if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
 						/* trace shadow ray */
 						float3 shadow;
@@ -179,9 +179,6 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
 			int num_samples = kernel_data.integrator.mesh_light_samples;
 			float num_samples_inv = 1.0f/num_samples;
 
-			if(kernel_data.integrator.num_all_lights)
-				num_samples_inv *= 0.5f;
-
 			for(int j = 0; j < num_samples; j++) {
 				/* sample random position on random triangle */
 				float light_t = path_branched_rng_1D_for_decision(kg, rng, state, j, num_samples, PRNG_LIGHT);
@@ -209,6 +206,9 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
 
 				/* todo: split up light_sample so we don't have to call it again with new position */
 				if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+					if(kernel_data.integrator.num_all_lights)
+						ls.pdf *= 2.0f;
+
 					if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
 						/* trace shadow ray */
 						float3 shadow;




More information about the Bf-blender-cvs mailing list