diff options
author | Lukas Stockner <lukas.stockner@freenet.de> | 2016-09-25 23:11:50 +0300 |
---|---|---|
committer | Lukas Stockner <lukas.stockner@freenet.de> | 2016-09-26 00:16:05 +0300 |
commit | 07de832e22f5052d042605fdf3f8161a213c4f80 (patch) | |
tree | 4c75f6001b90eaa1691f44a9a1fbbf07720f0428 /intern/cycles/kernel | |
parent | 18b0738303b27d827d3f4d4e32a22785817a818e (diff) |
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
Diffstat (limited to 'intern/cycles/kernel')
-rw-r--r-- | intern/cycles/kernel/kernel_path_surface.h | 15 | ||||
-rw-r--r-- | intern/cycles/kernel/kernel_path_volume.h | 12 |
2 files changed, 15 insertions, 12 deletions
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index 27acf8166b3..45f0f1cbfaa 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 0bb8f1c517f..5ee1912c913 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; |