[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