Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/light/tree.h
| Show All 16 Lines | |||||
| #include "kernel/light/area.h" | #include "kernel/light/area.h" | ||||
| #include "kernel/light/common.h" | #include "kernel/light/common.h" | ||||
| #include "kernel/light/light.h" | #include "kernel/light/light.h" | ||||
| #include "kernel/light/spot.h" | #include "kernel/light/spot.h" | ||||
| #include "kernel/light/triangle.h" | #include "kernel/light/triangle.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* TODO: this seems like a relative expensive computation, and we can make it a lot cheaper | /* TODO: this seems like a relative expensive computation. We can make it a lot cheaper by using a | ||||
| * by using a bounding sphere instead of a bounding box. This will be more inaccurate, but it | * bounding sphere instead of a bounding box, but this will reduce the accuracy sometimes. */ | ||||
| * might be fine when used along with the adaptive splitting. */ | |||||
| ccl_device float light_tree_cos_bounding_box_angle(const BoundingBox bbox, | ccl_device float light_tree_cos_bounding_box_angle(const BoundingBox bbox, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 point_to_centroid) | const float3 point_to_centroid) | ||||
| { | { | ||||
| if (P.x > bbox.min.x && P.y > bbox.min.y && P.z > bbox.min.z && P.x < bbox.max.x && | if (P.x > bbox.min.x && P.y > bbox.min.y && P.z > bbox.min.z && P.x < bbox.max.x && | ||||
| P.y < bbox.max.y && P.z < bbox.max.z) { | P.y < bbox.max.y && P.z < bbox.max.z) { | ||||
| /* If P is inside the bbox, `theta_u` covers the whole sphere */ | /* If P is inside the bbox, `theta_u` covers the whole sphere. */ | ||||
| return -1.0f; | return -1.0f; | ||||
| } | } | ||||
| float cos_theta_u = 1.0f; | float cos_theta_u = 1.0f; | ||||
| /* Iterate through all 8 possible points of the bounding box. */ | /* Iterate through all 8 possible points of the bounding box. */ | ||||
| for (int i = 0; i < 8; ++i) { | for (int i = 0; i < 8; ++i) { | ||||
| const float3 corner = make_float3((i & 1) ? bbox.max.x : bbox.min.x, | const float3 corner = make_float3((i & 1) ? bbox.max.x : bbox.min.x, | ||||
| (i & 2) ? bbox.max.y : bbox.min.y, | (i & 2) ? bbox.max.y : bbox.min.y, | ||||
| (i & 4) ? bbox.max.z : bbox.min.z); | (i & 4) ? bbox.max.z : bbox.min.z); | ||||
| /* Calculate the bounding box angle. */ | /* Calculate the bounding box angle. */ | ||||
| float3 point_to_corner = normalize(corner - P); | float3 point_to_corner = normalize(corner - P); | ||||
| cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner)); | cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner)); | ||||
| } | } | ||||
| return cos_theta_u; | return cos_theta_u; | ||||
| } | } | ||||
| ccl_device_forceinline float sin_from_cos(const float c) | ccl_device_forceinline float sin_from_cos(const float c) | ||||
| { | { | ||||
| return safe_sqrtf(1.0f - sqr(c)); | return safe_sqrtf(1.0f - sqr(c)); | ||||
| } | } | ||||
| /* Compute vector v as in Fig .8. P_v is the corresponding point along the ray ccl_device float3 */ | /* Compute vector v as in Fig .8. P_v is the corresponding point along the ray. */ | ||||
| ccl_device float3 compute_v( | ccl_device float3 compute_v( | ||||
| const float3 centroid, const float3 P, const float3 D, const float3 bcone_axis, const float t) | const float3 centroid, const float3 P, const float3 D, const float3 bcone_axis, const float t) | ||||
| { | { | ||||
| const float3 unnormalized_v0 = P - centroid; | const float3 unnormalized_v0 = P - centroid; | ||||
| const float3 unnormalized_v1 = unnormalized_v0 + D * fminf(t, 1e12f); | const float3 unnormalized_v1 = unnormalized_v0 + D * fminf(t, 1e12f); | ||||
| const float3 v0 = normalize(unnormalized_v0); | const float3 v0 = normalize(unnormalized_v0); | ||||
| const float3 v1 = normalize(unnormalized_v1); | const float3 v1 = normalize(unnormalized_v1); | ||||
| Show All 25 Lines | ccl_device void light_tree_importance(const float3 N_or_D, | ||||
| ccl_private float &max_importance, | ccl_private float &max_importance, | ||||
| ccl_private float &min_importance) | ccl_private float &min_importance) | ||||
| { | { | ||||
| max_importance = 0.0f; | max_importance = 0.0f; | ||||
| min_importance = 0.0f; | min_importance = 0.0f; | ||||
| const float sin_theta_u = sin_from_cos(cos_theta_u); | const float sin_theta_u = sin_from_cos(cos_theta_u); | ||||
| /* cos(theta_i') in the paper, omitted for volume */ | /* cos(theta_i') in the paper, omitted for volume. */ | ||||
| float cos_min_incidence_angle = 1.0f; | float cos_min_incidence_angle = 1.0f; | ||||
| float cos_max_incidence_angle = 1.0f; | float cos_max_incidence_angle = 1.0f; | ||||
| /* when sampling the light tree for the second time in `shade_volume.h` and when query the pdf in | /* When sampling the light tree for the second time in `shade_volume.h` and when query the pdf in | ||||
| * `sample.h` */ | * `sample.h`. */ | ||||
| const bool in_volume = is_zero(N_or_D); | const bool in_volume = is_zero(N_or_D); | ||||
| if (!in_volume_segment && !in_volume) { | if (!in_volume_segment && !in_volume) { | ||||
| const float3 N = N_or_D; | const float3 N = N_or_D; | ||||
| const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) : | const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) : | ||||
| dot(point_to_centroid, N); | dot(point_to_centroid, N); | ||||
| const float sin_theta_i = sin_from_cos(cos_theta_i); | const float sin_theta_i = sin_from_cos(cos_theta_i); | ||||
| /* cos_min_incidence_angle = cos(max{theta_i - theta_u, 0}) = cos(theta_i') in the paper */ | /* cos_min_incidence_angle = cos(max{theta_i - theta_u, 0}) = cos(theta_i') in the paper */ | ||||
| cos_min_incidence_angle = cos_theta_i >= cos_theta_u ? | cos_min_incidence_angle = cos_theta_i >= cos_theta_u ? | ||||
| 1.0f : | 1.0f : | ||||
| cos_theta_i * cos_theta_u + sin_theta_i * sin_theta_u; | cos_theta_i * cos_theta_u + sin_theta_i * sin_theta_u; | ||||
| /* If the node is guaranteed to be behind the surface we're sampling, and the surface is | /* If the node is guaranteed to be behind the surface we're sampling, and the surface is | ||||
| * opaque, then we can give the node an importance of 0 as it contributes nothing to the | * opaque, then we can give the node an importance of 0 as it contributes nothing to the | ||||
| * surface. This is more accurate than the bbox test if we are calculating the importance of | * surface. This is more accurate than the bbox test if we are calculating the importance of | ||||
| * an emitter with radius */ | * an emitter with radius. */ | ||||
| if (!has_transmission && cos_min_incidence_angle < 0) { | if (!has_transmission && cos_min_incidence_angle < 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* cos_max_incidence_angle = cos(min{theta_i + theta_u, pi}) */ | /* cos_max_incidence_angle = cos(min{theta_i + theta_u, pi}) */ | ||||
| cos_max_incidence_angle = fmaxf(cos_theta_i * cos_theta_u - sin_theta_i * sin_theta_u, 0.0f); | cos_max_incidence_angle = fmaxf(cos_theta_i * cos_theta_u - sin_theta_i * sin_theta_u, 0.0f); | ||||
| } | } | ||||
| /* cos(theta - theta_u) */ | /* cos(theta - theta_u) */ | ||||
| const float cos_theta = dot(bcone.axis, -point_to_centroid); | const float cos_theta = dot(bcone.axis, -point_to_centroid); | ||||
| const float sin_theta = sin_from_cos(cos_theta); | const float sin_theta = sin_from_cos(cos_theta); | ||||
| const float cos_theta_minus_theta_u = cos_theta * cos_theta_u + sin_theta * sin_theta_u; | const float cos_theta_minus_theta_u = cos_theta * cos_theta_u + sin_theta * sin_theta_u; | ||||
| float cos_theta_o, sin_theta_o; | float cos_theta_o, sin_theta_o; | ||||
| fast_sincosf(bcone.theta_o, &sin_theta_o, &cos_theta_o); | fast_sincosf(bcone.theta_o, &sin_theta_o, &cos_theta_o); | ||||
| /* minimum angle an emitter’s axis would form with the direction to the shading point, | /* Minimum angle an emitter’s axis would form with the direction to the shading point, | ||||
| * cos(theta') in the paper */ | * cos(theta') in the paper. */ | ||||
| float cos_min_outgoing_angle; | float cos_min_outgoing_angle; | ||||
| if ((cos_theta >= cos_theta_u) || (cos_theta_minus_theta_u >= cos_theta_o)) { | if ((cos_theta >= cos_theta_u) || (cos_theta_minus_theta_u >= cos_theta_o)) { | ||||
| /* theta - theta_o - theta_u <= 0 */ | /* theta - theta_o - theta_u <= 0 */ | ||||
| kernel_assert((fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u)) < 5e-4f); | kernel_assert((fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u)) < 5e-4f); | ||||
| cos_min_outgoing_angle = 1.0f; | cos_min_outgoing_angle = 1.0f; | ||||
| } | } | ||||
| else if ((bcone.theta_o + bcone.theta_e > M_PI_F) || | else if ((bcone.theta_o + bcone.theta_e > M_PI_F) || | ||||
| (cos_theta_minus_theta_u > cos(bcone.theta_o + bcone.theta_e))) { | (cos_theta_minus_theta_u > cos(bcone.theta_o + bcone.theta_e))) { | ||||
| /* theta' = theta - theta_o - theta_u < theta_e */ | /* theta' = theta - theta_o - theta_u < theta_e */ | ||||
| kernel_assert( | kernel_assert( | ||||
| (fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u) - bcone.theta_e) < 5e-4f); | (fast_acosf(cos_theta) - bcone.theta_o - fast_acosf(cos_theta_u) - bcone.theta_e) < 5e-4f); | ||||
| const float sin_theta_minus_theta_u = sin_from_cos(cos_theta_minus_theta_u); | const float sin_theta_minus_theta_u = sin_from_cos(cos_theta_minus_theta_u); | ||||
| cos_min_outgoing_angle = cos_theta_minus_theta_u * cos_theta_o + | cos_min_outgoing_angle = cos_theta_minus_theta_u * cos_theta_o + | ||||
| sin_theta_minus_theta_u * sin_theta_o; | sin_theta_minus_theta_u * sin_theta_o; | ||||
| } | } | ||||
| else { | else { | ||||
| /* cluster invisible */ | /* Cluster is invisible. */ | ||||
| return; | return; | ||||
| } | } | ||||
| /* TODO: find a good approximation for f_a. */ | /* TODO: find a good approximation for f_a. */ | ||||
| const float f_a = 1.0f; | const float f_a = 1.0f; | ||||
| /* TODO: also consider t (or theta_a, theta_b) for volume */ | /* TODO: also consider t (or theta_a, theta_b) for volume */ | ||||
| max_importance = fabsf(f_a * cos_min_incidence_angle * energy * cos_min_outgoing_angle / | max_importance = fabsf(f_a * cos_min_incidence_angle * energy * cos_min_outgoing_angle / | ||||
| (in_volume_segment ? min_distance : sqr(min_distance))); | (in_volume_segment ? min_distance : sqr(min_distance))); | ||||
| Show All 32 Lines | if (prim_id < 0) { | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id); | ||||
| centroid = klight->co; | centroid = klight->co; | ||||
| switch (klight->type) { | switch (klight->type) { | ||||
| case LIGHT_SPOT: | case LIGHT_SPOT: | ||||
| dir = klight->spot.dir; | dir = klight->spot.dir; | ||||
| break; | break; | ||||
| case LIGHT_POINT: | case LIGHT_POINT: | ||||
| /* Disk-oriented normal */ | /* Disk-oriented normal. */ | ||||
| dir = safe_normalize(P - centroid); | dir = safe_normalize(P - centroid); | ||||
| break; | break; | ||||
| case LIGHT_AREA: | case LIGHT_AREA: | ||||
| dir = klight->area.dir; | dir = klight->area.dir; | ||||
| break; | break; | ||||
| case LIGHT_BACKGROUND: | case LIGHT_BACKGROUND: | ||||
| /* Aarbitrary centroid and direction */ | /* Arbitrary centroid and direction. */ | ||||
| centroid = make_float3(0.0f, 0.0f, 1.0f); | centroid = make_float3(0.0f, 0.0f, 1.0f); | ||||
| dir = make_float3(0.0f, 0.0f, -1.0f); | dir = make_float3(0.0f, 0.0f, -1.0f); | ||||
| return !in_volume_segment; | return !in_volume_segment; | ||||
| case LIGHT_DISTANT: | case LIGHT_DISTANT: | ||||
| dir = centroid; | dir = centroid; | ||||
| return !in_volume_segment; | return !in_volume_segment; | ||||
| default: | default: | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| const int object = kemitter->mesh_light.object_id; | const int object = kemitter->mesh_light.object_id; | ||||
| float3 vertices[3]; | float3 vertices[3]; | ||||
| triangle_world_space_vertices(kg, object, prim_id, -1.0f, vertices); | triangle_world_space_vertices(kg, object, prim_id, -1.0f, vertices); | ||||
| centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f; | centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f; | ||||
| if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_FRONT) { | if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_FRONT) { | ||||
| dir = safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0])); | dir = safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0])); | ||||
| } | } | ||||
| else if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_BACK) { | else if (kemitter->mesh_light.emission_sampling == EMISSION_SAMPLING_BACK) { | ||||
| dir = -safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0])); | dir = -safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0])); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Double sided: any vector in the plane. */ | /* Double-sided: any vector in the plane. */ | ||||
| dir = safe_normalize(vertices[0] - vertices[1]); | dir = safe_normalize(vertices[0] - vertices[1]); | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device void light_tree_emitter_importance(KernelGlobals kg, | ccl_device void light_tree_emitter_importance(KernelGlobals kg, | ||||
| Show All 21 Lines | if (!compute_emitter_centroid_and_dir<in_volume_segment>( | ||||
| kg, kemitter, P, centroid, bcone.axis)) { | kg, kemitter, P, centroid, bcone.axis)) { | ||||
| return; | return; | ||||
| } | } | ||||
| const int prim_id = kemitter->prim_id; | const int prim_id = kemitter->prim_id; | ||||
| if (in_volume_segment) { | if (in_volume_segment) { | ||||
| const float3 D = N_or_D; | const float3 D = N_or_D; | ||||
| /* Closest point */ | /* Closest point. */ | ||||
| P_c = P + dot(centroid - P, D) * D; | P_c = P + dot(centroid - P, D) * D; | ||||
| /* minimal distance of the ray to the cluster */ | /* Minimal distance of the ray to the cluster. */ | ||||
| distance.x = len(centroid - P_c); | distance.x = len(centroid - P_c); | ||||
| distance.y = distance.x; | distance.y = distance.x; | ||||
| point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t); | point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t); | ||||
| } | } | ||||
| else { | else { | ||||
| P_c = P; | P_c = P; | ||||
| } | } | ||||
| bool is_visible; | bool is_visible; | ||||
| if (prim_id < 0) { | if (prim_id < 0) { | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id); | ||||
| switch (klight->type) { | switch (klight->type) { | ||||
| /* Function templates only modifies cos_theta_u when in_volume_segment = true */ | /* Function templates only modifies cos_theta_u when in_volume_segment = true. */ | ||||
| case LIGHT_SPOT: | case LIGHT_SPOT: | ||||
| is_visible = spot_light_tree_parameters<in_volume_segment>( | is_visible = spot_light_tree_parameters<in_volume_segment>( | ||||
| klight, centroid, P_c, cos_theta_u, distance, point_to_centroid); | klight, centroid, P_c, cos_theta_u, distance, point_to_centroid); | ||||
| break; | break; | ||||
| case LIGHT_POINT: | case LIGHT_POINT: | ||||
| is_visible = point_light_tree_parameters<in_volume_segment>( | is_visible = point_light_tree_parameters<in_volume_segment>( | ||||
| klight, centroid, P_c, cos_theta_u, distance, point_to_centroid); | klight, centroid, P_c, cos_theta_u, distance, point_to_centroid); | ||||
| bcone.theta_o = 0.0f; | bcone.theta_o = 0.0f; | ||||
| Show All 9 Lines | switch (klight->type) { | ||||
| case LIGHT_DISTANT: | case LIGHT_DISTANT: | ||||
| is_visible = distant_light_tree_parameters( | is_visible = distant_light_tree_parameters( | ||||
| centroid, bcone.theta_e, cos_theta_u, distance, point_to_centroid); | centroid, bcone.theta_e, cos_theta_u, distance, point_to_centroid); | ||||
| break; | break; | ||||
| default: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| else { /* mesh light */ | else { /* Mesh light. */ | ||||
| is_visible = triangle_light_tree_parameters<in_volume_segment>( | is_visible = triangle_light_tree_parameters<in_volume_segment>( | ||||
| kg, kemitter, centroid, P_c, N_or_D, bcone, cos_theta_u, distance, point_to_centroid); | kg, kemitter, centroid, P_c, N_or_D, bcone, cos_theta_u, distance, point_to_centroid); | ||||
| } | } | ||||
| is_visible |= has_transmission; | is_visible |= has_transmission; | ||||
| if (!is_visible) { | if (!is_visible) { | ||||
| return; | return; | ||||
| } | } | ||||
| Show All 19 Lines | ccl_device void light_tree_node_importance(KernelGlobals kg, | ||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const ccl_global KernelLightTreeNode *knode, | const ccl_global KernelLightTreeNode *knode, | ||||
| ccl_private float &max_importance, | ccl_private float &max_importance, | ||||
| ccl_private float &min_importance) | ccl_private float &min_importance) | ||||
| { | { | ||||
| max_importance = 0.0f; | max_importance = 0.0f; | ||||
| min_importance = 0.0f; | min_importance = 0.0f; | ||||
| if (knode->num_prims == 1) { | if (knode->num_prims == 1) { | ||||
| /* At a leaf node with only one emitter */ | /* At a leaf node with only one emitter. */ | ||||
| light_tree_emitter_importance<in_volume_segment>( | light_tree_emitter_importance<in_volume_segment>( | ||||
| kg, P, N_or_D, t, has_transmission, -knode->child_index, max_importance, min_importance); | kg, P, N_or_D, t, has_transmission, -knode->child_index, max_importance, min_importance); | ||||
| } | } | ||||
| else if (knode->num_prims != 0) { | else if (knode->num_prims != 0) { | ||||
| const BoundingCone bcone = knode->bcone; | const BoundingCone bcone = knode->bcone; | ||||
| const BoundingBox bbox = knode->bbox; | const BoundingBox bbox = knode->bbox; | ||||
| float3 point_to_centroid; | float3 point_to_centroid; | ||||
| float cos_theta_u; | float cos_theta_u; | ||||
| float distance; | float distance; | ||||
| if (knode->bit_trail == 1) { | if (knode->bit_trail == 1) { | ||||
| /* distant light node */ | /* Distant light node. */ | ||||
| if (in_volume_segment) { | if (in_volume_segment) { | ||||
| return; | return; | ||||
| } | } | ||||
| point_to_centroid = -bcone.axis; | point_to_centroid = -bcone.axis; | ||||
| cos_theta_u = fast_cosf(bcone.theta_o); | cos_theta_u = fast_cosf(bcone.theta_o); | ||||
| distance = 1.0f; | distance = 1.0f; | ||||
| } | } | ||||
| else { | else { | ||||
| const float3 centroid = 0.5f * (bbox.min + bbox.max); | const float3 centroid = 0.5f * (bbox.min + bbox.max); | ||||
| if (in_volume_segment) { | if (in_volume_segment) { | ||||
| const float3 D = N_or_D; | const float3 D = N_or_D; | ||||
| const float3 closest_point = P + dot(centroid - P, D) * D; | const float3 closest_point = P + dot(centroid - P, D) * D; | ||||
| /* minimal distance of the ray to the cluster */ | /* Minimal distance of the ray to the cluster. */ | ||||
| distance = len(centroid - closest_point); | distance = len(centroid - closest_point); | ||||
| point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t); | point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t); | ||||
| cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid); | cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid); | ||||
| } | } | ||||
| else { | else { | ||||
| const float3 N = N_or_D; | const float3 N = N_or_D; | ||||
| const float3 bbox_extent = bbox.max - centroid; | const float3 bbox_extent = bbox.max - centroid; | ||||
| const bool bbox_is_visible = has_transmission | | const bool bbox_is_visible = has_transmission | | ||||
| (dot(N, centroid - P) + dot(fabs(N), fabs(bbox_extent)) > 0); | (dot(N, centroid - P) + dot(fabs(N), fabs(bbox_extent)) > 0); | ||||
| /* If the node is guaranteed to be behind the surface we're sampling, and the surface is | /* If the node is guaranteed to be behind the surface we're sampling, and the surface is | ||||
| * opaque, then we can give the node an importance of 0 as it contributes nothing to the | * opaque, then we can give the node an importance of 0 as it contributes nothing to the | ||||
| * surface. */ | * surface. */ | ||||
| if (!bbox_is_visible) { | if (!bbox_is_visible) { | ||||
| return; | return; | ||||
| } | } | ||||
| point_to_centroid = normalize_len(centroid - P, &distance); | point_to_centroid = normalize_len(centroid - P, &distance); | ||||
| cos_theta_u = light_tree_cos_bounding_box_angle(bbox, P, point_to_centroid); | cos_theta_u = light_tree_cos_bounding_box_angle(bbox, P, point_to_centroid); | ||||
| } | } | ||||
| /* clamp distance to half the radius of the cluster when splitting is disabled */ | /* Clamp distance to half the radius of the cluster when splitting is disabled. */ | ||||
| distance = fmaxf(0.5f * len(centroid - bbox.max), distance); | distance = fmaxf(0.5f * len(centroid - bbox.max), distance); | ||||
| } | } | ||||
| /* TODO: currently max_distance = min_distance, max_importance = min_importance for the | /* TODO: currently max_distance = min_distance, max_importance = min_importance for the | ||||
| * nodes. Do we need better weights for complex scenes? */ | * nodes. Do we need better weights for complex scenes? */ | ||||
| light_tree_importance<in_volume_segment>(N_or_D, | light_tree_importance<in_volume_segment>(N_or_D, | ||||
| has_transmission, | has_transmission, | ||||
| point_to_centroid, | point_to_centroid, | ||||
| cos_theta_u, | cos_theta_u, | ||||
| Show All 26 Lines | ccl_device void sample_resevoir(const int current_index, | ||||
| } | } | ||||
| else { | else { | ||||
| rand = (rand - thresh) / (1.0f - thresh); | rand = (rand - thresh) / (1.0f - thresh); | ||||
| } | } | ||||
| kernel_assert(rand >= 0.0f && rand <= 1.0f); | kernel_assert(rand >= 0.0f && rand <= 1.0f); | ||||
| return; | return; | ||||
| } | } | ||||
| /* pick an emitter from a leaf node using resevoir sampling, keep two reservoirs for upper and | /* Pick an emitter from a leaf node using resevoir sampling, keep two reservoirs for upper and | ||||
| * lower bounds */ | * lower bounds. */ | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg, | ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg, | ||||
| ccl_private float &rand, | ccl_private float &rand, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N_or_D, | const float3 N_or_D, | ||||
| const float t, | const float t, | ||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const ccl_global KernelLightTreeNode *knode, | const ccl_global KernelLightTreeNode *knode, | ||||
| ccl_private float *pdf_factor) | ccl_private float *pdf_factor) | ||||
| { | { | ||||
| float selected_importance[2] = {0.0f, 0.0f}; | float selected_importance[2] = {0.0f, 0.0f}; | ||||
| float total_importance[2] = {0.0f, 0.0f}; | float total_importance[2] = {0.0f, 0.0f}; | ||||
| int selected_index = -1; | int selected_index = -1; | ||||
| /* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0 */ | /* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0. */ | ||||
| kernel_assert(knode->num_prims <= sizeof(uint) * 8); | kernel_assert(knode->num_prims <= sizeof(uint) * 8); | ||||
| uint has_importance = 0; | uint has_importance = 0; | ||||
| const bool sample_max = (rand > 0.5f); /* sampling using the maximum importance */ | const bool sample_max = (rand > 0.5f); /* Sampling using the maximum importance. */ | ||||
| rand = rand * 2.0f - float(sample_max); | rand = rand * 2.0f - float(sample_max); | ||||
| for (int i = 0; i < knode->num_prims; i++) { | for (int i = 0; i < knode->num_prims; i++) { | ||||
| int current_index = -knode->child_index + i; | int current_index = -knode->child_index + i; | ||||
| /* maximum importance = importance[0], minimum importance = importance[1] */ | /* maximum importance = importance[0], minimum importance = importance[1] */ | ||||
| float importance[2]; | float importance[2]; | ||||
| light_tree_emitter_importance<in_volume_segment>( | light_tree_emitter_importance<in_volume_segment>( | ||||
| kg, P, N_or_D, t, has_transmission, current_index, importance[0], importance[1]); | kg, P, N_or_D, t, has_transmission, current_index, importance[0], importance[1]); | ||||
| Show All 12 Lines | for (int i = 0; i < knode->num_prims; i++) { | ||||
| has_importance |= ((importance[0] > 0) << i); | has_importance |= ((importance[0] > 0) << i); | ||||
| } | } | ||||
| if (total_importance[0] == 0.0f) { | if (total_importance[0] == 0.0f) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (total_importance[1] == 0.0f) { | if (total_importance[1] == 0.0f) { | ||||
| /* uniformly sample emitters with positive maximum importance */ | /* Uniformly sample emitters with positive maximum importance. */ | ||||
| if (sample_max) { | if (sample_max) { | ||||
| selected_importance[1] = 1.0f; | selected_importance[1] = 1.0f; | ||||
| total_importance[1] = float(popcount(has_importance)); | total_importance[1] = float(popcount(has_importance)); | ||||
| } | } | ||||
| else { | else { | ||||
| selected_index = -1; | selected_index = -1; | ||||
| for (int i = 0; i < knode->num_prims; i++) { | for (int i = 0; i < knode->num_prims; i++) { | ||||
| int current_index = -knode->child_index + i; | int current_index = -knode->child_index + i; | ||||
| Show All 38 Lines | light_tree_node_importance<in_volume_segment>( | ||||
| kg, P, N_or_D, t, has_transmission, right, max_right_importance, min_right_importance); | kg, P, N_or_D, t, has_transmission, right, max_right_importance, min_right_importance); | ||||
| const float total_max_importance = max_left_importance + max_right_importance; | const float total_max_importance = max_left_importance + max_right_importance; | ||||
| if (total_max_importance == 0.0f) { | if (total_max_importance == 0.0f) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const float total_min_importance = min_left_importance + min_right_importance; | const float total_min_importance = min_left_importance + min_right_importance; | ||||
| /* average two probabilities of picking the left child node using lower and upper bounds */ | /* Average two probabilities of picking the left child node using lower and upper bounds. */ | ||||
| const float probability_max = max_left_importance / total_max_importance; | const float probability_max = max_left_importance / total_max_importance; | ||||
| const float probability_min = total_min_importance > 0 ? | const float probability_min = total_min_importance > 0 ? | ||||
| min_left_importance / total_min_importance : | min_left_importance / total_min_importance : | ||||
| 0.5f * (float(max_left_importance > 0) + | 0.5f * (float(max_left_importance > 0) + | ||||
| float(max_right_importance == 0.0f)); | float(max_right_importance == 0.0f)); | ||||
| left_probability = 0.5f * (probability_max + probability_min); | left_probability = 0.5f * (probability_max + probability_min); | ||||
| return true; | return true; | ||||
| } | } | ||||
| Show All 15 Lines | if (!kernel_data.integrator.use_direct_light) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION); | const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION); | ||||
| float pdf_leaf = 1.0f; | float pdf_leaf = 1.0f; | ||||
| float pdf_emitter_from_leaf = 1.0f; | float pdf_emitter_from_leaf = 1.0f; | ||||
| int selected_light = -1; | int selected_light = -1; | ||||
| int node_index = 0; /* root node */ | int node_index = 0; /* Root node. */ | ||||
| /* Traverse the light tree until a leaf node is reached. */ | /* Traverse the light tree until a leaf node is reached. */ | ||||
| while (true) { | while (true) { | ||||
| const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index); | const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index); | ||||
| if (knode->child_index <= 0) { | if (knode->child_index <= 0) { | ||||
| /* At a leaf node, we pick an emitter */ | /* At a leaf node, we pick an emitter. */ | ||||
| selected_light = light_tree_cluster_select_emitter<in_volume_segment>( | selected_light = light_tree_cluster_select_emitter<in_volume_segment>( | ||||
| kg, randv, P, N_or_D, t, has_transmission, knode, &pdf_emitter_from_leaf); | kg, randv, P, N_or_D, t, has_transmission, knode, &pdf_emitter_from_leaf); | ||||
| break; | break; | ||||
| } | } | ||||
| /* At an interior node, the left child is directly after the parent, | /* At an interior node, the left child is directly after the parent, while the right child is | ||||
| * while the right child is stored as the child index. */ | * stored as the child index. */ | ||||
| const int left_index = node_index + 1; | const int left_index = node_index + 1; | ||||
| const int right_index = knode->child_index; | const int right_index = knode->child_index; | ||||
| float left_prob; | float left_prob; | ||||
| if (!get_left_probability<in_volume_segment>( | if (!get_left_probability<in_volume_segment>( | ||||
| kg, P, N_or_D, t, has_transmission, left_index, right_index, left_prob)) { | kg, P, N_or_D, t, has_transmission, left_index, right_index, left_prob)) { | ||||
| return false; /* both child nodes have zero importance */ | return false; /* Both child nodes have zero importance. */ | ||||
| } | } | ||||
| float discard; | float discard; | ||||
| float total_prob = left_prob; | float total_prob = left_prob; | ||||
| node_index = left_index; | node_index = left_index; | ||||
| sample_resevoir(right_index, 1.0f - left_prob, node_index, discard, total_prob, randu); | sample_resevoir(right_index, 1.0f - left_prob, node_index, discard, total_prob, randu); | ||||
| pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob); | pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob); | ||||
| } | } | ||||
| if (selected_light < 0) { | if (selected_light < 0) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Sample a point on the chosen emitter */ | /* Sample a point on the chosen emitter. */ | ||||
| ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ||||
| selected_light); | selected_light); | ||||
| /* TODO: this is the same code as light_distribution_sample, except the index is determined | /* TODO: this is the same code as light_distribution_sample, except the index is determined | ||||
| * differently. Would it be better to refactor this into a separate function? */ | * differently. Would it be better to refactor this into a separate function? */ | ||||
| const int prim = kemitter->prim_id; | const int prim = kemitter->prim_id; | ||||
| if (prim >= 0) { | if (prim >= 0) { | ||||
| /* Mesh light. */ | /* Mesh light. */ | ||||
| Show All 26 Lines | ccl_device_noinline bool light_tree_sample(KernelGlobals kg, | ||||
| return (ls->pdf > 0); | return (ls->pdf > 0); | ||||
| } | } | ||||
| /* We need to be able to find the probability of selecting a given light for MIS. */ | /* We need to be able to find the probability of selecting a given light for MIS. */ | ||||
| ccl_device float light_tree_pdf( | ccl_device float light_tree_pdf( | ||||
| KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int prim) | KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int prim) | ||||
| { | { | ||||
| const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION); | const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION); | ||||
| /* Target emitter info */ | /* Target emitter info. */ | ||||
| const int target_emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) : | const int target_emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) : | ||||
| kernel_data_fetch(light_to_tree, ~prim); | kernel_data_fetch(light_to_tree, ~prim); | ||||
| ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ||||
| target_emitter); | target_emitter); | ||||
| const int target_leaf = kemitter->parent_index; | const int target_leaf = kemitter->parent_index; | ||||
| ccl_global const KernelLightTreeNode *kleaf = &kernel_data_fetch(light_tree_nodes, target_leaf); | ccl_global const KernelLightTreeNode *kleaf = &kernel_data_fetch(light_tree_nodes, target_leaf); | ||||
| uint bit_trail = kleaf->bit_trail; | uint bit_trail = kleaf->bit_trail; | ||||
| int node_index = 0; /* root node */ | int node_index = 0; /* Root node. */ | ||||
| float pdf = 1.0f; | float pdf = 1.0f; | ||||
| /* Traverse the light tree until we reach the target leaf node */ | /* Traverse the light tree until we reach the target leaf node. */ | ||||
| while (true) { | while (true) { | ||||
| const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index); | const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, node_index); | ||||
| if (knode->child_index <= 0) { | if (knode->child_index <= 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| /* Interior node */ | /* Interior node. */ | ||||
| const int left_index = node_index + 1; | const int left_index = node_index + 1; | ||||
| const int right_index = knode->child_index; | const int right_index = knode->child_index; | ||||
| float left_prob; | float left_prob; | ||||
| if (!get_left_probability<false>( | if (!get_left_probability<false>( | ||||
| kg, P, N, 0, has_transmission, left_index, right_index, left_prob)) { | kg, P, N, 0, has_transmission, left_index, right_index, left_prob)) { | ||||
| return 0.0f; | return 0.0f; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines | |||||