Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/light/tree.h
| Show All 34 Lines | for (int i = 0; i < 8; ++i) { | ||||
| /* Figure out whether or not the bounding box is in front or behind the shading point. */ | /* Figure out whether or not the bounding box is in front or behind the shading point. */ | ||||
| bbox_is_visible |= dot(point_to_corner, N) > 0; | bbox_is_visible |= dot(point_to_corner, N) > 0; | ||||
| } | } | ||||
| return cos_theta_u; | return cos_theta_u; | ||||
| } | } | ||||
| /* This is the general function for calculating the importance of either a cluster or an emitter. | /* This is the general function for calculating the importance of either a cluster or an emitter. | ||||
| * Both of the specialized functions obtain the necessary data before calling this function. */ | * Both of the specialized functions obtain the necessary data before calling this function. */ | ||||
| ccl_device void light_tree_cluster_importance(const float3 N, | template<bool in_volume_segment> | ||||
| ccl_device void light_tree_cluster_importance(const float3 N_or_D, | |||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const float3 point_to_centroid, | const float3 point_to_centroid, | ||||
| /* point_to_centroid is unnormalized for volume */ | |||||
| const float cos_theta_u, | const float cos_theta_u, | ||||
| const float3 bcone_axis, | const float3 bcone_axis, | ||||
| const float inv_max_distance_squared, | const float max_distance, | ||||
| const float inv_min_distance_squared, | const float min_distance, | ||||
| const float t, | |||||
| const float theta_o, | const float theta_o, | ||||
| const float theta_e, | const float theta_e, | ||||
| const float energy, | const float energy, | ||||
| 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 cos_theta = dot(bcone_axis, -point_to_centroid); | float cos_theta, cos_theta_i, sin_theta_i; | ||||
| const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) : | float cos_min_outgoing_angle; /* minimum angle an emitter’s axis would form with the | ||||
| dot(point_to_centroid, N); | direction to the shading point, cos(theta') in the paper */ | ||||
| const float sin_theta_i = safe_sqrtf(1.0f - sqr(cos_theta_i)); | float cos_min_incidence_angle = 1.0f; /* cos(theta_i') in the paper, omitted for volume */ | ||||
| const float sin_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_u)); | const float sin_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_u)); | ||||
| if (in_volume_segment) { | |||||
| const float3 D = N_or_D; | |||||
| const float3 v0 = -normalize(point_to_centroid); | |||||
| const float3 v1 = normalize(-point_to_centroid + D * fminf(t, 1e12f)); | |||||
| const float3 o0 = v0; | |||||
| float3 o1, o2; | |||||
| make_orthonormals_tangent(o0, v1, &o1, &o2); | |||||
| const float dot_o0_a = dot(o0, bcone_axis); | |||||
| const float dot_o1_a = dot(o1, bcone_axis); | |||||
| const float cos_phi0 = dot_o0_a / sqrtf(sqr(dot_o0_a) + sqr(dot_o1_a)); | |||||
| /* Eq. (6) */ | |||||
| cos_theta = (dot_o1_a < 0 || dot(v0, v1) > cos_phi0) ? | |||||
| fmaxf(dot_o0_a, dot(v1, bcone_axis)) : /* b_max */ | |||||
| dot(bcone_axis, cos_phi0 * o0 + safe_sqrtf(1.0f - sqr(cos_phi0)) * o1); | |||||
| } | |||||
| else { | |||||
| const float3 N = N_or_D; | |||||
| cos_theta = dot(bcone_axis, -point_to_centroid); | |||||
| cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) : dot(point_to_centroid, N); | |||||
| sin_theta_i = safe_sqrtf(1.0f - sqr(cos_theta_i)); | |||||
| /* cos_min_incidence_angle = cos(max{theta_i - theta_u, 0}), also cos(theta_i') in the paper*/ | /* cos_min_incidence_angle = cos(max{theta_i - theta_u, 0}), also cos(theta_i') in the paper*/ | ||||
| const float 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 opaque, | /* If the node is guaranteed to be behind the surface we're sampling, and the surface is | ||||
| * then we can give the node an importance of 0 as it contributes nothing to the surface. | * opaque, then we can give the node an importance of 0 as it contributes nothing to the | ||||
| * This is more accurate than the bbox test if we are calculating the importance of an emitter | * surface. This is more accurate than the bbox test if we are calculating the importance of an | ||||
| * with radius */ | * emitter with radius */ | ||||
| if (!has_transmission && cos_min_incidence_angle < 0) { | if (!has_transmission && cos_min_incidence_angle < 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| } | |||||
| /* cos(theta - theta_u) */ | /* cos(theta - theta_u) */ | ||||
| const float sin_theta = safe_sqrtf(1.0f - sqr(cos_theta)); | const float sin_theta = safe_sqrtf(1.0f - sqr(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(theta_o, &sin_theta_o, &cos_theta_o); | fast_sincosf(theta_o, &sin_theta_o, &cos_theta_o); | ||||
| float cos_min_outgoing_angle; /* minimum angle an emitter’s normal would form with the direction | |||||
| to the shading point, cos(theta') in the paper */ | |||||
| 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) - theta_o - fast_acosf(cos_theta_u)) < 5e-4f); | kernel_assert((fast_acosf(cos_theta) - theta_o - fast_acosf(cos_theta_u)) < 5e-4f); | ||||
| cos_min_outgoing_angle = 1.0f; | cos_min_outgoing_angle = 1.0f; | ||||
| } | } | ||||
| else if ((cos_theta > cos_theta_u) || (theta_o + theta_e > M_PI_F) || | else if ((cos_theta > cos_theta_u) || (theta_o + theta_e > M_PI_F) || | ||||
| (cos_theta_minus_theta_u > cos(theta_o + theta_e))) { | (cos_theta_minus_theta_u > cos(theta_o + theta_e))) { | ||||
| /* theta' = theta - theta_o - theta_u < theta_e */ | /* theta' = theta - theta_o - theta_u < theta_e */ | ||||
| kernel_assert((fast_acosf(cos_theta) - theta_o - fast_acosf(cos_theta_u) - theta_e) < 5e-4f); | kernel_assert((fast_acosf(cos_theta) - theta_o - fast_acosf(cos_theta_u) - theta_e) < 5e-4f); | ||||
| const float sin_theta_minus_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_minus_theta_u)); | const float sin_theta_minus_theta_u = safe_sqrtf(1.0f - sqr(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 */ | |||||
| 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; | ||||
| max_importance = fabsf(f_a * cos_min_incidence_angle * energy * inv_min_distance_squared * | /* TODO: also consider t (or theta_a, theta_b) for volume */ | ||||
| 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))); | |||||
| if (inv_max_distance_squared == inv_min_distance_squared) { | /* TODO: also min importance for volume? */ | ||||
| if (max_distance == min_distance || in_volume_segment) { | |||||
| min_importance = max_importance; | min_importance = max_importance; | ||||
| return; | return; | ||||
| } | } | ||||
| /* compute mininum importance */ | |||||
| /* cos_max_incidence_angle = cos(min{theta_i + theta_u, pi}) */ | /* cos_max_incidence_angle = cos(min{theta_i + theta_u, pi}) */ | ||||
| const float cos_max_incidence_angle = fmaxf( | const float cos_max_incidence_angle = fmaxf( | ||||
| cos_theta_i * cos_theta_u - sin_theta_i * sin_theta_u, 0.0f); | cos_theta_i * cos_theta_u - sin_theta_i * sin_theta_u, 0.0f); | ||||
| /* cos(theta + theta_o + theta_u) if theta + theta_o + theta_u < theta_e, 0 otherwise */ | /* cos(theta + theta_o + theta_u) if theta + theta_o + theta_u < theta_e, 0 otherwise */ | ||||
| float cos_max_outgoing_angle; | float cos_max_outgoing_angle; | ||||
| const float cos_theta_plus_theta_u = cos_theta * cos_theta_u - sin_theta * sin_theta_u; | const float cos_theta_plus_theta_u = cos_theta * cos_theta_u - sin_theta * sin_theta_u; | ||||
| if (theta_e - theta_o < 0 || cos_theta < 0 || cos_theta_u < 0 || | if (theta_e - theta_o < 0 || cos_theta < 0 || cos_theta_u < 0 || | ||||
| cos_theta_plus_theta_u < cos(theta_e - theta_o)) { | cos_theta_plus_theta_u < cos(theta_e - theta_o)) { | ||||
| min_importance = 0.f; | min_importance = 0.0f; | ||||
| } | } | ||||
| else { | else { | ||||
| const float sin_theta_plus_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_plus_theta_u)); | const float sin_theta_plus_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_plus_theta_u)); | ||||
| cos_max_outgoing_angle = cos_theta_plus_theta_u * cos_theta_o - | cos_max_outgoing_angle = cos_theta_plus_theta_u * cos_theta_o - | ||||
| sin_theta_plus_theta_u * sin_theta_o; | sin_theta_plus_theta_u * sin_theta_o; | ||||
| min_importance = fabsf(f_a * cos_max_incidence_angle * energy * inv_max_distance_squared * | min_importance = fabsf(f_a * cos_max_incidence_angle * energy * cos_max_outgoing_angle / | ||||
| cos_max_outgoing_angle); | sqr(max_distance)); | ||||
| } | } | ||||
| } | } | ||||
| /* This is uniformly sampling the reservoir for now. */ | /* This is uniformly sampling the reservoir for now. */ | ||||
| ccl_device float light_tree_emitter_reservoir_weight(KernelGlobals kg, | ccl_device float light_tree_emitter_reservoir_weight(KernelGlobals kg, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N, | ||||
| int emitter_index) | int emitter_index) | ||||
| { | { | ||||
| if (emitter_index < 0) { | if (emitter_index < 0) { | ||||
| return 0.0f; | return 0.0f; | ||||
| } | } | ||||
| /* TODO: reservoir is disabled for now */ | |||||
| return 1.0f; | |||||
| ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ||||
| emitter_index); | emitter_index); | ||||
| const int prim = kemitter->prim_id; | const int prim = kemitter->prim_id; | ||||
| /* Triangles are handled normally for now. */ | /* Triangles are handled normally for now. */ | ||||
| if (prim < 0) { | if (prim < 0) { | ||||
| const int lamp = -prim - 1; | const int lamp = -prim - 1; | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); | ||||
| /* We use a special calculation to check if a light is | /* We use a special calculation to check if a light is | ||||
| * within the bounds of a spot or area light. */ | * within the bounds of a spot or area light. */ | ||||
| if (klight->type == LIGHT_SPOT) { | if (klight->type == LIGHT_SPOT) { | ||||
| return spot_light_tree_weight(klight, P, N); | return spot_light_tree_weight(klight, P, N); | ||||
| } | } | ||||
| else if (klight->type == LIGHT_AREA) { | else if (klight->type == LIGHT_AREA) { | ||||
| return area_light_tree_weight(klight, P, N); | return area_light_tree_weight(klight, P, N); | ||||
| } | } | ||||
| } | } | ||||
| return 1.0f; | return 1.0f; | ||||
| } | } | ||||
| template<bool in_volume_segment> | |||||
| ccl_device void light_tree_emitter_importance(KernelGlobals kg, | ccl_device void light_tree_emitter_importance(KernelGlobals kg, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N_or_D, | ||||
| const float t, | |||||
| const bool has_transmission, | const bool has_transmission, | ||||
| int emitter_index, | int emitter_index, | ||||
| ccl_private float &max_importance, | ccl_private float &max_importance, | ||||
| ccl_private float &min_importance) | ccl_private float &min_importance) | ||||
| { | { | ||||
| ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, | ||||
| emitter_index); | emitter_index); | ||||
| float3 bcone_axis = make_float3(kemitter->bounding_cone_axis[0], | float3 bcone_axis = make_float3(kemitter->bounding_cone_axis[0], | ||||
| kemitter->bounding_cone_axis[1], | kemitter->bounding_cone_axis[1], | ||||
| kemitter->bounding_cone_axis[2]); | kemitter->bounding_cone_axis[2]); | ||||
| float theta_o = kemitter->theta_o; | float theta_o = kemitter->theta_o; | ||||
| float cos_theta_u, inv_max_distance_squared, inv_min_distance_squared; | float cos_theta_u, max_distance, min_distance; | ||||
| float3 point_to_centroid; | float3 centroid, point_to_centroid; | ||||
| bool bbox_is_visible = has_transmission; | bool bbox_is_visible = has_transmission; | ||||
| const int prim = kemitter->prim_id; | const int prim = kemitter->prim_id; | ||||
| if (prim < 0) { | if (prim < 0) { | ||||
| const int lamp = -prim - 1; | const int lamp = -prim - 1; | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); | ||||
| const float3 centroid = make_float3(klight->co[0], klight->co[1], klight->co[2]); | centroid = make_float3(klight->co[0], klight->co[1], klight->co[2]); | ||||
| if (klight->type == LIGHT_SPOT || klight->type == LIGHT_POINT) { | if (klight->type == LIGHT_SPOT || klight->type == LIGHT_POINT) { | ||||
| const float radius = klight->spot.radius; | const float radius = klight->spot.radius; | ||||
| float distance; | float distance; | ||||
| point_to_centroid = safe_normalize_len(centroid - P, &distance); | point_to_centroid = safe_normalize_len(centroid - P, &distance); | ||||
| min_distance = distance; | |||||
| inv_min_distance_squared = 1.0f / sqr(distance); | max_distance = sqrtf(sqr(radius) + sqr(distance)); | ||||
| inv_max_distance_squared = 1.0f / (sqr(radius) + sqr(distance)); | const float hypotenus = max_distance; | ||||
| const float inv_hypotenus = safe_sqrtf(inv_max_distance_squared); | cos_theta_u = distance / hypotenus; | ||||
| cos_theta_u = distance * inv_hypotenus; | |||||
| bbox_is_visible = true; /* will be tested later */ | bbox_is_visible = true; /* will be tested later */ | ||||
| } | } | ||||
| else { /* TODO: support area light */ | else { /* TODO: support area light */ | ||||
| const float3 bbox_min = make_float3(kemitter->bounding_box_min[0], | const float3 bbox_min = make_float3(kemitter->bounding_box_min[0], | ||||
| kemitter->bounding_box_min[1], | kemitter->bounding_box_min[1], | ||||
| kemitter->bounding_box_min[2]); | kemitter->bounding_box_min[2]); | ||||
| const float3 bbox_max = make_float3(kemitter->bounding_box_max[0], | const float3 bbox_max = make_float3(kemitter->bounding_box_max[0], | ||||
| kemitter->bounding_box_max[1], | kemitter->bounding_box_max[1], | ||||
| kemitter->bounding_box_max[2]); | kemitter->bounding_box_max[2]); | ||||
| const float3 centroid = 0.5f * (bbox_min + bbox_max); | centroid = 0.5f * (bbox_min + bbox_max); | ||||
| float distance; | float distance; | ||||
| point_to_centroid = normalize_len(centroid - P, &distance); | point_to_centroid = normalize_len(centroid - P, &distance); | ||||
| const float inv_distance_squared = 1.0f / fmaxf(0.25f * len_squared(centroid - bbox_max), | max_distance = distance; | ||||
| sqr(distance)); | min_distance = distance; | ||||
| inv_max_distance_squared = inv_distance_squared; | |||||
| inv_min_distance_squared = inv_distance_squared; | |||||
| cos_theta_u = light_tree_cos_bounding_box_angle( | cos_theta_u = light_tree_cos_bounding_box_angle( | ||||
| bbox_min, bbox_max, P, N, point_to_centroid, bbox_is_visible); | bbox_min, bbox_max, P, N_or_D, point_to_centroid, bbox_is_visible); | ||||
| } | } | ||||
| if (klight->type == LIGHT_POINT) { | if (klight->type == LIGHT_POINT) { | ||||
| bcone_axis = -point_to_centroid; /* disk oriented normal */ | bcone_axis = -point_to_centroid; /* disk oriented normal */ | ||||
| theta_o = 0.f; | theta_o = 0.0f; | ||||
| } | } | ||||
| } | } | ||||
| else { /* TODO: support mesh light */ | else { /* TODO: support mesh light */ | ||||
| const float3 bbox_min = make_float3(kemitter->bounding_box_min[0], | const float3 bbox_min = make_float3(kemitter->bounding_box_min[0], | ||||
| kemitter->bounding_box_min[1], | kemitter->bounding_box_min[1], | ||||
| kemitter->bounding_box_min[2]); | kemitter->bounding_box_min[2]); | ||||
| const float3 bbox_max = make_float3(kemitter->bounding_box_max[0], | const float3 bbox_max = make_float3(kemitter->bounding_box_max[0], | ||||
| kemitter->bounding_box_max[1], | kemitter->bounding_box_max[1], | ||||
| kemitter->bounding_box_max[2]); | kemitter->bounding_box_max[2]); | ||||
| const float3 centroid = 0.5f * (bbox_min + bbox_max); | centroid = 0.5f * (bbox_min + bbox_max); | ||||
| float distance; | float distance; | ||||
| point_to_centroid = normalize_len(centroid - P, &distance); | point_to_centroid = normalize_len(centroid - P, &distance); | ||||
| const float inv_distance_squared = 1.0f / fmaxf(0.25f * len_squared(centroid - bbox_max), | max_distance = distance; | ||||
| sqr(distance)); | min_distance = distance; | ||||
| inv_max_distance_squared = inv_distance_squared; | |||||
| inv_min_distance_squared = inv_distance_squared; | |||||
| cos_theta_u = light_tree_cos_bounding_box_angle( | cos_theta_u = light_tree_cos_bounding_box_angle( | ||||
| bbox_min, bbox_max, P, N, point_to_centroid, bbox_is_visible); | bbox_min, bbox_max, P, N_or_D, point_to_centroid, bbox_is_visible); | ||||
| } | } | ||||
| if (!bbox_is_visible) { | if (!bbox_is_visible) { | ||||
| max_importance = 0.0f; | max_importance = 0.0f; | ||||
| min_importance = 0.0f; | min_importance = 0.0f; | ||||
| return; | return; | ||||
| } | } | ||||
| light_tree_cluster_importance(N, | /* TODO: better measure for single emitter */ | ||||
| if (in_volume_segment) { | |||||
| const float3 D = N_or_D; | |||||
| const float3 closest_point = P + D * dot(point_to_centroid, D); | |||||
| /* minimal distance of the ray to the cluster */ | |||||
| min_distance = len(centroid - closest_point); | |||||
| max_distance = min_distance; | |||||
| point_to_centroid = centroid - P; | |||||
| } | |||||
| light_tree_cluster_importance<in_volume_segment>(N_or_D, | |||||
| has_transmission, | has_transmission, | ||||
| point_to_centroid, | point_to_centroid, | ||||
| cos_theta_u, | cos_theta_u, | ||||
| bcone_axis, | bcone_axis, | ||||
| inv_max_distance_squared, | max_distance, | ||||
| inv_min_distance_squared, | min_distance, | ||||
| t, | |||||
| theta_o, | theta_o, | ||||
| kemitter->theta_e, | kemitter->theta_e, | ||||
| kemitter->energy, | kemitter->energy, | ||||
| max_importance, | max_importance, | ||||
| min_importance); | min_importance); | ||||
| } | } | ||||
| ccl_device bool light_tree_should_split(KernelGlobals kg, | ccl_device bool light_tree_should_split(KernelGlobals kg, | ||||
| const float3 P, | const float3 P, | ||||
| const ccl_global KernelLightTreeNode *knode) | const ccl_global KernelLightTreeNode *knode) | ||||
| { | { | ||||
| /* TODO: don't split because it introduces variance. Maybe delete relevant field and functions | /* TODO: don't split because it introduces variance. Maybe delete relevant field and functions | ||||
| * later. */ | * later. */ | ||||
| Show All 30 Lines | ccl_device bool light_tree_should_split(KernelGlobals kg, | ||||
| const float V_g = (b - a) * (b - a) * E_g * E_g * E_g / 3.0f; | const float V_g = (b - a) * (b - a) * E_g * E_g * E_g / 3.0f; | ||||
| const float V_e = knode->energy_variance; | const float V_e = knode->energy_variance; | ||||
| const float total_variance = V_e * V_g + V_e * E_g * E_g + E_e * E_e * V_g; | const float total_variance = V_e * V_g + V_e * E_g * E_g + E_e * E_e * V_g; | ||||
| const float normalized_variance = sqrt(sqrt(1.0f / (1.0f + sqrt(total_variance)))); | const float normalized_variance = sqrt(sqrt(1.0f / (1.0f + sqrt(total_variance)))); | ||||
| return (normalized_variance < splitting_threshold); | return (normalized_variance < splitting_threshold); | ||||
| } | } | ||||
| template<bool in_volume_segment> | |||||
| ccl_device void light_tree_node_importance(KernelGlobals kg, | ccl_device void light_tree_node_importance(KernelGlobals kg, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N_or_D, | ||||
| const float t, | |||||
| 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) | ||||
| { | { | ||||
| if (knode->child_index <= 0 && knode->num_prims == 1) { | if (knode->child_index <= 0 && knode->num_prims == 1) { | ||||
| /* at a leaf node and there is only one emitter */ | /* at a leaf node and there is only one emitter */ | ||||
| light_tree_emitter_importance( | light_tree_emitter_importance<in_volume_segment>( | ||||
| kg, P, N, 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 { | else { | ||||
| const float3 bbox_min = make_float3( | const float3 bbox_min = make_float3( | ||||
| knode->bounding_box_min[0], knode->bounding_box_min[1], knode->bounding_box_min[2]); | knode->bounding_box_min[0], knode->bounding_box_min[1], knode->bounding_box_min[2]); | ||||
| const float3 bbox_max = make_float3( | const float3 bbox_max = make_float3( | ||||
| knode->bounding_box_max[0], knode->bounding_box_max[1], knode->bounding_box_max[2]); | knode->bounding_box_max[0], knode->bounding_box_max[1], knode->bounding_box_max[2]); | ||||
| const float3 bcone_axis = make_float3( | const float3 bcone_axis = make_float3( | ||||
| knode->bounding_cone_axis[0], knode->bounding_cone_axis[1], knode->bounding_cone_axis[2]); | knode->bounding_cone_axis[0], knode->bounding_cone_axis[1], knode->bounding_cone_axis[2]); | ||||
| const float3 centroid = 0.5f * (bbox_min + bbox_max); | const float3 centroid = 0.5f * (bbox_min + bbox_max); | ||||
| float distance; | float distance; | ||||
| const float3 point_to_centroid = normalize_len(centroid - P, &distance); | float3 point_to_centroid = normalize_len(centroid - P, &distance); | ||||
| bool bbox_is_visible = has_transmission; | bool bbox_is_visible = has_transmission; | ||||
| float cos_theta_u = light_tree_cos_bounding_box_angle( | float cos_theta_u = light_tree_cos_bounding_box_angle( | ||||
| bbox_min, bbox_max, P, N, point_to_centroid, bbox_is_visible); | bbox_min, bbox_max, P, N_or_D, point_to_centroid, bbox_is_visible); | ||||
| /* 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) { | ||||
| max_importance = 0.0f; | max_importance = 0.0f; | ||||
| min_importance = 0.0f; | min_importance = 0.0f; | ||||
| return; | return; | ||||
| } | } | ||||
| /* TODO: we're using the splitting heuristic now, do we still need to clamp the distance to | if (in_volume_segment) { | ||||
| * half the radius of the cluster? */ | const float3 D = N_or_D; | ||||
| const float inv_distance_squared = 1.0f / fmaxf(0.25f * len_squared(centroid - bbox_max), | const float3 closest_point = P + D * dot(point_to_centroid, D); | ||||
| sqr(distance)); | /* minimal distance of the ray to the cluster */ | ||||
| distance = len(centroid - closest_point); | |||||
| point_to_centroid = centroid - P; | |||||
| } | |||||
| /* clamp distance to half the radius of the cluster when splitting is disabled */ | |||||
| distance = fmaxf(0.5f * len(centroid - bbox_max), distance); | |||||
| /* TODO: currently max_distance = min_distance, max_importance = min_importance for the nodes. | /* TODO: currently max_distance = min_distance, max_importance = min_importance for the nodes. | ||||
| * Do we need better weights for complex scenes? */ | * Do we need better weights for complex scenes? */ | ||||
| light_tree_cluster_importance(N, | light_tree_cluster_importance<in_volume_segment>(N_or_D, | ||||
| has_transmission, | has_transmission, | ||||
| point_to_centroid, | point_to_centroid, | ||||
| cos_theta_u, | cos_theta_u, | ||||
| bcone_axis, | bcone_axis, | ||||
| inv_distance_squared, | distance, | ||||
| inv_distance_squared, | distance, | ||||
| t, | |||||
| knode->theta_o, | knode->theta_o, | ||||
| knode->theta_e, | knode->theta_e, | ||||
| knode->energy, | knode->energy, | ||||
| max_importance, | max_importance, | ||||
| min_importance); | min_importance); | ||||
| } | } | ||||
| } | } | ||||
| ccl_device_inline void sample_resevoir(const int current_index, | ccl_device_inline void sample_resevoir(const int current_index, | ||||
| const float current_weight, | const float current_weight, | ||||
| ccl_private int &selected_index, | ccl_private int &selected_index, | ||||
| ccl_private float &selected_weight, | ccl_private float &selected_weight, | ||||
| ccl_private float &total_weight, | ccl_private float &total_weight, | ||||
| Show All 12 Lines | ccl_device_inline void sample_resevoir(const int current_index, | ||||
| else { | else { | ||||
| *rand = (*rand - thresh) / (1.0f - thresh); | *rand = (*rand - thresh) / (1.0f - thresh); | ||||
| } | } | ||||
| 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> | |||||
| ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg, | ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg, | ||||
| ccl_private float *randu, | ccl_private float *randu, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N_or_D, | ||||
| 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) | ||||
| { | { | ||||
| /* the first emitter in the cluster */ | /* the first emitter in the cluster */ | ||||
| int selected_prim_index_max = -knode->child_index; | int selected_prim_index_max = -knode->child_index; | ||||
| float max_importance, min_importance; | float max_importance, min_importance; | ||||
| light_tree_emitter_importance( | light_tree_emitter_importance<in_volume_segment>( | ||||
| kg, P, N, has_transmission, selected_prim_index_max, max_importance, min_importance); | kg, P, N_or_D, t, has_transmission, selected_prim_index_max, max_importance, min_importance); | ||||
| float selected_max_importance = max_importance; | float selected_max_importance = max_importance; | ||||
| float total_max_importance = max_importance; | float total_max_importance = max_importance; | ||||
| int selected_prim_index_min = selected_prim_index_max; | int selected_prim_index_min = selected_prim_index_max; | ||||
| float total_min_importance = min_importance; | float total_min_importance = min_importance; | ||||
| float selected_min_importance = min_importance; | float selected_min_importance = min_importance; | ||||
| for (int i = 1; i < knode->num_prims; i++) { | for (int i = 1; i < knode->num_prims; i++) { | ||||
| int current_prim_index = -knode->child_index + i; | int current_prim_index = -knode->child_index + i; | ||||
| light_tree_emitter_importance( | light_tree_emitter_importance<in_volume_segment>( | ||||
| kg, P, N, has_transmission, current_prim_index, max_importance, min_importance); | kg, P, N_or_D, t, has_transmission, current_prim_index, max_importance, min_importance); | ||||
| /* resevoir sampling using the maximum weights */ | /* resevoir sampling using the maximum weights */ | ||||
| sample_resevoir(current_prim_index, | sample_resevoir(current_prim_index, | ||||
| max_importance, | max_importance, | ||||
| selected_prim_index_max, | selected_prim_index_max, | ||||
| selected_max_importance, | selected_max_importance, | ||||
| total_max_importance, | total_max_importance, | ||||
| randu); | randu); | ||||
| Show All 38 Lines | ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg, | ||||
| } | } | ||||
| *pdf_factor = 0.5f * (selected_min_importance / total_min_importance + | *pdf_factor = 0.5f * (selected_min_importance / total_min_importance + | ||||
| selected_max_importance / total_max_importance); | selected_max_importance / total_max_importance); | ||||
| return selected_prim_index; | return selected_prim_index; | ||||
| } | } | ||||
| /* to-do: for now, we're not going to worry about being in a volume, | |||||
| * but this is how the other function determines whether we're in a volume or not. */ | |||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device bool light_tree_sample(KernelGlobals kg, | ccl_device bool light_tree_sample(KernelGlobals kg, | ||||
| ccl_private const RNGState *rng_state, | ccl_private const RNGState *rng_state, | ||||
| ccl_private float *randu, | ccl_private float *randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N_or_D, | ||||
| const float t, | |||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const int path_flag, | const int path_flag, | ||||
| const int bounce, | const int bounce, | ||||
| ccl_private LightSample *ls, | ccl_private LightSample *ls, | ||||
| ccl_private float *pdf_factor) | ccl_private float *pdf_factor) | ||||
| { | { | ||||
| /* We keep track of the currently selected primitive and its weight, | /* We keep track of the currently selected primitive and its weight, | ||||
| * as well as the total weight as part of the weighted reservoir sampling. */ | * as well as the total weight as part of the weighted reservoir sampling. */ | ||||
| Show All 17 Lines | while (stack_index >= 0) { | ||||
| const float pdf_node_selection = pdfs_node_selection[stack_index]; | const float pdf_node_selection = pdfs_node_selection[stack_index]; | ||||
| const int index = stack[stack_index]; | const int index = stack[stack_index]; | ||||
| const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, index); | const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, index); | ||||
| /* If we're at a leaf node, we choose a primitive. Otherwise, we check if we should split | /* If we're at a leaf node, we choose a primitive. Otherwise, we check if we should split | ||||
| * or traverse down the light tree. */ | * or traverse down the light tree. */ | ||||
| if (knode->child_index <= 0) { | if (knode->child_index <= 0) { | ||||
| float pdf_emitter_selection = 1.0f; | float pdf_emitter_selection = 1.0f; | ||||
| const int selected_light = light_tree_cluster_select_emitter( | const int selected_light = light_tree_cluster_select_emitter<in_volume_segment>( | ||||
| kg, randu, P, N, has_transmission, knode, &pdf_emitter_selection); | kg, randu, P, N_or_D, t, has_transmission, knode, &pdf_emitter_selection); | ||||
| if (selected_light < 0) { | if (selected_light < 0) { | ||||
| stack_index--; | stack_index--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| const float light_reservoir_weight = light_tree_emitter_reservoir_weight( | const float light_reservoir_weight = light_tree_emitter_reservoir_weight( | ||||
| kg, P, N, selected_light); | kg, P, N_or_D, selected_light); | ||||
| /* TODO: make pdf_node_emitter_selection part of the light_reservoir_weight, otherwise result | /* TODO: make pdf_node_emitter_selection part of the light_reservoir_weight, otherwise result | ||||
| * is suboptimal. */ | * is suboptimal, or disable splitting and remove reservoir-related code . */ | ||||
| if (light_reservoir_weight == 0.0f) { | if (light_reservoir_weight == 0.0f) { | ||||
| stack_index--; | stack_index--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| total_reservoir_weight += light_reservoir_weight; | total_reservoir_weight += light_reservoir_weight; | ||||
| /* We compute the probability of switching to the new candidate sample, | /* We compute the probability of switching to the new candidate sample, | ||||
| * otherwise we stick with the old one. */ | * otherwise we stick with the old one. */ | ||||
| Show All 27 Lines | while (stack_index >= 0) { | ||||
| } | } | ||||
| /* If we don't split, then we need to choose sampling between the left or right child. */ | /* If we don't split, then we need to choose sampling between the left or right child. */ | ||||
| const ccl_global KernelLightTreeNode *left = &kernel_data_fetch(light_tree_nodes, left_index); | const ccl_global KernelLightTreeNode *left = &kernel_data_fetch(light_tree_nodes, left_index); | ||||
| const ccl_global KernelLightTreeNode *right = &kernel_data_fetch(light_tree_nodes, | const ccl_global KernelLightTreeNode *right = &kernel_data_fetch(light_tree_nodes, | ||||
| right_index); | right_index); | ||||
| float min_left_importance, max_left_importance, min_right_importance, max_right_importance; | float min_left_importance, max_left_importance, min_right_importance, max_right_importance; | ||||
| light_tree_node_importance( | light_tree_node_importance<in_volume_segment>( | ||||
| kg, P, N, has_transmission, left, max_left_importance, min_left_importance); | kg, P, N_or_D, t, has_transmission, left, max_left_importance, min_left_importance); | ||||
| light_tree_node_importance( | light_tree_node_importance<in_volume_segment>( | ||||
| kg, P, N, 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; | ||||
| const float total_min_importance = min_left_importance + min_right_importance; | const float total_min_importance = min_left_importance + min_right_importance; | ||||
| if (total_max_importance == 0.0f) { | if (total_max_importance == 0.0f) { | ||||
| stack_index--; | stack_index--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | ccl_device bool light_tree_sample(KernelGlobals kg, | ||||
| if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { | if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return light_sample<in_volume_segment>(kg, lamp, *randu, randv, P, path_flag, ls); | return light_sample<in_volume_segment>(kg, lamp, *randu, randv, P, path_flag, ls); | ||||
| } | } | ||||
| template<bool in_volume_segment> | |||||
| ccl_device float light_tree_distant_light_importance(KernelGlobals kg, | ccl_device float light_tree_distant_light_importance(KernelGlobals kg, | ||||
| const float3 N, | const float3 N, | ||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const int index) | const int index) | ||||
| { | { | ||||
| if (in_volume_segment) { | |||||
| return 0.0f; | |||||
| } | |||||
| ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch( | ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch( | ||||
| light_tree_distant_group, index); | light_tree_distant_group, index); | ||||
| if (kdistant->energy == 0.0f) { | if (kdistant->energy == 0.0f) { | ||||
| return 0.0f; | return 0.0f; | ||||
| } | } | ||||
| const float3 light_axis = make_float3( | const float3 light_axis = make_float3( | ||||
| Show All 26 Lines | |||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device bool light_tree_sample_distant_lights(KernelGlobals kg, | ccl_device bool light_tree_sample_distant_lights(KernelGlobals kg, | ||||
| ccl_private const RNGState *rng_state, | ccl_private const RNGState *rng_state, | ||||
| ccl_private float *randu, | ccl_private float *randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N, | ||||
| const float t, | |||||
| const bool has_transmission, | const bool has_transmission, | ||||
| const int path_flag, | const int path_flag, | ||||
| const int bounce, | const int bounce, | ||||
| ccl_private LightSample *ls, | ccl_private LightSample *ls, | ||||
| ccl_private float *pdf_factor) | ccl_private float *pdf_factor) | ||||
| { | { | ||||
| kernel_assert(!in_volume_segment); | |||||
| /* TODO: do single loop over lights to avoid computing importance twice? */ | /* TODO: do single loop over lights to avoid computing importance twice? */ | ||||
| const int num_distant_lights = kernel_data.integrator.num_distant_lights; | const int num_distant_lights = kernel_data.integrator.num_distant_lights; | ||||
| float total_importance = 0.0f; | float total_importance = 0.0f; | ||||
| for (int i = 0; i < num_distant_lights; i++) { | for (int i = 0; i < num_distant_lights; i++) { | ||||
| total_importance += light_tree_distant_light_importance(kg, N, has_transmission, i); | total_importance += light_tree_distant_light_importance<in_volume_segment>( | ||||
| kg, N, has_transmission, i); | |||||
| } | } | ||||
| if (total_importance == 0.0f) { | if (total_importance == 0.0f) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| float light_cdf = 0.0f; | float light_cdf = 0.0f; | ||||
| for (int i = 0; i < num_distant_lights; i++) { | for (int i = 0; i < num_distant_lights; i++) { | ||||
| const float light_pdf = light_tree_distant_light_importance(kg, N, has_transmission, i) / | const float light_pdf = light_tree_distant_light_importance<in_volume_segment>( | ||||
| kg, N, has_transmission, i) / | |||||
| total_importance; | total_importance; | ||||
| if (*randu <= light_cdf + light_pdf) { | if (*randu <= light_cdf + light_pdf) { | ||||
| *randu = (*randu - light_cdf) / light_pdf; | *randu = (*randu - light_cdf) / light_pdf; | ||||
| *pdf_factor *= light_pdf; | *pdf_factor *= light_pdf; | ||||
| ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch( | ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch( | ||||
| light_tree_distant_group, i); | light_tree_distant_group, i); | ||||
| const int lamp = kdistant->prim_id; | const int lamp = kdistant->prim_id; | ||||
| Show All 19 Lines | |||||
| ccl_device float light_tree_pdf(KernelGlobals kg, | ccl_device float light_tree_pdf(KernelGlobals kg, | ||||
| ConstIntegratorState state, | ConstIntegratorState state, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N, | ||||
| const int path_flag, | const int path_flag, | ||||
| const int prim) | 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); | ||||
| float distant_light_importance = light_tree_distant_light_importance( | float distant_light_importance = light_tree_distant_light_importance<false>( | ||||
| kg, N, has_transmission, kernel_data.integrator.num_distant_lights); | kg, N, has_transmission, kernel_data.integrator.num_distant_lights); | ||||
| float light_tree_importance = 0.0f; | float light_tree_importance = 0.0f; | ||||
| if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | ||||
| const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | ||||
| float discard; | float discard; | ||||
| light_tree_node_importance(kg, P, N, has_transmission, kroot, light_tree_importance, discard); | light_tree_node_importance<false>( | ||||
| kg, P, N, 0, has_transmission, kroot, light_tree_importance, discard); | |||||
| } | } | ||||
| const float total_group_importance = light_tree_importance + distant_light_importance; | const float total_group_importance = light_tree_importance + distant_light_importance; | ||||
| kernel_assert(total_group_importance != 0.0f); | kernel_assert(total_group_importance != 0.0f); | ||||
| float pdf = light_tree_importance / total_group_importance; | float pdf = light_tree_importance / total_group_importance; | ||||
| 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, | ||||
| Show All 38 Lines | if (knode->child_index <= 0) { | ||||
| if (index == target_leaf) { | if (index == target_leaf) { | ||||
| float target_max_importance = 0.0f; | float target_max_importance = 0.0f; | ||||
| float target_min_importance = 0.0f; | float target_min_importance = 0.0f; | ||||
| float total_max_importance = 0.0f; | float total_max_importance = 0.0f; | ||||
| float total_min_importance = 0.0f; | float total_min_importance = 0.0f; | ||||
| for (int i = 0; i < knode->num_prims; i++) { | for (int i = 0; i < knode->num_prims; i++) { | ||||
| const int emitter = -knode->child_index + i; | const int emitter = -knode->child_index + i; | ||||
| float max_importance, min_importance; | float max_importance, min_importance; | ||||
| light_tree_emitter_importance( | light_tree_emitter_importance<false>( | ||||
| kg, P, N, has_transmission, emitter, max_importance, min_importance); | kg, P, N, 0, has_transmission, emitter, max_importance, min_importance); | ||||
| if (emitter == target_emitter) { | if (emitter == target_emitter) { | ||||
| target_max_importance = max_importance; | target_max_importance = max_importance; | ||||
| target_min_importance = min_importance; | target_min_importance = min_importance; | ||||
| selected_reservoir_weight = light_tree_emitter_reservoir_weight(kg, P, N, emitter); | selected_reservoir_weight = light_tree_emitter_reservoir_weight(kg, P, N, emitter); | ||||
| total_reservoir_weight += selected_reservoir_weight; | total_reservoir_weight += selected_reservoir_weight; | ||||
| } | } | ||||
| total_max_importance += max_importance; | total_max_importance += max_importance; | ||||
| total_min_importance += min_importance; | total_min_importance += min_importance; | ||||
| Show All 10 Lines | if (knode->child_index <= 0) { | ||||
| } | } | ||||
| else { | else { | ||||
| pdf = 0.0f; | pdf = 0.0f; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| int selected_light = -1; | int selected_light = -1; | ||||
| float pdf_emitter_selection = 1.0f; | float pdf_emitter_selection = 1.0f; | ||||
| selected_light = light_tree_cluster_select_emitter( | selected_light = light_tree_cluster_select_emitter<false>( | ||||
| kg, &randu, P, N, has_transmission, knode, &pdf_emitter_selection); | kg, &randu, P, N, 0, has_transmission, knode, &pdf_emitter_selection); | ||||
| if (selected_light < 0) { | if (selected_light < 0) { | ||||
| stack_index--; | stack_index--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| total_reservoir_weight += light_tree_emitter_reservoir_weight(kg, P, N, selected_light); | total_reservoir_weight += light_tree_emitter_reservoir_weight(kg, P, N, selected_light); | ||||
| } | } | ||||
| Show All 15 Lines | while (stack_index >= 0) { | ||||
| } | } | ||||
| /* No splitting, choose between the left or the right child */ | /* No splitting, choose between the left or the right child */ | ||||
| const ccl_global KernelLightTreeNode *left = &kernel_data_fetch(light_tree_nodes, left_index); | const ccl_global KernelLightTreeNode *left = &kernel_data_fetch(light_tree_nodes, left_index); | ||||
| const ccl_global KernelLightTreeNode *right = &kernel_data_fetch(light_tree_nodes, | const ccl_global KernelLightTreeNode *right = &kernel_data_fetch(light_tree_nodes, | ||||
| right_index); | right_index); | ||||
| float min_left_importance, max_left_importance, min_right_importance, max_right_importance; | float min_left_importance, max_left_importance, min_right_importance, max_right_importance; | ||||
| light_tree_node_importance( | light_tree_node_importance<false>( | ||||
| kg, P, N, has_transmission, left, max_left_importance, min_left_importance); | kg, P, N, 0, has_transmission, left, max_left_importance, min_left_importance); | ||||
| light_tree_node_importance( | light_tree_node_importance<false>( | ||||
| kg, P, N, has_transmission, right, max_right_importance, min_right_importance); | kg, P, N, 0, 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; | ||||
| const float total_min_importance = min_left_importance + min_right_importance; | const float total_min_importance = min_left_importance + min_right_importance; | ||||
| if (total_max_importance == 0.0f) { | if (total_max_importance == 0.0f) { | ||||
| stack_index--; | stack_index--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| Show All 20 Lines | ccl_device float light_tree_pdf(KernelGlobals kg, | ||||
| } | } | ||||
| return pdf; | return pdf; | ||||
| } | } | ||||
| ccl_device float light_tree_pdf_distant( | ccl_device float light_tree_pdf_distant( | ||||
| 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); | ||||
| float distant_light_importance = light_tree_distant_light_importance( | float distant_light_importance = light_tree_distant_light_importance<false>( | ||||
| kg, N, has_transmission, kernel_data.integrator.num_distant_lights); | kg, N, has_transmission, kernel_data.integrator.num_distant_lights); | ||||
| float light_tree_importance = 0.0f; | float light_tree_importance = 0.0f; | ||||
| if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | ||||
| const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | ||||
| float discard; | float discard; | ||||
| light_tree_node_importance(kg, P, N, has_transmission, kroot, light_tree_importance, discard); | light_tree_node_importance<false>( | ||||
| kg, P, N, 0, has_transmission, kroot, light_tree_importance, discard); | |||||
| } | } | ||||
| const float total_group_importance = light_tree_importance + distant_light_importance; | const float total_group_importance = light_tree_importance + distant_light_importance; | ||||
| kernel_assert(total_group_importance != 0.0f); | kernel_assert(total_group_importance != 0.0f); | ||||
| float pdf = distant_light_importance / total_group_importance; | float pdf = distant_light_importance / total_group_importance; | ||||
| /* The light_to_tree array doubles as a lookup table for | /* The light_to_tree array doubles as a lookup table for | ||||
| * both the light tree as well as the distant lights group.*/ | * both the light tree as well as the distant lights group.*/ | ||||
| const int distant_light = kernel_data_fetch(light_to_tree, prim); | const int distant_light = kernel_data_fetch(light_to_tree, prim); | ||||
| const int num_distant_lights = kernel_data.integrator.num_distant_lights; | const int num_distant_lights = kernel_data.integrator.num_distant_lights; | ||||
| float emitter_importance = 0.0f; | float emitter_importance = 0.0f; | ||||
| float total_importance = 0.0f; | float total_importance = 0.0f; | ||||
| for (int i = 0; i < num_distant_lights; i++) { | for (int i = 0; i < num_distant_lights; i++) { | ||||
| float importance = light_tree_distant_light_importance(kg, N, has_transmission, i); | float importance = light_tree_distant_light_importance<false>(kg, N, has_transmission, i); | ||||
| if (i == distant_light) { | if (i == distant_light) { | ||||
| emitter_importance = importance; | emitter_importance = importance; | ||||
| } | } | ||||
| total_importance += importance; | total_importance += importance; | ||||
| } | } | ||||
| pdf *= emitter_importance / total_importance; | pdf *= emitter_importance / total_importance; | ||||
| return pdf; | return pdf; | ||||
| } | } | ||||
| template<bool in_volume_segment> | template<bool in_volume_segment> | ||||
| ccl_device bool light_tree_sample(KernelGlobals kg, | ccl_device bool light_tree_sample(KernelGlobals kg, | ||||
| ccl_private const RNGState *rng_state, | ccl_private const RNGState *rng_state, | ||||
| float randu, | float randu, | ||||
| const float randv, | const float randv, | ||||
| const float time, | const float time, | ||||
| const float3 P, | const float3 P, | ||||
| const float3 N, | const float3 N_or_D, | ||||
| const float t, | |||||
| const int shader_flags, | const int shader_flags, | ||||
| const int bounce, | const int bounce, | ||||
| const uint32_t path_flag, | const uint32_t path_flag, | ||||
| ccl_private LightSample *ls) | ccl_private LightSample *ls) | ||||
| { | { | ||||
| const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION); | const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION); | ||||
| kernel_assert(!in_volume_segment || (in_volume_segment && has_transmission)); | |||||
| /* TODO: add distant lights to light tree (as one child node of the root node) */ | /* TODO: add distant lights to light tree (as one child node of the root node) */ | ||||
| float distant_light_importance = light_tree_distant_light_importance( | float distant_light_importance = light_tree_distant_light_importance<in_volume_segment>( | ||||
| kg, N, has_transmission, kernel_data.integrator.num_distant_lights); | kg, N_or_D, has_transmission, kernel_data.integrator.num_distant_lights); | ||||
| float light_tree_importance = 0.0f; | float light_tree_importance = 0.0f; | ||||
| if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { | ||||
| const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); | ||||
| float discard; | float discard; | ||||
| light_tree_node_importance(kg, P, N, has_transmission, kroot, light_tree_importance, discard); | light_tree_node_importance<in_volume_segment>( | ||||
| kg, P, N_or_D, t, has_transmission, kroot, light_tree_importance, discard); | |||||
| } | } | ||||
| const float total_importance = light_tree_importance + distant_light_importance; | const float total_importance = light_tree_importance + distant_light_importance; | ||||
| if (total_importance == 0.0f) { | if (total_importance == 0.0f) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const float light_tree_probability = light_tree_importance / total_importance; | const float light_tree_probability = light_tree_importance / total_importance; | ||||
| float pdf_factor = 1.0f; | float pdf_factor = 1.0f; | ||||
| bool ret; | bool ret; | ||||
| if (randu <= light_tree_probability) { | if (randu <= light_tree_probability) { | ||||
| randu = randu / light_tree_probability; | randu = randu / light_tree_probability; | ||||
| pdf_factor *= light_tree_probability; | pdf_factor *= light_tree_probability; | ||||
| ret = light_tree_sample<in_volume_segment>(kg, | ret = light_tree_sample<in_volume_segment>(kg, | ||||
| rng_state, | rng_state, | ||||
| &randu, | &randu, | ||||
| randv, | randv, | ||||
| time, | time, | ||||
| P, | P, | ||||
| N, | N_or_D, | ||||
| t, | |||||
| has_transmission, | has_transmission, | ||||
| path_flag, | path_flag, | ||||
| bounce, | bounce, | ||||
| ls, | ls, | ||||
| &pdf_factor); | &pdf_factor); | ||||
| } | } | ||||
| else { | else { | ||||
| randu = (randu - light_tree_probability) / (1.0f - light_tree_probability); | randu = (randu - light_tree_probability) / (1.0f - light_tree_probability); | ||||
| pdf_factor *= (1.0f - light_tree_probability); | pdf_factor *= (1.0f - light_tree_probability); | ||||
| ret = light_tree_sample_distant_lights<in_volume_segment>(kg, | ret = light_tree_sample_distant_lights<in_volume_segment>(kg, | ||||
| rng_state, | rng_state, | ||||
| &randu, | &randu, | ||||
| randv, | randv, | ||||
| time, | time, | ||||
| P, | P, | ||||
| N, | N_or_D, | ||||
| t, | |||||
| has_transmission, | has_transmission, | ||||
| path_flag, | path_flag, | ||||
| bounce, | bounce, | ||||
| ls, | ls, | ||||
| &pdf_factor); | &pdf_factor); | ||||
| } | } | ||||
| ls->pdf_selection = pdf_factor; | ls->pdf_selection = pdf_factor; | ||||
| ls->pdf *= pdf_factor; | ls->pdf *= pdf_factor; | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||