Commit: 260b2e9e20ac2c2acff17498e2ca006f2a2d9d95
Author: Erik Englesson
Date:   Wed Jul 11 07:49:30 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB260b2e9e20ac2c2acff17498e2ca006f2a2d9d95

Cycles: Updated the importance metric

The new paper provides an updated importance
metric which is now implemented. Also, a bug
in the index used for background lights in
the MIS calculations have been fixed.

Technical details:
- The new importance metric depends on the
  normal at the shading point. The MIS
  calculations have been changed
  accordingly.

- The uncertainty angle was described in
  the paper and is now implemented.

- In the implementation details section
  of the paper they mention that they
  limit the distance if splitting is
  disabled. This is implemented too.

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

M       intern/cycles/kernel/kernel_bake.h
M       intern/cycles/kernel/kernel_emission.h
M       intern/cycles/kernel/kernel_light.h
M       intern/cycles/kernel/kernel_path.h
M       intern/cycles/kernel/kernel_path_branched.h
M       intern/cycles/kernel/kernel_path_surface.h
M       intern/cycles/kernel/kernel_path_volume.h
M       intern/cycles/kernel/split/kernel_direct_lighting.h
M       intern/cycles/kernel/split/kernel_indirect_background.h
M       intern/cycles/kernel/split/kernel_lamp_emission.h

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

diff --git a/intern/cycles/kernel/kernel_bake.h 
b/intern/cycles/kernel/kernel_bake.h
index 79e6d1b4862..f68afb117a9 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -100,6 +100,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                                                             &indirect_sd,
                                                             &emission_sd,
                                                             &ray,
+                                                            sd->N,
                                                             throughput,
                                                             &state,
                                                             &L_sample);
@@ -118,7 +119,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                                state.ray_t = 0.0f;
 #endif
                                /* compute indirect light */
-                               kernel_path_indirect(kg, &indirect_sd, 
&emission_sd, &ray, throughput, &state, &L_sample);
+                               kernel_path_indirect(kg, &indirect_sd, 
&emission_sd, &ray, sd->N, throughput, &state, &L_sample);
 
                                /* sum and reset indirect light pass variables 
for the next samples */
                                path_radiance_sum_indirect(&L_sample);
diff --git a/intern/cycles/kernel/kernel_emission.h 
b/intern/cycles/kernel/kernel_emission.h
index 4fc05894d00..f3693638292 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -212,7 +212,7 @@ ccl_device_noinline float3 
indirect_primitive_emission(KernelGlobals *kg, Shader
                /* multiple importance sampling, get triangle light pdf,
                 * and compute weight with respect to BSDF pdf */
                float pdf = triangle_light_pdf(kg, sd, t);
-               pdf *= light_distribution_pdf(kg, sd->P, sd->prim);
+               pdf *= light_distribution_pdf(kg, sd->P, sd->N, sd->prim);
                float mis_weight = power_heuristic(bsdf_pdf, pdf);
 
                return L*mis_weight;
@@ -226,13 +226,13 @@ ccl_device_noinline float3 
indirect_primitive_emission(KernelGlobals *kg, Shader
 ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
                                                 ShaderData *emission_sd,
                                                 ccl_addr_space PathState 
*state,
+                                                float3 N,
                                                 Ray *ray,
                                                 float3 *emission)
 {
        bool hit_lamp = false;
 
        *emission = make_float3(0.0f, 0.0f, 0.0f);
-
        for(int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) 
{
                LightSample ls;
 
@@ -276,7 +276,7 @@ ccl_device_noinline bool 
indirect_lamp_emission(KernelGlobals *kg,
                         * and compute weight with respect to BSDF pdf */
 
                        /* multiply with light picking probablity to pdf */
-                       ls.pdf *= light_distribution_pdf(kg, ls.P, ~ls.lamp);
+                       ls.pdf *= light_distribution_pdf(kg, ray->P, N, 
~ls.lamp);
                        float mis_weight = power_heuristic(state->ray_pdf, 
ls.pdf);
                        L *= mis_weight;
                }
@@ -292,6 +292,7 @@ ccl_device_noinline bool 
indirect_lamp_emission(KernelGlobals *kg,
 
 ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
                                                ShaderData *emission_sd,
+                                               float3 N,
                                                ccl_addr_space PathState *state,
                                                ccl_addr_space Ray *ray)
 {
@@ -330,7 +331,7 @@ ccl_device_noinline float3 
indirect_background(KernelGlobals *kg,
                 * direction, and compute weight with respect to BSDF pdf */
                float pdf = background_light_pdf(kg, ray->P, ray->D);
                int background_index = 
kernel_data.integrator.background_light_index;
-               pdf *= light_distribution_pdf(kg, ray->P, background_index);
+               pdf *= light_distribution_pdf(kg, ray->P, N, ~background_index);
                float mis_weight = power_heuristic(state->ray_pdf, pdf);
 
                return L*mis_weight;
diff --git a/intern/cycles/kernel/kernel_light.h 
b/intern/cycles/kernel/kernel_light.h
index 57f238425ee..8346aea1386 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1102,28 +1102,70 @@ ccl_device bool 
light_select_reached_max_bounces(KernelGlobals *kg, int index, i
        return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
 }
 
-ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, int 
node_offset)
+ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, float3 N, 
int node_offset)
 {
-       float4 node0 = kernel_tex_fetch(__light_tree_nodes, node_offset + 0);
-       float4 node1 = kernel_tex_fetch(__light_tree_nodes, node_offset + 1);
-       float4 node2 = kernel_tex_fetch(__light_tree_nodes, node_offset + 2);
-       float4 node3 = kernel_tex_fetch(__light_tree_nodes, node_offset + 3);
-
-       float energy = node0[0];
-       float3 bboxMin = make_float3( node1[0], node1[1], node1[2]);
-       float3 bboxMax = make_float3( node1[3], node2[0], node2[1]);
-       float theta_o = node2[2];
-       float theta_e = node2[3];
-       float3 axis = make_float3(node3[0], node3[1], node3[2]);
-       float3 centroid = 0.5f*(bboxMax + bboxMin);
-
-       float3 centroidToP = P-centroid;
-       float theta = acosf(dot(axis,normalize(centroidToP)));
-       float theta_u = 0; // TODO: Figure out how to calculate this one
-       float d2 = len_squared(centroidToP);
-
-       // todo: fix clamp here so it is 0 outside theta_e + theta_o ?
-       return energy * cosf(clamp(theta - theta_o - theta_u, 0.0, theta_e))/d2;
+       const float4 node0 = kernel_tex_fetch(__light_tree_nodes, node_offset + 
0);
+       const float4 node1 = kernel_tex_fetch(__light_tree_nodes, node_offset + 
1);
+       const float4 node2 = kernel_tex_fetch(__light_tree_nodes, node_offset + 
2);
+       const float4 node3 = kernel_tex_fetch(__light_tree_nodes, node_offset + 
3);
+
+       const float energy    = node0[0];
+       const float3 bboxMin  = make_float3( node1[0], node1[1], node1[2]);
+       const float3 bboxMax  = make_float3( node1[3], node2[0], node2[1]);
+       const float theta_o   = node2[2];
+       const float theta_e   = node2[3];
+       const float3 axis     = make_float3(node3[0], node3[1], node3[2]);
+       const float3 centroid = 0.5f*(bboxMax + bboxMin);
+
+       /* eq. 3 */
+
+       /* "theta_u captures the solid angle of the entire box" */
+       /* approixmate solid angle of box with solid angle of bounding sphere */
+       /* (---r---C       )
+        *  \     /
+        *   \ th/ <--- d
+        *    \ /
+        *     P
+        * sin(th) = r/d <=> sin^2(th) = r^2 / d^2 */
+       const float3 centroidToP        = P - centroid;
+       const float3 centroidToPDir     = normalize(centroidToP);
+       const float r2                  = len_squared(bboxMax - centroid);
+       float d2                        = len_squared(centroidToP);
+
+       /* based on comment in the implementation details of the paper */
+       const bool splitting = kernel_data.integrator.splitting_threshold != 
0.0f;
+       if(!splitting){
+               d2 = max(d2, r2 * 0.25f);
+       }
+
+       float theta_u;
+       if(d2 <= r2){
+               /* P is inside bounding sphere */
+               theta_u = M_PI_F;
+       } else {
+               const float sin_theta_u_squared = r2 / d2;
+               const float cos_theta_u         = safe_sqrtf(1.0f - 
sin_theta_u_squared);
+               theta_u                         = acosf(cos_theta_u);
+       }
+
+       /* cos(theta') */
+       const float theta       = acosf(dot(axis, centroidToPDir));
+       const float theta_prime = fmaxf(theta - theta_o - theta_u, 0.0f);
+       if (theta_prime >= theta_e){
+               return 0.0f;
+       }
+       const float cos_theta_prime = cosf(theta_prime);
+
+       /* f_a|cos(theta'_i)| -- diffuse approximation */
+       const float theta_i               = acosf(dot(N, -centroidToPDir));
+       const float theta_i_prime         = fmaxf(theta_i - theta_u, 0.0f);
+       const float cos_theta_i_prime     = cosf(theta_i_prime);
+       const float abs_cos_theta_i_prime = fabsf(cos_theta_i_prime);
+       /* doing something similar to bsdf_diffuse_eval_reflect() */
+       /* TODO: Use theta_i or theta_i_prime here? */
+       const float f_a                   = fmaxf(cos_theta_i_prime, 0.0f) * 
M_1_PI_F;
+
+       return f_a * abs_cos_theta_i_prime * energy * cos_theta_prime / d2;
 }
 
 ccl_device void update_parent_node(KernelGlobals *kg, int node_offset,
@@ -1162,8 +1204,8 @@ ccl_device void light_background_sample(KernelGlobals 
*kg, float3 P, float *rand
 
 /* picks a light from the light BVH and returns its index and the probability 
of
  * picking this light. */
-ccl_device void light_bvh_sample(KernelGlobals *kg, float3 P, float randu,
-                                 int *index, float *pdf_factor)
+ccl_device void light_bvh_sample(KernelGlobals *kg, float3 P, float3 N,
+                                 float randu, int *index, float *pdf_factor)
 {
        int sampled_index = -1;
        *pdf_factor = 1.0f;
@@ -1178,6 +1220,7 @@ ccl_device void light_bvh_sample(KernelGlobals *kg, 
float3 P, float randu,
                /* Found a leaf - Choose which light to use */
                if(secondChildOffset == -1){ // Found a leaf
                        if(num_emitters == 1){
+
                                sampled_index = distribution_id;
                        } else { // Leaf with several lights. Pick one randomly.
                                int light = min((int)(randu* 
(float)num_emitters), num_emitters-1);
@@ -1190,8 +1233,12 @@ ccl_device void light_bvh_sample(KernelGlobals *kg, 
float3 P, float randu,
                        /* calculate probability of going down left node */
                        int child_offsetL = offset + 4;
                        int child_offsetR = 4*secondChildOffset;
-                       float I_L = calc_node_importance(kg, P, child_offsetL);
-                       float I_R = calc_node_importance(kg, P, child_offsetR);
+                       float I_L = calc_node_importance(kg, P, N, 
child_offsetL);
+                       float I_R = calc_node_importance(kg, P, N, 
child_offsetR);
+                       if( (I_L==0.0f) && (I_R == 0.0f)){
+                               *pdf_factor = 0.0f;
+                               break;
+                       }
                        float P_L = I_L / ( I_L + I_R);
 
                        /* choose which node to go down */
@@ -1250,7 +1297,7 @@ ccl_device int triangle_to_distribution(KernelGlobals 
*kg, int triangle_id)
 }
 
 /* computes the probability of picking a light in the given node_id */
-ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 P, int node_id){
+ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 P, float3 N, int 
node_id){
        float pdf = 1.0f;
        /* read in first part of root node of light BVH */
        int secondChildOffset, distribution_id, num_emitters;
@@ -1270,8 +1317,13 @@ ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 
P, int node_id){
                        /* calculate probability of going down left node */
                        int child_offsetL = offset + 4;
                        int child_offsetR = 4*secondChildOffset;
-                       float I_L = calc_node_importance(kg, P, child_offsetL);
-                       float I_R = calc_node_importance

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to