Uses a light tree to more effectively sample scenes with many lights. This can significantly reduce noise, at the cost of a somewhat longer render time per sample. Light tree sampling is enabled by default. It can be disabled in the Sampling > Lights panel. Scenes using light clamping or ray visibility tricks may render different as these are biased techniques that depend on the sampling strategy. The implementation is currently disabled on AMD HIP. This is planned to be fixed before the release. Implementation by Jeffrey Liu, Weizhen Huang, Alaska and Brecht Van Lommel. Ref T77889
128 lines
3.6 KiB
C
128 lines
3.6 KiB
C
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/geom/geom.h"
|
|
|
|
#include "kernel/light/common.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
ccl_device_inline bool distant_light_sample(const ccl_global KernelLight *klight,
|
|
const float randu,
|
|
const float randv,
|
|
ccl_private LightSample *ls)
|
|
{
|
|
/* distant light */
|
|
float3 lightD = klight->co;
|
|
float3 D = lightD;
|
|
float radius = klight->distant.radius;
|
|
float invarea = klight->distant.invarea;
|
|
|
|
if (radius > 0.0f) {
|
|
D = normalize(D + disk_light_sample(D, randu, randv) * radius);
|
|
}
|
|
|
|
ls->P = D;
|
|
ls->Ng = D;
|
|
ls->D = -D;
|
|
ls->t = FLT_MAX;
|
|
|
|
float costheta = dot(lightD, D);
|
|
ls->pdf = invarea / (costheta * costheta * costheta);
|
|
ls->eval_fac = ls->pdf;
|
|
|
|
return true;
|
|
}
|
|
|
|
ccl_device bool distant_light_sample_from_intersection(KernelGlobals kg,
|
|
const float3 ray_D,
|
|
const int lamp,
|
|
ccl_private LightSample *ccl_restrict ls)
|
|
{
|
|
ccl_global const KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
|
const int shader = klight->shader_id;
|
|
const float radius = klight->distant.radius;
|
|
const LightType type = (LightType)klight->type;
|
|
|
|
if (type != LIGHT_DISTANT) {
|
|
return false;
|
|
}
|
|
if (!(shader & SHADER_USE_MIS)) {
|
|
return false;
|
|
}
|
|
if (radius == 0.0f) {
|
|
return false;
|
|
}
|
|
|
|
/* a distant light is infinitely far away, but equivalent to a disk
|
|
* shaped light exactly 1 unit away from the current shading point.
|
|
*
|
|
* radius t^2/cos(theta)
|
|
* <----------> t = sqrt(1^2 + tan(theta)^2)
|
|
* tan(th) area = radius*radius*pi
|
|
* <----->
|
|
* \ | (1 + tan(theta)^2)/cos(theta)
|
|
* \ | (1 + tan(acos(cos(theta)))^2)/cos(theta)
|
|
* t \th| 1 simplifies to
|
|
* \-| 1/(cos(theta)^3)
|
|
* \| magic!
|
|
* P
|
|
*/
|
|
|
|
float3 lightD = klight->co;
|
|
float costheta = dot(-lightD, ray_D);
|
|
float cosangle = klight->distant.cosangle;
|
|
|
|
/* Workaround to prevent a hang in the classroom scene with AMD HIP drivers 22.10,
|
|
* Remove when a compiler fix is available. */
|
|
#ifdef __HIP__
|
|
ls->shader = klight->shader_id;
|
|
#endif
|
|
|
|
if (costheta < cosangle)
|
|
return false;
|
|
|
|
ls->type = type;
|
|
#ifndef __HIP__
|
|
ls->shader = klight->shader_id;
|
|
#endif
|
|
ls->object = PRIM_NONE;
|
|
ls->prim = PRIM_NONE;
|
|
ls->lamp = lamp;
|
|
/* todo: missing texture coordinates */
|
|
ls->u = 0.0f;
|
|
ls->v = 0.0f;
|
|
ls->t = FLT_MAX;
|
|
ls->P = -ray_D;
|
|
ls->Ng = -ray_D;
|
|
ls->D = ray_D;
|
|
ls->group = lamp_lightgroup(kg, lamp);
|
|
|
|
/* compute pdf */
|
|
float invarea = klight->distant.invarea;
|
|
ls->pdf = invarea / (costheta * costheta * costheta);
|
|
ls->eval_fac = ls->pdf;
|
|
|
|
return true;
|
|
}
|
|
|
|
ccl_device_forceinline bool distant_light_tree_parameters(const float3 centroid,
|
|
const float theta_e,
|
|
ccl_private float &cos_theta_u,
|
|
ccl_private float2 &distance,
|
|
ccl_private float3 &point_to_centroid)
|
|
{
|
|
/* Treating it as a disk light 1 unit away */
|
|
cos_theta_u = fast_cosf(theta_e);
|
|
|
|
distance = make_float2(1.0f / cos_theta_u, 1.0f);
|
|
|
|
point_to_centroid = -centroid;
|
|
|
|
return true;
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|