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. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs