Light Linking: Select one of dedicated lights #107739
|
@ -8,6 +8,7 @@
|
||||||
#include "kernel/integrator/shade_surface.h"
|
#include "kernel/integrator/shade_surface.h"
|
||||||
#include "kernel/integrator/shadow_linking.h"
|
#include "kernel/integrator/shadow_linking.h"
|
||||||
#include "kernel/light/light.h"
|
#include "kernel/light/light.h"
|
||||||
|
#include "kernel/sample/lcg.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -28,6 +29,11 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
|
||||||
const int last_object = INTEGRATOR_STATE(state, isect, object);
|
const int last_object = INTEGRATOR_STATE(state, isect, object);
|
||||||
const int last_type = INTEGRATOR_STATE(state, isect, type);
|
const int last_type = INTEGRATOR_STATE(state, isect, type);
|
||||||
|
|
||||||
|
uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_hash),
|
||||||
|
INTEGRATOR_STATE(state, path, rng_offset),
|
||||||
|
INTEGRATOR_STATE(state, path, sample),
|
||||||
|
0x68bc21eb);
|
||||||
|
|
||||||
/* The lights_intersect() has a "refining" behavior: it chooses intersection closer to the
|
/* The lights_intersect() has a "refining" behavior: it chooses intersection closer to the
|
||||||
* current intersection's distance. Hence initialize the fields which are accessed prior to
|
* current intersection's distance. Hence initialize the fields which are accessed prior to
|
||||||
* recording an intersection. */
|
* recording an intersection. */
|
||||||
|
@ -36,22 +42,20 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
|
||||||
|
|
||||||
// TODO: Support mesh emitters.
|
// TODO: Support mesh emitters.
|
||||||
|
|
||||||
// TODO: Support multiple light sources.
|
|
||||||
|
|
||||||
// TODO: Distant lights.
|
// TODO: Distant lights.
|
||||||
|
|
||||||
// TODO: Only if ray is not fully occluded.
|
// TODO: Only if ray is not fully occluded.
|
||||||
|
|
||||||
// TODO: What of the actual shadow ray hits the same light through a semi-transparent surface?
|
|
||||||
|
|
||||||
const int receiver_forward = light_link_receiver_forward(kg, state);
|
const int receiver_forward = light_link_receiver_forward(kg, state);
|
||||||
|
const int num_hits = lights_intersect_shadow_linked(
|
||||||
|
kg, ray, isect, last_prim, last_object, last_type, path_flag, receiver_forward, &lcg_state);
|
||||||
|
|
||||||
if (!lights_intersect_shadow_linked(
|
if (num_hits == 0) {
|
||||||
kg, ray, isect, last_prim, last_object, last_type, path_flag, receiver_forward))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTEGRATOR_STATE_WRITE(state, shadow_link, dedicated_light_weight) = num_hits;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +86,7 @@ ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state
|
||||||
shadow_linking_store_last_primitives(state);
|
shadow_linking_store_last_primitives(state);
|
||||||
|
|
||||||
/* Write intersection result into global integrator state memory, so that the
|
/* Write intersection result into global integrator state memory, so that the
|
||||||
* shade_dedicated_light kernel can use it for calculation of the light sample, */
|
* shade_dedicated_light kernel can use it for calculation of the light sample. */
|
||||||
integrator_state_write_isect(state, &isect);
|
integrator_state_write_isect(state, &isect);
|
||||||
|
|
||||||
integrator_path_next(kg,
|
integrator_path_next(kg,
|
||||||
|
|
|
@ -73,7 +73,8 @@ ccl_device void shadow_linking_shade(KernelGlobals kg, IntegratorState state)
|
||||||
mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray.P);
|
mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray.P);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Spectrum bsdf_spectrum = light_eval * mis_weight;
|
const Spectrum bsdf_spectrum = light_eval * mis_weight *
|
||||||
|
INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
|
||||||
|
|
||||||
shadow_linking_setup_ray_from_intersection(state, &ray, &isect);
|
shadow_linking_setup_ray_from_intersection(state, &ray, &isect);
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,7 @@ KERNEL_STRUCT_END(guiding)
|
||||||
/******************************* Shadow linking *******************************/
|
/******************************* Shadow linking *******************************/
|
||||||
|
|
||||||
KERNEL_STRUCT_BEGIN(shadow_link)
|
KERNEL_STRUCT_BEGIN(shadow_link)
|
||||||
|
KERNEL_STRUCT_MEMBER(shadow_link, float, dedicated_light_weight, KERNEL_FEATURE_SHADOW_LINKING)
|
||||||
/* Copy of primitive and object from the last main path intersection. */
|
/* Copy of primitive and object from the last main path intersection. */
|
||||||
KERNEL_STRUCT_MEMBER(shadow_link, int, last_isect_prim, KERNEL_FEATURE_SHADOW_LINKING)
|
KERNEL_STRUCT_MEMBER(shadow_link, int, last_isect_prim, KERNEL_FEATURE_SHADOW_LINKING)
|
||||||
KERNEL_STRUCT_MEMBER(shadow_link, int, last_isect_object, KERNEL_FEATURE_SHADOW_LINKING)
|
KERNEL_STRUCT_MEMBER(shadow_link, int, last_isect_object, KERNEL_FEATURE_SHADOW_LINKING)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "kernel/light/point.h"
|
#include "kernel/light/point.h"
|
||||||
#include "kernel/light/spot.h"
|
#include "kernel/light/spot.h"
|
||||||
#include "kernel/light/triangle.h"
|
#include "kernel/light/triangle.h"
|
||||||
|
#include "kernel/sample/lcg.h"
|
||||||
|
|
||||||
#include "kernel/sample/mapping.h"
|
#include "kernel/sample/mapping.h"
|
||||||
|
|
||||||
|
@ -245,16 +246,23 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
||||||
/* Intersect ray with individual light. */
|
/* Intersect ray with individual light. */
|
||||||
|
|
||||||
template<bool is_main_path>
|
template<bool is_main_path>
|
||||||
ccl_device bool lights_intersect_impl(KernelGlobals kg,
|
ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
|
||||||
ccl_private const Ray *ccl_restrict ray,
|
ccl_private const Ray *ccl_restrict ray,
|
||||||
ccl_private Intersection *ccl_restrict isect,
|
ccl_private Intersection *ccl_restrict isect,
|
||||||
const int last_prim,
|
const int last_prim,
|
||||||
const int last_object,
|
const int last_object,
|
||||||
const int last_type,
|
const int last_type,
|
||||||
const uint32_t path_flag,
|
const uint32_t path_flag,
|
||||||
const uint8_t path_mnee,
|
const uint8_t path_mnee,
|
||||||
const int receiver_forward)
|
const int receiver_forward,
|
||||||
|
ccl_private uint *lcg_state)
|
||||||
{
|
{
|
||||||
|
#ifdef __SHADOW_LINKING__
|
||||||
|
const bool is_indirect_ray = !(path_flag & PATH_RAY_CAMERA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int num_hits = 0;
|
||||||
|
|
||||||
for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) {
|
for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) {
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
||||||
|
|
||||||
|
@ -290,7 +298,6 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
|
||||||
* lights. */
|
* lights. */
|
||||||
if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) {
|
if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) {
|
||||||
if (is_main_path) {
|
if (is_main_path) {
|
||||||
const bool is_indirect_ray = !(path_flag & PATH_RAY_CAMERA);
|
|
||||||
if (is_indirect_ray && kernel_data_fetch(lights, lamp).shadow_set_membership) {
|
if (is_indirect_ray && kernel_data_fetch(lights, lamp).shadow_set_membership) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -299,7 +306,6 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __LIGHT_LINKING__
|
#ifdef __LIGHT_LINKING__
|
||||||
|
@ -331,19 +337,39 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t < isect->t &&
|
/* Avoid self-intersections. */
|
||||||
!(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP))
|
if (last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP) {
|
||||||
{
|
continue;
|
||||||
isect->t = t;
|
|
||||||
isect->u = u;
|
|
||||||
isect->v = v;
|
|
||||||
isect->type = PRIMITIVE_LAMP;
|
|
||||||
isect->prim = lamp;
|
|
||||||
isect->object = OBJECT_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++num_hits;
|
||||||
|
|
||||||
|
#ifdef __SHADOW_LINKING__
|
||||||
|
if (!is_main_path) {
|
||||||
|
|||||||
|
/* The non-main rays are only raced by the dedicated light kernel, after the shadow linking
|
||||||
|
* feature check. */
|
||||||
|
kernel_assert(kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING);
|
||||||
|
|
||||||
|
if ((isect->prim != PRIM_NONE) && (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
|
||||||
Sergey Sharybin
commented
I think this should actually be Edit: Sorry for the noise, was looking into the code while being a bit distracted by other tasks. it is actually probably correct, but need to review it with a bit more focused mind. I think this should actually be `lcg_step_float(lcg_state) > 1.0f / num_hits`
Edit: Sorry for the noise, was looking into the code while being a bit distracted by other tasks. it is actually probably correct, but need to review it with a bit more focused mind.
|
|||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (t >= isect->t)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
isect->t = t;
|
||||||
|
isect->u = u;
|
||||||
|
isect->v = v;
|
||||||
|
isect->type = PRIMITIVE_LAMP;
|
||||||
|
isect->prim = lamp;
|
||||||
|
isect->object = OBJECT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isect->prim != PRIM_NONE;
|
return num_hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
ccl_device bool lights_intersect(KernelGlobals kg,
|
ccl_device bool lights_intersect(KernelGlobals kg,
|
||||||
|
@ -358,18 +384,29 @@ ccl_device bool lights_intersect(KernelGlobals kg,
|
||||||
const uint8_t path_mnee = INTEGRATOR_STATE(state, path, mnee);
|
const uint8_t path_mnee = INTEGRATOR_STATE(state, path, mnee);
|
||||||
const int receiver_forward = light_link_receiver_forward(kg, state);
|
const int receiver_forward = light_link_receiver_forward(kg, state);
|
||||||
|
|
||||||
return lights_intersect_impl<true>(
|
lights_intersect_impl<true>(kg,
|
||||||
kg, ray, isect, last_prim, last_object, last_type, path_flag, path_mnee, receiver_forward);
|
ray,
|
||||||
|
isect,
|
||||||
|
last_prim,
|
||||||
|
last_object,
|
||||||
|
last_type,
|
||||||
|
path_flag,
|
||||||
|
path_mnee,
|
||||||
|
receiver_forward,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
return isect->prim != PRIM_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ccl_device bool lights_intersect_shadow_linked(KernelGlobals kg,
|
ccl_device int lights_intersect_shadow_linked(KernelGlobals kg,
|
||||||
ccl_private const Ray *ccl_restrict ray,
|
ccl_private const Ray *ccl_restrict ray,
|
||||||
ccl_private Intersection *ccl_restrict isect,
|
ccl_private Intersection *ccl_restrict isect,
|
||||||
const int last_prim,
|
const int last_prim,
|
||||||
const int last_object,
|
const int last_object,
|
||||||
const int last_type,
|
const int last_type,
|
||||||
const uint32_t path_flag,
|
const uint32_t path_flag,
|
||||||
const int receiver_forward)
|
const int receiver_forward,
|
||||||
|
ccl_private uint *lcg_state)
|
||||||
{
|
{
|
||||||
return lights_intersect_impl<false>(kg,
|
return lights_intersect_impl<false>(kg,
|
||||||
ray,
|
ray,
|
||||||
|
@ -379,7 +416,8 @@ ccl_device bool lights_intersect_shadow_linked(KernelGlobals kg,
|
||||||
last_type,
|
last_type,
|
||||||
path_flag,
|
path_flag,
|
||||||
PATH_MNEE_NONE,
|
PATH_MNEE_NONE,
|
||||||
receiver_forward);
|
receiver_forward,
|
||||||
|
lcg_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup light sample from intersection. */
|
/* Setup light sample from intersection. */
|
||||||
|
|
Loading…
Reference in New Issue
CUDA 10 does not support C++17, so can't use
if constexpr
.Leaving it out should give the same result I think.