[Bf-blender-cvs] [c6bd7a974b3] gsoc-2018-many-light-sampling: Cycles: Updated the split heuristic
Erik Englesson
noreply at git.blender.org
Fri Jul 13 13:57:43 CEST 2018
Commit: c6bd7a974b34d47f01f02666d8cdd5057bc77eba
Author: Erik Englesson
Date: Tue Jul 10 11:13:14 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rBc6bd7a974b34d47f01f02666d8cdd5057bc77eba
Cycles: Updated the split heuristic
The split heuristic is now based on the
new paper instead of the abstract/slides
from 2017.
===================================================================
M intern/cycles/kernel/kernel_light.h
M intern/cycles/kernel/kernel_path_surface.h
M intern/cycles/render/light.cpp
M intern/cycles/render/light_tree.cpp
M intern/cycles/render/light_tree.h
===================================================================
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 39d575adefa..5ded315881a 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1128,12 +1128,12 @@ ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, int node_offs
ccl_device void update_parent_node(KernelGlobals *kg, int node_offset,
int *childOffset, int *distribution_id,
- int *nemitters)
+ int *num_emitters)
{
float4 node = kernel_tex_fetch(__light_tree_nodes, node_offset);
(*childOffset) = __float_as_int(node[1]);
(*distribution_id) = __float_as_int(node[2]);
- (*nemitters) = __float_as_int(node[3]);
+ (*num_emitters) = __float_as_int(node[3]);
}
/* picks one of the distant lights and computes the probability of picking it */
@@ -1169,21 +1169,21 @@ ccl_device void light_bvh_sample(KernelGlobals *kg, float3 P, float randu,
*pdf_factor = 1.0f;
/* read in first part of root node of light BVH */
- int secondChildOffset, distribution_id, nemitters;
- update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &nemitters);
+ int secondChildOffset, distribution_id, num_emitters;
+ update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &num_emitters);
int offset = 0;
do{
/* Found a leaf - Choose which light to use */
- if(nemitters > 0){ // Found a leaf
- if(nemitters == 1){
+ if(secondChildOffset == -1){ // Found a leaf
+ if(num_emitters == 1){
sampled_index = distribution_id;
} else { // Leaf with several lights. Pick one randomly.
light_distribution_sample(kg, &randu); // TODO: Rescale random number in a better way
- int light = min((int)(randu* (float)nemitters), nemitters-1);
+ int light = min((int)(randu* (float)num_emitters), num_emitters-1);
sampled_index = distribution_id +light;
- *pdf_factor *= 1.0f / (float)nemitters;
+ *pdf_factor *= 1.0f / (float)num_emitters;
}
break;
} else { // Interior node, pick left or right randomly
@@ -1207,7 +1207,7 @@ ccl_device void light_bvh_sample(KernelGlobals *kg, float3 P, float randu,
/* update parent node info for next iteration */
update_parent_node(kg, offset, &secondChildOffset,
- &distribution_id, &nemitters);
+ &distribution_id, &num_emitters);
}
@@ -1249,16 +1249,16 @@ ccl_device int triangle_to_distribution(KernelGlobals *kg, int triangle_id)
ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 P, int node_id){
float pdf = 1.0f;
/* read in first part of root node of light BVH */
- int secondChildOffset, distribution_id, nemitters;
- update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &nemitters);
+ int secondChildOffset, distribution_id, num_emitters;
+ update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &num_emitters);
int offset = 0;
do{
- if(nemitters > 0){ // Found our leaf node
+ if(secondChildOffset == -1){ // Found our leaf node
kernel_assert(offset == node_id);
- if(nemitters > 1){
- pdf *= 1.0f / (float)nemitters;
+ if(num_emitters > 1){
+ pdf *= 1.0f / (float)num_emitters;
}
break;
} else { // Interior node, pick left or right depending on node_id
@@ -1282,7 +1282,7 @@ ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 P, int node_id){
/* update parent node info for next iteration */
update_parent_node(kg, offset, &secondChildOffset,
- &distribution_id, &nemitters);
+ &distribution_id, &num_emitters);
}
} while(true);
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 54062a1c2b7..a344f43d786 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -46,14 +46,13 @@ ccl_device void accum_light_contribution(KernelGlobals *kg,
}
/* Decides whether to go down both childen or only one in the tree traversal */
-ccl_device bool split(KernelGlobals *kg, ShaderData * sd, int node_offset,
- float randu, float randv)
+ccl_device bool split(KernelGlobals *kg, float3 P, int node_offset)
{
/* early exists if never/always splitting */
- const float threshold = 1.0f - kernel_data.integrator.splitting_threshold;
- if(threshold == 1.0f){
+ const double threshold = (double)kernel_data.integrator.splitting_threshold;
+ if(threshold == 0.0){
return false;
- } else if(threshold == 0.0f){
+ } else if(threshold == 1.0){
return true;
}
@@ -63,101 +62,59 @@ ccl_device bool split(KernelGlobals *kg, ShaderData * sd, int node_offset,
const float3 bboxMin = make_float3( node1[0], node1[1], node1[2]);
const float3 bboxMax = make_float3( node1[3], node2[0], node2[1]);
- /* if P is inside bounding box then split */
- const float3 P = sd->P;
- const bool x_inside = (P[0] >= bboxMin[0] && P[0] <= bboxMax[0]);
- const bool y_inside = (P[1] >= bboxMin[1] && P[1] <= bboxMax[1]);
- const bool z_inside = (P[2] >= bboxMin[2] && P[2] <= bboxMax[2]);
- if(x_inside && y_inside && z_inside){
- return true; // Split
- }
-
- /* solid angle */
-
- /* approximate solid angle of bbox with solid angle of sphere */
- // From PBRT, todo: do for visible faces of bbox instead?
- const float3 centroid = 0.5f * (bboxMax + bboxMin);
- const float radius_squared = len_squared(bboxMax-centroid);
- const float dist_squared = len_squared(centroid-P);
-
- /* (---r---C )
- * \ /
- * \ th/ <--- d
- * \ /
- * P
- * sin(th) = r/d <=> sin^2(th) = r^2 / d^2 */
- const float sin_theta_max_squared = radius_squared / dist_squared;
- const float cos_theta_max = safe_sqrtf(max(0.0f,1.0f-sin_theta_max_squared));
- const float solid_angle = (dist_squared <= radius_squared)
- ? M_2PI_F : M_2PI_F * (1.0f - cos_theta_max);
-
- /* BSDF peak */
-
- /* TODO: Instead of randomly picking a BSDF, it might be better to
- * loop over the BSDFs for the point and see if there are any specular ones.
- * If so, pick one of these, otherwise, skip BSDF peak calculations. */
- const ShaderClosure *sc = shader_bsdf_pick(sd, &randu);
- if(sc == NULL) {
- return false; // TODO: handle this
- }
-
- float bsdf_peak = 1.0f;
-
- /* only sample BSDF if "highly specular" */
- /* TODO: This does not work as I expect, but it might be related to that we
- * currently consider non-specular BSDFs here too */
- if(bsdf_get_roughness_squared(sc) < 0.25f) {
- float3 eval;
- float bsdf_pdf;
- float3 bsdf_omega_in;
- differential3 bsdf_domega_in;
-
- bsdf_pdf = 0.0f;
- bsdf_sample(kg, sd, sc, randu, randv, &eval, &bsdf_omega_in,
- &bsdf_domega_in, &bsdf_pdf);
-
- /* TODO: More efficient to:
- * 1. Only sample direction
- * 2. If sampled direction points towards cluster
- * - Compute conservative cosine with vector to cluster center
- * - Evaluate simplified GGX for direction sampled direction or
- * vector to cluster?
- */
-
- if(bsdf_pdf != 0.0f && !is_zero(eval)){
-
- /* check if sampled direction is pointing towards the cluster */
- const float3 P_to_centroid = normalize(centroid - P);
- const float theta = acosf(dot(bsdf_omega_in, P_to_centroid));
- const float theta_max = acosf(cos_theta_max);
- if(theta <= theta_max){
-
- eval /= bsdf_pdf;
- const float BSDF = min(max3(eval), 1.0f);
-
- /* conservative cosine between dir to cluster's center and N */
- const float cosNI = dot(P_to_centroid, sd->N);
- const float NI = acosf(cosNI);
- /* TODO: Do something better than clamp here.
- * The problem: conservative_cosNI = cos(M_PI_2_F - theta_max)
- * for NI > PI/2 instead of 0 */
- const float conservative_NI = clamp(NI - theta_max,
- 0.0, M_PI_2_F - theta_max);
- const float conservative_cosNI = cosf(conservative_NI);
-
- bsdf_peak = BSDF * conservative_cosNI;
- }
- }
+ /* if P is inside bounding sphere then split */
+ const float3 centroid = 0.5f * (bboxMax + bboxMin);
+ const double radius_squared = (double)len_squared(bboxMax - centroid);
+ const double dist_squared = (double)len_squared(centroid - P);
+ if(dist_squared <= radius_squared){
+ return true;
}
- /* TODO: how to make it so bsdf_peak makes it more probable to split? */
- const float heuristic = solid_angle * bsdf_peak;
-
- /* normalize heuristic */
- const float normalized_heuristic = heuristic * M_1_PI_F * 0.5f;
-
- /* if heuristic is larger than the threshold then split */
- return normalized_heuristic > threshold;
+ /* eq. 8 & 9 */
+ /* observed precision issues and issues with overflow of num_emitters_squared.
+ * using doubles to fix this for now. */
+
+ /* Interval the distance can be in: [a,b] */
+ const double radius = sqrt(radius_squared);
+ const double dist = sqrt(dist_squared);
+ const double a = dist - radius;
+ const double b = dist + radius;
+
+ const double g_mean = 1.0 / (a * b);
+ const double g_mean_squared = g_mean * g_mean;
+ const double a3 = a * a * a;
+ const double b3 = b * b * b;
+ const double g_variance = (b3 - a3) / (3.0 * (b - a) * a3 * b3) -
+ g_mean_squared;
+
+ /* eq. 10 */
+ const float4 node0 = kernel_tex_fetch(__light_tree_nodes, node_offset );
+ const float4 node3 = kernel_tex_fetch(__light_tree_nodes, node_offset + 3);
+ const double energy = (double)node0[0];
+ const double e_variance = (double)node3[3];
+ const double num_emitters = (double)__float_as_int(node0[3]);
+
+ const double num_emitters_squared = num_emitters * num_emitters;
+ const double e_mean = energy / num_emitters;
+ const double e_mean_squared = e_mean * e_mean;
+ const double variance = (e_variance * (g_variance + g_mean_squared) +
+ e_mean_squared * g_variance) * num_emitters_squared;
+ /*
+ * If I run into further precision issues
+ * sigma^2 = (V[e] * (V[g] + E[g]^2) + (E[e]^2 * V[g]) * N^2 =
+ * = / V[e] = E[e^2] - E[e]^2 = ((e_1)^2 + (e_2)^2 +..+(e_N)^2)/N - E[e]^2 / =
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list