[Bf-blender-cvs] [260b2e9e20a] gsoc-2018-many-light-sampling: Cycles: Updated the importance metric
Erik Englesson
noreply at git.blender.org
Fri Jul 13 13:57:46 CEST 2018
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. @@
More information about the Bf-blender-cvs
mailing list