Cycles: replace spot light disk sampling with sphere sampling #109329

Merged
Weizhen Huang merged 12 commits from weizhen/blender:spot_light_to_sphere_light_with_cone into main 2023-07-07 17:15:24 +02:00
3 changed files with 12 additions and 22 deletions
Showing only changes of commit d55a26255b - Show all commits

View File

@ -44,7 +44,7 @@ ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight,
ls->P = P + ls->D * ls->t;
ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
ls->eval_fac = klight->spot.eval_fac;
if (r_sq == 0) {
/* Use intensity instead of radiance for point light. */
ls->eval_fac /= sqr(ls->t);
@ -100,7 +100,7 @@ ccl_device_forceinline void point_light_mnee_sample_update(const ccl_global Kern
ls->Ng = normalize(ls->P - klight->co);
}
else {
ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
ls->eval_fac = klight->spot.eval_fac;
ls->Ng = -ls->D;
@ -136,7 +136,7 @@ ccl_device_inline bool point_light_sample_from_intersection(
const uint32_t path_flag,
ccl_private LightSample *ccl_restrict ls)
{
ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
ls->eval_fac = klight->spot.eval_fac;
const float radius = klight->spot.radius;

View File

@ -1353,7 +1353,7 @@ typedef struct KernelSpotLight {
packed_float3 scaled_axis_u;
float radius;
packed_float3 scaled_axis_v;
float invarea;
float eval_fac;
packed_float3 dir;
float cos_half_spot_angle;
float inv_len_z;
@ -1361,6 +1361,7 @@ typedef struct KernelSpotLight {
float pad[2];
} KernelSpotLight;
/* TODO: maybe rename spot to sphere */
/* PointLight is SpotLight with only radius and invarea being used. */
typedef struct KernelAreaLight {

View File

@ -1210,22 +1210,22 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
klights[light_index].strength[1] = light->strength.y;
klights[light_index].strength[2] = light->strength.z;
if (light->light_type == LIGHT_POINT) {
if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
float radius = light->size;
/* TODO: `invarea` was used for disk sampling, with the current solid angle sampling this
* becomes unnecessary. We could store `eval_fac` instead, but currently it shares the same
* #KernelSpotLight type with #LIGHT_SPOT, so keep it know until refactor for spot light. */
float invarea = (light->normalize && radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) :
float invarea = (light->normalize && radius > 0.0f) ? 1.0f / (M_4PI_F * radius * radius) :
1.0f;
/* Convert radiant flux to radiance or radiant intensity. */
float eval_fac = (radius > 0) ? invarea * M_1_PI_F : 0.25f * M_1_PI_F;
if (light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
klights[light_index].co = co;
klights[light_index].spot.radius = radius;
klights[light_index].spot.invarea = invarea;
klights[light_index].spot.eval_fac = eval_fac;
}
else if (light->light_type == LIGHT_DISTANT) {
shader_id &= ~SHADER_AREA_LIGHT;
@ -1306,9 +1306,7 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
klights[light_index].area.tan_half_spread = tan_half_spread;
klights[light_index].area.normalize_spread = normalize_spread;
}
else if (light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
if (light->light_type == LIGHT_SPOT) {
/* Scale axes to accommodate non-uniform scaling. */
float3 scaled_axis_u = light->axisu / len_squared(light->axisu);
float3 scaled_axis_v = light->axisv / len_squared(light->axisv);
@ -1316,20 +1314,11 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
/* Keep direction normalized. */
float3 dir = safe_normalize_len(light->dir, &len_z);
float radius = light->size;
float invarea = (light->normalize && radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) :
1.0f;
float cos_half_spot_angle = cosf(light->spot_angle * 0.5f);
float spot_smooth = 1.0f / ((1.0f - cos_half_spot_angle) * light->spot_smooth);
if (light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
klights[light_index].co = co;
klights[light_index].spot.scaled_axis_u = scaled_axis_u;
klights[light_index].spot.radius = radius;
klights[light_index].spot.scaled_axis_v = scaled_axis_v;
klights[light_index].spot.invarea = invarea;
klights[light_index].spot.dir = dir;
klights[light_index].spot.cos_half_spot_angle = cos_half_spot_angle;
klights[light_index].spot.inv_len_z = 1.0f / len_z;