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,
|
ccl_private float2 *t_range,
|
||||||
const ccl_private LightSample *ls)
|
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) {
|
if (ls->type == LIGHT_SPOT) {
|
||||||
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
|
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
|
||||||
return spot_light_valid_ray_segment(klight, ray_P, ray_D, t_range);
|
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 Ray *ccl_restrict ray,
|
||||||
ccl_private const ShaderData *ccl_restrict sd,
|
ccl_private const ShaderData *ccl_restrict sd,
|
||||||
ccl_private const RNGState *ccl_restrict rng_state,
|
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. */
|
/* Test if there is a light or BSDF that needs direct light. */
|
||||||
if (!kernel_data.integrator.use_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 uint bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||||
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
|
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,
|
if (!light_sample_from_volume_segment(kg,
|
||||||
rand_light,
|
rand_light,
|
||||||
sd->time,
|
sd->time,
|
||||||
@ -761,41 +754,26 @@ ccl_device_forceinline void integrate_volume_direct_light(
|
|||||||
# ifdef __PATH_GUIDING__
|
# ifdef __PATH_GUIDING__
|
||||||
ccl_private const Spectrum unlit_throughput,
|
ccl_private const Spectrum unlit_throughput,
|
||||||
# endif
|
# 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);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sample position on the same light again, now from the shading point where we scattered.
|
/* 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;
|
|
||||||
{
|
{
|
||||||
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
|
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
|
||||||
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
|
const uint bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||||
const float3 rand_light = path_state_rng_3D(kg, rng_state, PRNG_LIGHT);
|
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,
|
if (!light_sample<false>(
|
||||||
rng_state,
|
kg, rand_light, sd->time, P, N, object_receiver, shader_flags, bounce, path_flag, &ls))
|
||||||
rand_light,
|
|
||||||
sd->time,
|
|
||||||
P,
|
|
||||||
zero_float3(),
|
|
||||||
light_link_receiver_nee(kg, sd),
|
|
||||||
SD_BSDF_HAS_TRANSMISSION,
|
|
||||||
bounce,
|
|
||||||
path_flag,
|
|
||||||
&ls))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -913,6 +891,7 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
|
|||||||
KernelGlobals kg,
|
KernelGlobals kg,
|
||||||
IntegratorState state,
|
IntegratorState state,
|
||||||
ccl_private ShaderData *sd,
|
ccl_private ShaderData *sd,
|
||||||
|
ccl_private const Ray *ray,
|
||||||
ccl_private const RNGState *rng_state,
|
ccl_private const RNGState *rng_state,
|
||||||
ccl_private const ShaderVolumePhases *phases)
|
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, P) = sd->P;
|
||||||
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
|
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_wo);
|
||||||
INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
|
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;
|
INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
|
||||||
# ifdef __RAY_DIFFERENTIALS__
|
# ifdef __RAY_DIFFERENTIALS__
|
||||||
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
|
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 */
|
/* Update path state */
|
||||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
|
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(
|
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
|
||||||
unguided_phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
|
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. */
|
/* Sample light ahead of volume stepping, for equiangular sampling. */
|
||||||
/* TODO: distant lights are ignored now, but could instead use even distribution. */
|
/* 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);
|
const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
|
||||||
|
|
||||||
EquiangularCoefficients equiangular_coeffs = {zero_float3(), make_float2(ray->tmin, ray->tmax)};
|
EquiangularCoefficients equiangular_coeffs = {zero_float3(), make_float2(ray->tmin, ray->tmax)};
|
||||||
|
|
||||||
const bool have_equiangular_sample = need_light_sample &&
|
const bool have_equiangular_sample =
|
||||||
integrate_volume_equiangular_sample_light(
|
need_light_sample && integrate_volume_equiangular_sample_light(
|
||||||
kg, state, ray, &sd, &rng_state, &equiangular_coeffs);
|
kg, state, ray, &sd, &rng_state, &equiangular_coeffs, ls);
|
||||||
|
|
||||||
VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
|
VolumeSampleMethod direct_sample_method = (have_equiangular_sample) ?
|
||||||
volume_stack_sample_method(kg, state) :
|
volume_stack_sample_method(kg, state) :
|
||||||
@ -1129,7 +1112,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
|||||||
# ifdef __PATH_GUIDING__
|
# ifdef __PATH_GUIDING__
|
||||||
unlit_throughput,
|
unlit_throughput,
|
||||||
# endif
|
# endif
|
||||||
result.direct_throughput);
|
result.direct_throughput,
|
||||||
|
ls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indirect light.
|
/* Indirect light.
|
||||||
@ -1168,7 +1152,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
|||||||
# endif
|
# endif
|
||||||
# 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;
|
return VOLUME_PATH_SCATTERED;
|
||||||
}
|
}
|
||||||
else {
|
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, time, KERNEL_FEATURE_PATH_TRACING)
|
||||||
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
|
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
|
||||||
KERNEL_STRUCT_MEMBER(ray, float, dD, 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)
|
KERNEL_STRUCT_END(ray)
|
||||||
|
|
||||||
/*************************** Intersection result ******************************/
|
/*************************** 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)) +
|
const bool shape_above_surface = dot(N, centroid - P) + fabsf(dot(N, extentu)) +
|
||||||
fabsf(dot(N, extentv)) >
|
fabsf(dot(N, extentv)) >
|
||||||
0;
|
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
|
CCL_NAMESPACE_END
|
||||||
|
@ -12,9 +12,9 @@ CCL_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
typedef struct LightSample {
|
typedef struct LightSample {
|
||||||
float3 P; /* position on light, or direction for distant light */
|
float3 P; /* position on light, or direction for distant light */
|
||||||
float3 Ng; /* normal on light */
|
packed_float3 Ng; /* normal on light */
|
||||||
float3 D; /* direction from shading point to light */
|
|
||||||
float t; /* distance to light (FLT_MAX for distant 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 u, v; /* parametric coordinate on primitive */
|
||||||
float pdf; /* pdf for selecting light and point on light */
|
float pdf; /* pdf for selecting light and point on light */
|
||||||
float pdf_selection; /* pdf for selecting light */
|
float pdf_selection; /* pdf for selecting light */
|
||||||
@ -25,6 +25,7 @@ typedef struct LightSample {
|
|||||||
int lamp; /* lamp id */
|
int lamp; /* lamp id */
|
||||||
int group; /* lightgroup */
|
int group; /* lightgroup */
|
||||||
LightType type; /* type of light */
|
LightType type; /* type of light */
|
||||||
|
int emitter_id; /* index in the emitter array */
|
||||||
} LightSample;
|
} LightSample;
|
||||||
|
|
||||||
/* Utilities */
|
/* Utilities */
|
||||||
|
@ -41,36 +41,14 @@ ccl_device int light_distribution_sample(KernelGlobals kg, const float rand)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool in_volume_segment>
|
|
||||||
ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
|
ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
|
||||||
const float3 rand,
|
const float 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,
|
|
||||||
ccl_private LightSample *ls)
|
ccl_private LightSample *ls)
|
||||||
{
|
{
|
||||||
/* Sample light index from distribution. */
|
/* Sample light index from distribution. */
|
||||||
/* The first two dimensions of the Sobol sequence have better stratification. */
|
ls->emitter_id = light_distribution_sample(kg, rand);
|
||||||
const int index = light_distribution_sample(kg, rand.z);
|
ls->pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
||||||
const float pdf_selection = kernel_data.integrator.distribution_pdf_lights;
|
return true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ccl_device_inline float light_distribution_pdf_lamp(KernelGlobals kg)
|
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>
|
template<bool in_volume_segment>
|
||||||
ccl_device_noinline bool light_sample(KernelGlobals kg,
|
ccl_device_noinline bool light_sample(KernelGlobals kg,
|
||||||
const float2 rand,
|
const float3 rand_light,
|
||||||
const float time,
|
const float time,
|
||||||
const float3 P,
|
const float3 P,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@ -185,33 +185,31 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
|||||||
const int shader_flags,
|
const int shader_flags,
|
||||||
const int bounce,
|
const int bounce,
|
||||||
const uint32_t path_flag,
|
const uint32_t path_flag,
|
||||||
const int emitter_index,
|
|
||||||
const int object_id,
|
|
||||||
const float pdf_selection,
|
|
||||||
ccl_private LightSample *ls)
|
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;
|
int prim;
|
||||||
MeshLight mesh_light;
|
MeshLight mesh_light;
|
||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||||
emitter_index);
|
ls->emitter_id);
|
||||||
prim = kemitter->light.id;
|
prim = kemitter->light.id;
|
||||||
mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
|
mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
|
||||||
mesh_light.object_id = object_id;
|
mesh_light.object_id = ls->object;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
||||||
light_distribution, emitter_index);
|
light_distribution, ls->emitter_id);
|
||||||
prim = kdistribution->prim;
|
prim = kdistribution->prim;
|
||||||
mesh_light = kdistribution->mesh_light;
|
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) {
|
if (prim >= 0) {
|
||||||
/* Mesh light. */
|
/* Mesh light. */
|
||||||
const int object = mesh_light.object_id;
|
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,
|
const uint32_t path_flag,
|
||||||
ccl_private LightSample *ls)
|
ccl_private LightSample *ls)
|
||||||
{
|
{
|
||||||
|
const int shader_flags = SD_BSDF_HAS_TRANSMISSION;
|
||||||
|
|
||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
return light_tree_sample<true>(
|
if (!light_tree_sample<true>(kg, rand.z, P, D, t, object_receiver, shader_flags, ls)) {
|
||||||
kg, rand, time, P, D, t, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, ls);
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return light_distribution_sample<true>(
|
if (!light_distribution_sample(kg, rand.z, ls)) {
|
||||||
kg, rand, time, P, D, object_receiver, SD_BSDF_HAS_TRANSMISSION, bounce, path_flag, 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_device bool light_sample_from_position(KernelGlobals kg,
|
||||||
ccl_private const RNGState *rng_state,
|
ccl_private const RNGState *rng_state,
|
||||||
const float3 rand,
|
const float3 rand,
|
||||||
@ -354,19 +362,26 @@ ccl_device bool light_sample_from_position(KernelGlobals kg,
|
|||||||
const uint32_t path_flag,
|
const uint32_t path_flag,
|
||||||
ccl_private LightSample *ls)
|
ccl_private LightSample *ls)
|
||||||
{
|
{
|
||||||
|
/* Randomly select a light. */
|
||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
return light_tree_sample<false>(
|
if (!light_tree_sample<false>(kg, rand.z, P, N, 0.0f, object_receiver, shader_flags, ls)) {
|
||||||
kg, rand, time, P, N, 0.0f, object_receiver, shader_flags, bounce, path_flag, ls);
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return light_distribution_sample<false>(
|
if (!light_distribution_sample(kg, rand.z, ls)) {
|
||||||
kg, rand, time, P, N, object_receiver, shader_flags, bounce, path_flag, 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
|
/* Update light sample with new shading point position for MNEE. The position on the light is fixed
|
||||||
* except for directional light. */
|
* except for directional light. */
|
||||||
ccl_device_forceinline void light_sample_update(KernelGlobals kg,
|
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__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
float3 ray_P = INTEGRATOR_STATE(state, ray, P);
|
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);
|
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
||||||
|
|
||||||
uint lookup_offset = kernel_data_fetch(object_lookup_offset, sd->object);
|
uint lookup_offset = kernel_data_fetch(object_lookup_offset, sd->object);
|
||||||
uint prim_offset = kernel_data_fetch(object_prim_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);
|
uint triangle = kernel_data_fetch(triangle_to_tree, sd->prim - prim_offset + lookup_offset);
|
||||||
|
|
||||||
pdf *= light_tree_pdf(
|
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
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -445,9 +462,11 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg,
|
|||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
||||||
|
const float dt = INTEGRATOR_STATE(state, ray, previous_dt);
|
||||||
pdf *= light_tree_pdf(kg,
|
pdf *= light_tree_pdf(kg,
|
||||||
P,
|
P,
|
||||||
N,
|
N,
|
||||||
|
dt,
|
||||||
path_flag,
|
path_flag,
|
||||||
0,
|
0,
|
||||||
kernel_data_fetch(light_to_tree, ls->lamp),
|
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__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
|
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);
|
uint light = kernel_data_fetch(light_to_tree, kernel_data.background.light_index);
|
||||||
pdf *= light_tree_pdf(
|
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
|
else
|
||||||
#endif
|
#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_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
|
if (!in_volume_segment) {
|
||||||
* `sample.h`. */
|
|
||||||
const bool in_volume = is_zero(N_or_D);
|
|
||||||
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);
|
||||||
@ -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 /
|
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)));
|
||||||
|
|
||||||
/* TODO: also min importance for volume? */
|
/* TODO: compute proper min importance for volume. */
|
||||||
if (in_volume_segment) {
|
if (in_volume_segment) {
|
||||||
min_importance = max_importance;
|
min_importance = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,10 +267,10 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
|||||||
/* Arbitrary 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;
|
break;
|
||||||
case LIGHT_DISTANT:
|
case LIGHT_DISTANT:
|
||||||
dir = centroid;
|
dir = centroid;
|
||||||
return !in_volume_segment;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -323,12 +320,13 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
|
|||||||
float cos_theta_u;
|
float cos_theta_u;
|
||||||
float distance;
|
float distance;
|
||||||
if (knode->type == LIGHT_TREE_DISTANT) {
|
if (knode->type == LIGHT_TREE_DISTANT) {
|
||||||
if (in_volume_segment) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
point_to_centroid = -bcone.axis;
|
point_to_centroid = -bcone.axis;
|
||||||
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
|
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
|
||||||
distance = 1.0f;
|
distance = 1.0f;
|
||||||
|
if (t == FLT_MAX) {
|
||||||
|
/* In world volume, distant light has no contribution. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const float3 centroid = 0.5f * (bbox.min + bbox.max);
|
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. */
|
/* 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);
|
||||||
|
/* 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);
|
cos_theta_u = light_tree_cos_bounding_box_angle(bbox, closest_point, point_to_centroid);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -697,17 +698,16 @@ ccl_device int light_tree_root_node_index(KernelGlobals kg, const int object_rec
|
|||||||
return 0;
|
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>
|
template<bool in_volume_segment>
|
||||||
ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
||||||
const float3 rand,
|
const float rand,
|
||||||
const float time,
|
|
||||||
const float3 P,
|
const float3 P,
|
||||||
float3 N_or_D,
|
float3 N_or_D,
|
||||||
float t,
|
float t,
|
||||||
const int object_receiver,
|
const int object_receiver,
|
||||||
const int shader_flags,
|
const int shader_flags,
|
||||||
const int bounce,
|
|
||||||
const uint32_t path_flag,
|
|
||||||
ccl_private LightSample *ls)
|
ccl_private LightSample *ls)
|
||||||
{
|
{
|
||||||
if (!kernel_data.integrator.use_direct_light) {
|
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_leaf = 1.0f;
|
||||||
float pdf_selection = 1.0f;
|
float pdf_selection = 1.0f;
|
||||||
int selected_emitter = -1;
|
int selected_emitter = -1;
|
||||||
int object_emitter = 0;
|
|
||||||
int node_index = light_tree_root_node_index(kg, object_receiver);
|
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;
|
||||||
float rand_selection = rand.z;
|
|
||||||
|
|
||||||
float3 local_P = P;
|
float3 local_P = P;
|
||||||
|
|
||||||
@ -743,7 +741,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Continue with the picked mesh light. */
|
/* 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;
|
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_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,
|
return true;
|
||||||
float3_to_float2(rand),
|
|
||||||
time,
|
|
||||||
P,
|
|
||||||
N_or_D,
|
|
||||||
object_receiver,
|
|
||||||
shader_flags,
|
|
||||||
bounce,
|
|
||||||
path_flag,
|
|
||||||
selected_emitter,
|
|
||||||
object_emitter,
|
|
||||||
pdf_selection,
|
|
||||||
ls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
template<bool in_volume_segment>
|
||||||
ccl_device float light_tree_pdf(KernelGlobals kg,
|
ccl_device float light_tree_pdf(KernelGlobals kg,
|
||||||
float3 P,
|
float3 P,
|
||||||
float3 N,
|
float3 N,
|
||||||
|
const float dt,
|
||||||
const int path_flag,
|
const int path_flag,
|
||||||
const int object_emitter,
|
const int object_emitter,
|
||||||
const uint index_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++) {
|
for (int i = 0; i < knode->num_emitters; i++) {
|
||||||
const int emitter = knode->leaf.first_emitter + i;
|
const int emitter = knode->leaf.first_emitter + i;
|
||||||
float max_importance, min_importance;
|
float max_importance, min_importance;
|
||||||
light_tree_emitter_importance<false>(
|
light_tree_emitter_importance<in_volume_segment>(
|
||||||
kg, P, N, 0, has_transmission, emitter, max_importance, min_importance);
|
kg, P, N, dt, has_transmission, emitter, max_importance, min_importance);
|
||||||
num_has_importance += (max_importance > 0);
|
num_has_importance += (max_importance > 0);
|
||||||
if (emitter == target_emitter) {
|
if (emitter == target_emitter) {
|
||||||
target_max_importance = max_importance;
|
target_max_importance = max_importance;
|
||||||
@ -860,7 +849,7 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
|||||||
if (subtree_root_index != -1) {
|
if (subtree_root_index != -1) {
|
||||||
/* Arrived at the mesh light. Continue with the subtree. */
|
/* Arrived at the mesh light. Continue with the subtree. */
|
||||||
float unused;
|
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;
|
node_index = subtree_root_index;
|
||||||
subtree_root_index = -1;
|
subtree_root_index = -1;
|
||||||
@ -878,8 +867,8 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
|
|||||||
const int right_index = knode->inner.right_child;
|
const int right_index = knode->inner.right_child;
|
||||||
|
|
||||||
float left_prob;
|
float left_prob;
|
||||||
if (!get_left_probability<false>(
|
if (!get_left_probability<in_volume_segment>(
|
||||||
kg, P, N, 0, has_transmission, left_index, right_index, left_prob))
|
kg, P, N, dt, has_transmission, left_index, right_index, left_prob))
|
||||||
{
|
{
|
||||||
return 0.0f;
|
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
|
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
|
/* 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. */
|
* 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>
|
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 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
|
CCL_NAMESPACE_END
|
||||||
|
@ -45,6 +45,7 @@ CCL_NAMESPACE_BEGIN
|
|||||||
#define OBJECT_NONE (~0)
|
#define OBJECT_NONE (~0)
|
||||||
#define PRIM_NONE (~0)
|
#define PRIM_NONE (~0)
|
||||||
#define LAMP_NONE (~0)
|
#define LAMP_NONE (~0)
|
||||||
|
#define EMITTER_NONE (~0)
|
||||||
#define ID_NONE (0.0f)
|
#define ID_NONE (0.0f)
|
||||||
#define PASS_UNUSED (~0)
|
#define PASS_UNUSED (~0)
|
||||||
#define LIGHTGROUP_NONE (~0)
|
#define LIGHTGROUP_NONE (~0)
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 00af9c65712b6aa78ce6eb0c62c5aafb7a867f18
|
Subproject commit 9ce3adf54dae89a9daaa4dcd04cc3a566aed3aaf
|
Loading…
Reference in New Issue
Block a user