Light linking: Support distant lights for shadow linking #107979

Merged
Sergey Sharybin merged 2 commits from Sergey/blender:cycles-light-linking-distant into cycles-light-linking 2023-05-16 17:59:59 +02:00
6 changed files with 92 additions and 9 deletions

View File

@ -42,8 +42,6 @@ ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
// TODO: Support mesh emitters.
// TODO: Distant lights.
// TODO: Only if ray is not fully occluded.
const int receiver_forward = light_link_receiver_forward(kg, state);

View File

@ -138,10 +138,17 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
continue;
}
#endif
/* Light linking. */
#ifdef __LIGHT_LINKING__
if (!light_link_light_match(kg, light_link_receiver_forward(kg, state), lamp)) {
continue;
}
#endif
#ifdef __SHADOW_LINKING__
if (kernel_data_fetch(lights, lamp).shadow_set_membership != LIGHT_LINK_MASK_ALL) {
continue;
}
#endif
#ifdef __MNEE__
if (INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_CULL_LIGHT_CONNECTION) {

View File

@ -5,11 +5,44 @@
#include "kernel/integrator/path_state.h"
#include "kernel/integrator/shade_surface.h"
#include "kernel/light/distant.h"
#include "kernel/light/light.h"
CCL_NAMESPACE_BEGIN
#ifdef __SHADOW_LINKING__
ccl_device_inline bool shadow_linking_light_sample_from_intersection(
KernelGlobals kg,
ccl_private const Intersection &ccl_restrict isect,
ccl_private const Ray &ccl_restrict ray,
ccl_private LightSample *ccl_restrict ls)
{
const int lamp = isect.prim;
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
const LightType type = LightType(klight->type);
if (type == LIGHT_DISTANT) {
return distant_light_sample_from_intersection(kg, ray.D, lamp, ls);
}
return light_sample_from_intersection(kg, &isect, ray.P, ray.D, ls);
}
ccl_device_inline float shadow_linking_light_sample_mis_weight(KernelGlobals kg,
IntegratorState state,
const uint32_t path_flag,
const ccl_private LightSample *ls,
const float3 P)
{
if (ls->type == LIGHT_DISTANT) {
return light_sample_mis_weight_forward_distant(kg, state, path_flag, ls);
}
return light_sample_mis_weight_forward_lamp(kg, state, path_flag, ls, P);
}
/* Setup ray for the shadow path.
* Expects that the current state of the ray is the one calculated by the surface bounce, and the
* intersection corresponds to a point on an emitter. */
@ -49,7 +82,7 @@ ccl_device void shadow_linking_shade(KernelGlobals kg, IntegratorState state)
integrator_state_read_ray(state, &ray);
LightSample ls ccl_optional_struct_init;
const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray.P, ray.D, &ls);
const bool use_light_sample = shadow_linking_light_sample_from_intersection(kg, isect, ray, &ls);
if (!use_light_sample) {
/* No light to be sampled, so no direct light contribution either. */
return;
@ -70,7 +103,7 @@ ccl_device void shadow_linking_shade(KernelGlobals kg, IntegratorState state)
/* MIS weighting. */
float mis_weight = 1.0f;
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray.P);
mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
}
const Spectrum bsdf_spectrum = light_eval * mis_weight *

View File

@ -20,10 +20,10 @@ ccl_device_forceinline bool shadow_linking_scene_need_shadow_ray(KernelGlobals k
return false;
}
if (!kernel_data.integrator.use_light_mis) {
/* No need to cast extra shadow linking path if there are no lights with MIS in the scene. */
return false;
}
/* The distant lights might be using shadow linking, and they are not counted as
* kernel_data.integrator.use_light_mis.
* So there is a potential to avoid extra rays from being traced, but it requires more granular
* flags set in the integrator. */
return true;
}

View File

@ -36,6 +36,39 @@ ccl_device_inline bool distant_light_sample(const ccl_global KernelLight *klight
return true;
}
/* Special intersection check.
* Returns true if the distant_light_sample_from_intersection() for this light would return true.
*
* The intersection parameters t, u, v are optimized for the shadow ray towards a dedicated light:
* u = v = 0, t = FLT_MAX.
*/
ccl_device bool distant_light_intersect(const ccl_global KernelLight *klight,
const ccl_private Ray *ccl_restrict ray,
ccl_private float *t,
ccl_private float *u,
ccl_private float *v)
{
kernel_assert(klight->type == LIGHT_DISTANT);
if (klight->distant.radius == 0.0f) {
return false;
}
const float3 lightD = klight->co;
const float costheta = dot(-lightD, ray->D);
const float cosangle = klight->distant.cosangle;
if (costheta < cosangle) {
return false;
}
*t = FLT_MAX;
*u = 0.0f;
*v = 0.0f;
return true;
}
ccl_device bool distant_light_sample_from_intersection(KernelGlobals kg,
const float3 ray_D,
const int lamp,

View File

@ -335,6 +335,14 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
continue;
}
}
else if (type == LIGHT_DISTANT) {
if (is_main_path) {

Can't use constexpr.

Can't use constexpr.
continue;
}
if (!distant_light_intersect(klight, ray, &t, &u, &v)) {
continue;
}
}
else {
continue;
}
@ -374,6 +382,8 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
return num_hits;
}
/* Lights intersection for the main path.
* Intersects spot, point, and area lights. */
ccl_device bool lights_intersect(KernelGlobals kg,
IntegratorState state,
ccl_private const Ray *ccl_restrict ray,
@ -400,6 +410,8 @@ ccl_device bool lights_intersect(KernelGlobals kg,
return isect->prim != PRIM_NONE;
}
/* Lights intersection for the shadow linking.
* Intersects spot, point, area, and distant lights. */
ccl_device int lights_intersect_shadow_linked(KernelGlobals kg,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,