Light Linking: Select one of dedicated lights #107739

Merged
Sergey Sharybin merged 3 commits from Sergey/blender:cycles-light-linking-multiple-light into cycles-light-linking 2023-05-16 16:24:34 +02:00
4 changed files with 85 additions and 41 deletions

View File

@ -8,6 +8,7 @@
#include "kernel/integrator/shade_surface.h"
#include "kernel/integrator/shadow_linking.h"
#include "kernel/light/light.h"
#include "kernel/sample/lcg.h"
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_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
* current intersection's distance. Hence initialize the fields which are accessed prior to
* recording an intersection. */
@ -36,22 +42,20 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
// TODO: Support mesh emitters.
// TODO: Support multiple light sources.
// TODO: Distant lights.
// 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 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(
kg, ray, isect, last_prim, last_object, last_type, path_flag, receiver_forward))
{
if (num_hits == 0) {
return false;
}
INTEGRATOR_STATE_WRITE(state, shadow_link, dedicated_light_weight) = num_hits;
return true;
}
@ -82,7 +86,7 @@ ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state
shadow_linking_store_last_primitives(state);
/* 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_path_next(kg,

View File

@ -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);
}
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);

View File

@ -139,6 +139,7 @@ KERNEL_STRUCT_END(guiding)
/******************************* Shadow linking *******************************/
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. */
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)

View File

@ -9,6 +9,7 @@
#include "kernel/light/point.h"
#include "kernel/light/spot.h"
#include "kernel/light/triangle.h"
#include "kernel/sample/lcg.h"
#include "kernel/sample/mapping.h"
@ -245,16 +246,23 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
/* Intersect ray with individual light. */
template<bool is_main_path>
ccl_device bool lights_intersect_impl(KernelGlobals kg,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
const int last_object,
const int last_type,
const uint32_t path_flag,
const uint8_t path_mnee,
const int receiver_forward)
ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
const int last_object,
const int last_type,
const uint32_t path_flag,
const uint8_t path_mnee,
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++) {
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
@ -290,7 +298,6 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
* lights. */
if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) {
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) {
continue;
}
@ -299,7 +306,6 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
continue;
}
}
#endif
#ifdef __LIGHT_LINKING__
@ -331,19 +337,39 @@ ccl_device bool lights_intersect_impl(KernelGlobals kg,
continue;
}
if (t < isect->t &&
!(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP))
{
isect->t = t;
isect->u = u;
isect->v = v;
isect->type = PRIMITIVE_LAMP;
isect->prim = lamp;
isect->object = OBJECT_NONE;
/* Avoid self-intersections. */
if (last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP) {
continue;
}
++num_hits;
#ifdef __SHADOW_LINKING__
if (!is_main_path) {

CUDA 10 does not support C++17, so can't use if constexpr.

Leaving it out should give the same result I think.

CUDA 10 does not support C++17, so can't use `if constexpr`. Leaving it out should give the same result I think.
/* 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)) {
Review

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.

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,
@ -358,18 +384,29 @@ ccl_device bool lights_intersect(KernelGlobals kg,
const uint8_t path_mnee = INTEGRATOR_STATE(state, path, mnee);
const int receiver_forward = light_link_receiver_forward(kg, state);
return lights_intersect_impl<true>(
kg, ray, isect, last_prim, last_object, last_type, path_flag, path_mnee, receiver_forward);
lights_intersect_impl<true>(kg,
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_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
const int last_object,
const int last_type,
const uint32_t path_flag,
const int receiver_forward)
ccl_device int lights_intersect_shadow_linked(KernelGlobals kg,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
const int last_object,
const int last_type,
const uint32_t path_flag,
const int receiver_forward,
ccl_private uint *lcg_state)
{
return lights_intersect_impl<false>(kg,
ray,
@ -379,7 +416,8 @@ ccl_device bool lights_intersect_shadow_linked(KernelGlobals kg,
last_type,
path_flag,
PATH_MNEE_NONE,
receiver_forward);
receiver_forward,
lcg_state);
}
/* Setup light sample from intersection. */