[Bf-blender-cvs] [5a3f8a6067d] soc-2020-production-ready-light-tree: Changed calulation of theta_u in tree importance.
Sam Kottler
noreply at git.blender.org
Fri Jun 26 23:03:53 CEST 2020
Commit: 5a3f8a6067d12e1965ed9875a448c74607af49ca
Author: Sam Kottler
Date: Fri Jun 26 14:56:48 2020 -0600
Branches: soc-2020-production-ready-light-tree
https://developer.blender.org/rB5a3f8a6067d12e1965ed9875a448c74607af49ca
Changed calulation of theta_u in tree importance.
This reduces artifacts when using the light tree without splitting.
Before the theta_u was calclulated using a bounding sphere to
approximate a bounding box. This sometimes resulted in the cone
containng the bounding box much, much too big. Now theta_u is found
more carefully so that it is the smallest angle such that the cone
completely contains the bounding box.
===================================================================
M intern/cycles/kernel/kernel_light.h
===================================================================
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 438176f9518..104df3ec8e2 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1177,6 +1177,7 @@ ccl_device float calc_importance(KernelGlobals *kg,
float3 P,
float3 N,
float3 bboxMax,
+ float3 bboxMin,
float theta_o,
float theta_e,
float3 axis,
@@ -1185,14 +1186,6 @@ ccl_device float calc_importance(KernelGlobals *kg,
{
/* 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 centroid_to_P = P - centroid;
const float3 centroid_to_P_dir = normalize(centroid_to_P);
const float r2 = len_squared(bboxMax - centroid);
@@ -1201,26 +1194,42 @@ ccl_device float calc_importance(KernelGlobals *kg,
/* 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);
+ d2 = fmaxf(d2, r2 * 0.25f);
}
+ /* "theta_u captures the solid angle of the entire box" */
+
float theta_u;
- if (d2 <= r2) {
- /* P is inside bounding sphere */
+ if (P.x < bboxMax.x && P.y < bboxMax.y && P.z < bboxMax.z && P.x > bboxMin.x &&
+ P.y > bboxMin.y && P.z > bboxMin.z) {
+ /* P is inside bounding box */
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 = fast_acosf(cos_theta_u);
+ /* Find the smallest cone that contains the bounding box by checking which bbox vertex is
+ * farthest out. If we use a bounding sphere we get a too big cone. For example consider a long
+ * skinny bbox oriented with P next to one of the small sides. */
+ theta_u = 0;
+ float3 corners[8];
+ corners[0] = bboxMin;
+ corners[1] = make_float3(bboxMin.x, bboxMin.y, bboxMax.z);
+ corners[2] = make_float3(bboxMin.x, bboxMax.y, bboxMin.z);
+ corners[3] = make_float3(bboxMin.x, bboxMax.y, bboxMax.z);
+ corners[4] = make_float3(bboxMax.x, bboxMin.y, bboxMin.z);
+ corners[5] = make_float3(bboxMax.x, bboxMin.y, bboxMax.z);
+ corners[6] = make_float3(bboxMax.x, bboxMax.y, bboxMin.z);
+ corners[7] = bboxMax;
+ for (int i = 0; i < 8; ++i) {
+ float3 P_to_corner = normalize(P - corners[i]);
+ const float cos_theta_u = dot(-centroid_to_P_dir, P_to_corner);
+ theta_u = fmaxf(fast_acosf(cos_theta_u), theta_u);
+ }
}
/* cos(theta') */
- float cos_theta = fabsf(dot(axis, centroid_to_P_dir));
- /* theta is the angle between the axis and the line between P and the centroid. There are two
- * such angles so take the smaller one. */
+ float cos_theta = dot(axis, centroid_to_P_dir);
const float theta = fast_acosf(cos_theta);
- const float theta_prime = fminf(fmaxf(theta - theta_o - theta_u, 0.0f), theta_e);
+ const float theta_prime = fmaxf(theta - theta_o - theta_u, 0.0f);
if (theta_prime >= theta_e) {
return 0.0f;
}
@@ -1228,7 +1237,8 @@ ccl_device float calc_importance(KernelGlobals *kg,
/* f_a|cos(theta'_i)| -- diffuse approximation */
if (N != make_float3(0.0f, 0.0f, 0.0f)) {
- const float theta_i = fast_acosf(dot(N, -centroid_to_P_dir));
+ const float cos_theta_i = dot(N, -centroid_to_P_dir);
+ const float theta_i = fast_acosf(cos_theta_i);
const float theta_i_prime = fmaxf(theta_i - theta_u, 0.0f);
const float cos_theta_i_prime = fast_cosf(theta_i_prime);
const float abs_cos_theta_i_prime = fabsf(cos_theta_i_prime);
@@ -1268,7 +1278,7 @@ ccl_device float calc_light_importance(
const float energy = data2.w;
const float3 centroid = 0.5f * (bbox_max + bbox_min);
- return calc_importance(kg, P, N, bbox_max, theta_o, theta_e, axis, energy, centroid);
+ return calc_importance(kg, P, N, bbox_max, bbox_min, theta_o, theta_e, axis, energy, centroid);
}
/* the combined energy, spatial and orientation bounds for all the lights for the
@@ -1291,7 +1301,7 @@ ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, float3 N, int
const float3 axis = make_float3(node3.x, node3.y, node3.z);
const float3 centroid = 0.5f * (bbox_max + bbox_min);
- return calc_importance(kg, P, N, bbox_max, theta_o, theta_e, axis, energy, centroid);
+ return calc_importance(kg, P, N, bbox_max, bbox_min, theta_o, theta_e, axis, energy, centroid);
}
/* given a node offset, this function loads and decodes the minimum amount of
@@ -1594,7 +1604,6 @@ ccl_device float light_tree_pdf(KernelGlobals *kg,
float pdf,
bool can_split)
{
-
/* find mapping from distribution_id to node_id */
int node_id = kernel_tex_fetch(__light_distribution_to_node, distribution_id);
More information about the Bf-blender-cvs
mailing list