forked from blender/blender
realize-depth #5
@ -324,13 +324,6 @@ ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg,
|
||||
ccl_private float2 *t_range,
|
||||
const ccl_private LightSample *ls)
|
||||
{
|
||||
# ifdef __LIGHT_TREE__
|
||||
/* Do not compute ray segment until #119389 is landed. */
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (ls->type == LIGHT_SPOT) {
|
||||
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
|
||||
return spot_light_valid_ray_segment(klight, ray_P, ray_D, t_range);
|
||||
@ -708,7 +701,8 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
|
||||
ccl_private const Ray *ccl_restrict ray,
|
||||
ccl_private const ShaderData *ccl_restrict sd,
|
||||
ccl_private const RNGState *ccl_restrict rng_state,
|
||||
ccl_private EquiangularCoefficients *ccl_restrict equiangular_coeffs)
|
||||
ccl_private EquiangularCoefficients *ccl_restrict equiangular_coeffs,
|
||||
ccl_private LightSample &ccl_restrict ls)
|
||||
{
|
||||
/* Test if there is a light or BSDF that needs direct light. */
|
||||
if (!kernel_data.integrator.use_direct_light) {
|
||||
@ -720,7 +714,6 @@ ccl_device_forceinline bool integrate_volume_equiangular_sample_light(
|
||||
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
|
||||
|
||||
LightSample ls ccl_optional_struct_init;
|
||||
if (!light_sample_from_volume_segment(kg,
|
||||
rand_light,
|
||||
sd->time,
|
||||
@ -761,41 +754,26 @@ ccl_device_forceinline void integrate_volume_direct_light(
|
||||
# ifdef __PATH_GUIDING__
|
||||
ccl_private const Spectrum unlit_throughput,
|
||||
# endif
|
||||
ccl_private const Spectrum throughput)
|
||||
ccl_private const Spectrum throughput,
|
||||
ccl_private LightSample &ccl_restrict ls)
|
||||
{
|
||||
PROFILING_INIT(kg, PROFILING_SHADE_VOLUME_DIRECT_LIGHT);
|
||||
|
||||
if (!kernel_data.integrator.use_direct_light) {
|
||||
if (!kernel_data.integrator.use_direct_light || ls.emitter_id == EMITTER_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sample position on the same light again, now from the shading point where we scattered.
|
||||
*
|
||||
* Note that this means we sample the light tree twice when equiangular sampling is used.
|
||||
* We could consider sampling the light tree just once and use the same light position again.
|
||||
*
|
||||
* This would make the PDFs for MIS weights more complicated due to having to account for
|
||||
* both distance/equiangular and direct/indirect light sampling, but could be more accurate.
|
||||
* Additionally we could end up behind the light or outside a spot light cone, which might
|
||||
* waste a sample. Though on the other hand it would be possible to prevent that with
|
||||
* equiangular sampling restricted to a smaller sub-segment where the light has influence. */
|
||||
LightSample ls ccl_optional_struct_init;
|
||||
/* Sample position on the same light again, now from the shading point where we scattered. */
|
||||
{
|
||||
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
|
||||
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
|
||||
const float3 N = zero_float3();
|
||||
const int object_receiver = light_link_receiver_nee(kg, sd);
|
||||
const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
|
||||
|
||||
if (!light_sample_from_position(kg,
|
||||
rng_state,
|
||||
rand_light,
|
||||
sd->time,
|
||||
P,
|
||||
zero_float3(),
|
||||
light_link_receiver_nee(kg, sd),
|
||||
SD_BSDF_HAS_TRANSMISSION,
|
||||
bounce,
|
||||
path_flag,
|
||||
&ls))
|
||||
if (!light_sample<false>(
|
||||
kg, rand_light, sd->time, P, N, object_receiver, shader_flags, bounce, path_flag, &ls))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -913,6 +891,7 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
|
||||
KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private const Ray *ray,
|
||||
ccl_private const RNGState *rng_state,
|
||||
ccl_private const ShaderVolumePhases *phases)
|
||||
{
|
||||
@ -965,6 +944,7 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, previous_dt) = ray->tmax - ray->tmin;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
|
||||
@ -993,7 +973,8 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
|
||||
|
||||
/* Update path state */
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = zero_float3();
|
||||
const float3 previous_P = ray->P + ray->D * ray->tmin;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_origin_n) = sd->P - previous_P;
|
||||
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
||||
unguided_phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
||||
|
||||
@ -1025,13 +1006,15 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
||||
|
||||
/* Sample light ahead of volume stepping, for equiangular sampling. */
|
||||
/* TODO: distant lights are ignored now, but could instead use even distribution. */
|
||||
LightSample ls ccl_optional_struct_init;
|
||||
ls.emitter_id = EMITTER_NONE;
|
||||
const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
|
||||
|
||||
EquiangularCoefficients equiangular_coeffs = {zero_float3(), make_float2(ray->tmin, ray->tmax)};
|
||||
|
||||
const bool have_equiangular_sample = need_light_sample &&
|
||||
integrate_volume_equiangular_sample_light(
|
||||
kg, state, ray, &sd, &rng_state, &equiangular_coeffs);
|
||||
const bool have_equiangular_sample =
|
||||
need_light_sample && integrate_volume_equiangular_sample_light(
|
||||
kg, state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
|
||||
|
||||
VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
|
||||
volume_stack_sample_method(kg, state) :
|
||||
@ -1129,7 +1112,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
||||
# ifdef __PATH_GUIDING__
|
||||
unlit_throughput,
|
||||
# endif
|
||||
result.direct_throughput);
|
||||
result.direct_throughput,
|
||||
ls);
|
||||
}
|
||||
|
||||
/* Indirect light.
|
||||
@ -1168,7 +1152,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
||||
# endif
|
||||
# endif
|
||||
|
||||
if (integrate_volume_phase_scatter(kg, state, &sd, &rng_state, &result.indirect_phases)) {
|
||||
if (integrate_volume_phase_scatter(kg, state, &sd, ray, &rng_state, &result.indirect_phases)) {
|
||||
return VOLUME_PATH_SCATTERED;
|
||||
}
|
||||
else {
|
||||
|
@ -75,6 +75,9 @@ KERNEL_STRUCT_MEMBER(ray, float, tmax, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
|
||||
#ifdef __LIGHT_TREE__
|
||||
KERNEL_STRUCT_MEMBER(ray, float, previous_dt, KERNEL_FEATURE_PATH_TRACING)
|
||||
#endif
|
||||
KERNEL_STRUCT_END(ray)
|
||||
|
||||
/*************************** Intersection result ******************************/
|
||||
|
@ -518,9 +518,8 @@ ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLi
|
||||
const bool shape_above_surface = dot(N, centroid - P) + fabsf(dot(N, extentu)) +
|
||||
fabsf(dot(N, extentv)) >
|
||||
0;
|
||||
const bool in_volume = is_zero(N);
|
||||
|
||||
return (front_facing && shape_above_surface) || in_volume;
|
||||
return front_facing && shape_above_surface;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -12,9 +12,9 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
typedef struct LightSample {
|
||||
float3 P; /* position on light, or direction for distant light */
|
||||
float3 Ng; /* normal on light */
|
||||
float3 D; /* direction from shading point to light */
|
||||
packed_float3 Ng; /* normal on light */
|
||||
float t; /* distance to light (FLT_MAX for distant light) */
|
||||
float3 D; /* direction from shading point to light */
|
||||
float u, v; /* parametric coordinate on primitive */
|
||||
float pdf; /* pdf for selecting light and point on light */
|
||||
float pdf_selection; /* pdf for selecting light */
|
||||
@ -25,6 +25,7 @@ typedef struct LightSample {
|
||||
int lamp; /* lamp id */
|
||||
int group; /* lightgroup */
|
||||
LightType type; /* type of light */
|
||||
int emitter_id; /* index in the emitter array */
|
||||
} LightSample;
|
||||
|
||||
/* Utilities */
|
||||
|
@ -41,36 +41,14 @@ ccl_device int light_distribution_sample(KernelGlobals kg, const float rand)
|
||||
return index;
|
||||
}
|
||||
|
||||
template<bool in_volume_segment>
|
||||
ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
|
||||
const float3 rand,
|
||||
const float time,
|
||||
const float3 P,
|
||||
const float3 N,
|
||||
const int object_receiver,
|
||||
const int shader_flags,
|
||||
const int bounce,
|
||||
const uint32_t path_flag,
|
||||
const float rand,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
/* Sample light index from distribution. */
|
||||
/* The first two dimensions of the Sobol sequence have better stratification. */
|
||||
const int index = light_distribution_sample(kg, rand.z);
|
||||
const float pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
||||
const float2 rand_uv = float3_to_float2(rand);
|
||||
return light_sample<in_volume_segment>(kg,
|
||||
rand_uv,
|
||||
time,
|
||||
P,
|
||||
N,
|
||||
object_receiver,
|
||||
shader_flags,
|
||||
bounce,
|
||||
path_flag,
|
||||
index,
|
||||
0,
|
||||
pdf_selection,
|
||||
ls);
|
||||
ls->emitter_id = light_distribution_sample(kg, rand);
|
||||
ls->pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
||||
return true;
|
||||
}
|
||||
|
||||
ccl_device_inline float light_distribution_pdf_lamp(KernelGlobals kg)
|
||||
|
@ -177,7 +177,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
||||
|
||||
template<bool in_volume_segment>
|
||||
ccl_device_noinline bool light_sample(KernelGlobals kg,
|
||||
const float2 rand,
|
||||
const float3 rand_light,
|
||||
const float time,
|
||||
const float3 P,
|
||||
const float3 N,
|
||||
@ -185,33 +185,31 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
||||
const int shader_flags,
|
||||
const int bounce,
|
||||
const uint32_t path_flag,
|
||||
const int emitter_index,
|
||||
const int object_id,
|
||||
const float pdf_selection,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
/* The first two dimensions of the Sobol sequence have better stratification, use them to sample
|
||||
* position on the light. */
|
||||
const float2 rand = float3_to_float2(rand_light);
|
||||
|
||||
int prim;
|
||||
MeshLight mesh_light;
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||
emitter_index);
|
||||
ls->emitter_id);
|
||||
prim = kemitter->light.id;
|
||||
mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
|
||||
mesh_light.object_id = object_id;
|
||||
mesh_light.object_id = ls->object;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
||||
light_distribution, emitter_index);
|
||||
light_distribution, ls->emitter_id);
|
||||
prim = kdistribution->prim;
|
||||
mesh_light = kdistribution->mesh_light;
|
||||
}
|
||||
|
||||
/* A different value would be assigned in `triangle_light_sample()` if `!use_light_tree`. */
|
||||
ls->pdf_selection = pdf_selection;
|
||||
|
||||
if (prim >= 0) {
|
||||
/* Mesh light. */
|
||||
const int object = mesh_light.object_id;
|
||||
|
@ -329,19 +329,27 @@ ccl_device_inline bool light_sample_from_volume_segment(KernelGlobals kg,
|
||||
const uint32_t path_flag,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
|
||||
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
return light_tree_sample<true>(
|
||||
kg, rand, time, P, D, t, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
|
||||
if (!light_tree_sample<true>(kg, rand.z, P, D, t, object_receiver, shader_flags, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return light_distribution_sample<true>(
|
||||
kg, rand, time, P, D, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
|
||||
if (!light_distribution_sample(kg, rand.z, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sample position on the selected light. */
|
||||
return light_sample<true>(
|
||||
kg, rand, time, P, D, object_receiver, shader_flags, bounce, path_flag, ls);
|
||||
}
|
||||
|
||||
ccl_device bool light_sample_from_position(KernelGlobals kg,
|
||||
ccl_private const RNGState *rng_state,
|
||||
const float3 rand,
|
||||
@ -354,19 +362,26 @@ ccl_device bool light_sample_from_position(KernelGlobals kg,
|
||||
const uint32_t path_flag,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
/* Randomly select a light. */
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
return light_tree_sample<false>(
|
||||
kg, rand, time, P, N, 0.0f, object_receiver, shader_flags, bounce, path_flag, ls);
|
||||
if (!light_tree_sample<false>(kg, rand.z, P, N, 0.0f, object_receiver, shader_flags, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return light_distribution_sample<false>(
|
||||
kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, ls);
|
||||
if (!light_distribution_sample(kg, rand.z, ls)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sample position on the selected light. */
|
||||
return light_sample<false>(
|
||||
kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, ls);
|
||||
}
|
||||
|
||||
/* Update light sample with new shading point position for MNEE. The position on the light is fixed
|
||||
* except for directional light. */
|
||||
ccl_device_forceinline void light_sample_update(KernelGlobals kg,
|
||||
@ -415,13 +430,15 @@ ccl_device_inline float light_sample_mis_weight_forward_surface(KernelGlobals kg
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
float3 ray_P = INTEGRATOR_STATE(state, ray, P);
|
||||
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
|
||||
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
||||
|
||||
uint lookup_offset = kernel_data_fetch(object_lookup_offset, sd->object);
|
||||
uint prim_offset = kernel_data_fetch(object_prim_offset, sd->object);
|
||||
uint triangle = kernel_data_fetch(triangle_to_tree, sd->prim - prim_offset + lookup_offset);
|
||||
|
||||
pdf *= light_tree_pdf(
|
||||
kg, ray_P, N, path_flag, sd->object, triangle, light_link_receiver_forward(kg, state));
|
||||
kg, ray_P, N, dt, path_flag, sd->object, triangle, light_link_receiver_forward(kg, state));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -445,9 +462,11 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg,
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
||||
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
|
||||
pdf *= light_tree_pdf(kg,
|
||||
P,
|
||||
N,
|
||||
dt,
|
||||
path_flag,
|
||||
0,
|
||||
kernel_data_fetch(light_to_tree, ls->lamp),
|
||||
@ -485,9 +504,10 @@ ccl_device_inline float light_sample_mis_weight_forward_background(KernelGlobals
|
||||
#ifdef __LIGHT_TREE__
|
||||
if (kernel_data.integrator.use_light_tree) {
|
||||
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
||||
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
|
||||
uint light = kernel_data_fetch(light_to_tree, kernel_data.background.light_index);
|
||||
pdf *= light_tree_pdf(
|
||||
kg, ray_P, N, path_flag, 0, light, light_link_receiver_forward(kg, state));
|
||||
kg, ray_P, N, dt, path_flag, 0, light, light_link_receiver_forward(kg, state));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -148,10 +148,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
||||
float cos_min_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
|
||||
* `sample.h`. */
|
||||
const bool in_volume = is_zero(N_or_D);
|
||||
if (!in_volume_segment && !in_volume) {
|
||||
if (!in_volume_segment) {
|
||||
const float3 N = N_or_D;
|
||||
const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) :
|
||||
dot(point_to_centroid, N);
|
||||
@ -221,9 +218,9 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
||||
max_importance = fabsf(f_a * cos_min_incidence_angle * energy * cos_min_outgoing_angle /
|
||||
(in_volume_segment ? min_distance : sqr(min_distance)));
|
||||
|
||||
/* TODO: also min importance for volume? */
|
||||
/* TODO: compute proper min importance for volume. */
|
||||
if (in_volume_segment) {
|
||||
min_importance = max_importance;
|
||||
min_importance = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -270,10 +267,10 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
||||
/* Arbitrary centroid and direction. */
|
||||
centroid = make_float3(0.0f, 0.0f, 1.0f);
|
||||
dir = make_float3(0.0f, 0.0f, -1.0f);
|
||||
return !in_volume_segment;
|
||||
break;
|
||||
case LIGHT_DISTANT:
|
||||
dir = centroid;
|
||||
return !in_volume_segment;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -323,12 +320,13 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
||||
float cos_theta_u;
|
||||
float distance;
|
||||
if (knode->type == LIGHT_TREE_DISTANT) {
|
||||
if (in_volume_segment) {
|
||||
return;
|
||||
}
|
||||
point_to_centroid = -bcone.axis;
|
||||
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
|
||||
distance = 1.0f;
|
||||
if (t == FLT_MAX) {
|
||||
/* In world volume, distant light has no contribution. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float3 centroid = 0.5f * (bbox.min + bbox.max);
|
||||
@ -339,6 +337,9 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
||||
/* Minimal distance of the ray to the cluster. */
|
||||
distance = len(centroid - closest_point);
|
||||
point_to_centroid = -compute_v(centroid, P, D, bcone.axis, t);
|
||||
/* FIXME(weizhen): it is not clear from which point the `cos_theta_u` should be computed in
|
||||
* volume segment. We could use `closest_point` as a conservative measure, but then
|
||||
* `point_to_centroid` should also use `closest_point`. */
|
||||
cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid);
|
||||
}
|
||||
else {
|
||||
@ -697,17 +698,16 @@ ccl_device int light_tree_root_node_index(KernelGlobals kg, const int object_rec
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pick a random light from the light tree from a given shading point P, write to the picked light
|
||||
* index and the probability of picking the light. */
|
||||
template<bool in_volume_segment>
|
||||
ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
||||
const float3 rand,
|
||||
const float time,
|
||||
const float rand,
|
||||
const float3 P,
|
||||
float3 N_or_D,
|
||||
float t,
|
||||
const int object_receiver,
|
||||
const int shader_flags,
|
||||
const int bounce,
|
||||
const uint32_t path_flag,
|
||||
ccl_private LightSample *ls)
|
||||
{
|
||||
if (!kernel_data.integrator.use_direct_light) {
|
||||
@ -718,10 +718,8 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
||||
float pdf_leaf = 1.0f;
|
||||
float pdf_selection = 1.0f;
|
||||
int selected_emitter = -1;
|
||||
int object_emitter = 0;
|
||||
int node_index = light_tree_root_node_index(kg, object_receiver);
|
||||
/* The first two dimensions of the Sobol sequence have better stratification. */
|
||||
float rand_selection = rand.z;
|
||||
float rand_selection = rand;
|
||||
|
||||
float3 local_P = P;
|
||||
|
||||
@ -743,7 +741,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
||||
}
|
||||
|
||||
/* Continue with the picked mesh light. */
|
||||
object_emitter = kernel_data_fetch(light_tree_emitters, selected_emitter).mesh.object_id;
|
||||
ls->object = kernel_data_fetch(light_tree_emitters, selected_emitter).mesh.object_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -766,27 +764,18 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
||||
pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob);
|
||||
}
|
||||
|
||||
pdf_selection *= pdf_leaf;
|
||||
ls->emitter_id = selected_emitter;
|
||||
ls->pdf_selection = pdf_selection * pdf_leaf;
|
||||
|
||||
return light_sample<in_volume_segment>(kg,
|
||||
float3_to_float2(rand),
|
||||
time,
|
||||
P,
|
||||
N_or_D,
|
||||
object_receiver,
|
||||
shader_flags,
|
||||
bounce,
|
||||
path_flag,
|
||||
selected_emitter,
|
||||
object_emitter,
|
||||
pdf_selection,
|
||||
ls);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We need to be able to find the probability of selecting a given light for MIS. */
|
||||
template<bool in_volume_segment>
|
||||
ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||
float3 P,
|
||||
float3 N,
|
||||
const float dt,
|
||||
const int path_flag,
|
||||
const int object_emitter,
|
||||
const uint index_emitter,
|
||||
@ -837,8 +826,8 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||
for (int i = 0; i < knode->num_emitters; i++) {
|
||||
const int emitter = knode->leaf.first_emitter + i;
|
||||
float max_importance, min_importance;
|
||||
light_tree_emitter_importance<false>(
|
||||
kg, P, N, 0, has_transmission, emitter, max_importance, min_importance);
|
||||
light_tree_emitter_importance<in_volume_segment>(
|
||||
kg, P, N, dt, has_transmission, emitter, max_importance, min_importance);
|
||||
num_has_importance += (max_importance > 0);
|
||||
if (emitter == target_emitter) {
|
||||
target_max_importance = max_importance;
|
||||
@ -860,7 +849,7 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||
if (subtree_root_index != -1) {
|
||||
/* Arrived at the mesh light. Continue with the subtree. */
|
||||
float unused;
|
||||
light_tree_to_local_space<false>(kg, object_emitter, P, N, unused);
|
||||
light_tree_to_local_space<in_volume_segment>(kg, object_emitter, P, N, unused);
|
||||
|
||||
node_index = subtree_root_index;
|
||||
subtree_root_index = -1;
|
||||
@ -878,8 +867,8 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||
const int right_index = knode->inner.right_child;
|
||||
|
||||
float left_prob;
|
||||
if (!get_left_probability<false>(
|
||||
kg, P, N, 0, has_transmission, left_index, right_index, left_prob))
|
||||
if (!get_left_probability<in_volume_segment>(
|
||||
kg, P, N, dt, has_transmission, left_index, right_index, left_prob))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
@ -897,4 +886,27 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||
}
|
||||
}
|
||||
|
||||
/* If the function is called in volume, retrieve the previous point in volume segment, and compute
|
||||
* pdf from there. Otherwise compute from the current shading point. */
|
||||
ccl_device_inline float light_tree_pdf(KernelGlobals kg,
|
||||
float3 P,
|
||||
float3 N,
|
||||
const float dt,
|
||||
const int path_flag,
|
||||
const int emitter_object,
|
||||
const uint emitter_id,
|
||||
const int object_receiver)
|
||||
{
|
||||
if (path_flag & PATH_RAY_VOLUME_SCATTER) {
|
||||
const float3 D_times_t = N;
|
||||
const float3 D = normalize(D_times_t);
|
||||
P = P - D_times_t;
|
||||
return light_tree_pdf<true>(
|
||||
kg, P, D, dt, path_flag, emitter_object, emitter_id, object_receiver);
|
||||
}
|
||||
|
||||
return light_tree_pdf<false>(
|
||||
kg, P, N, 0.0f, path_flag, emitter_object, emitter_id, object_receiver);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -285,7 +285,8 @@ ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg,
|
||||
|
||||
/* Only one side is sampled, intersect the ray and the triangle light plane to find the visible
|
||||
* ray segment. Flip normal if Emission Sampling is set to back. */
|
||||
return ray_plane_intersect((shader_flag & SD_MIS_BACK) ? -ls->Ng : ls->Ng, P, D, t_range);
|
||||
const float3 N = ls->Ng;
|
||||
return ray_plane_intersect((shader_flag & SD_MIS_BACK) ? -N : N, P, D, t_range);
|
||||
}
|
||||
|
||||
template<bool in_volume_segment>
|
||||
@ -326,9 +327,8 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
|
||||
}
|
||||
|
||||
const bool front_facing = bcone.theta_o != 0.0f || dot(bcone.axis, point_to_centroid) < 0;
|
||||
const bool in_volume = is_zero(N);
|
||||
|
||||
return (front_facing && shape_above_surface) || in_volume;
|
||||
return front_facing && shape_above_surface;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -45,6 +45,7 @@ CCL_NAMESPACE_BEGIN
|
||||
#define OBJECT_NONE (~0)
|
||||
#define PRIM_NONE (~0)
|
||||
#define LAMP_NONE (~0)
|
||||
#define EMITTER_NONE (~0)
|
||||
#define ID_NONE (0.0f)
|
||||
#define PASS_UNUSED (~0)
|
||||
#define LIGHTGROUP_NONE (~0)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 00af9c65712b6aa78ce6eb0c62c5aafb7a867f18
|
||||
Subproject commit 9ce3adf54dae89a9daaa4dcd04cc3a566aed3aaf
|
Loading…
Reference in New Issue
Block a user