[Bf-blender-cvs] [b454416927f] master: Cycles: add non-uniform scaling to spot light size
Weizhen Huang
noreply at git.blender.org
Fri Feb 3 18:55:57 CET 2023
Commit: b454416927f159f2397f1d4b0c12dab38e674a13
Author: Weizhen Huang
Date: Thu Jan 26 16:17:08 2023 +0100
Branches: master
https://developer.blender.org/rBb454416927f159f2397f1d4b0c12dab38e674a13
Cycles: add non-uniform scaling to spot light size
Cycles ignores the size of spot lights, therefore the illuminated area doesn't match the gizmo. This patch resolves this discrepancy.
| Before (Cycles) | After (Cycles) | Eevee
|{F14200605}|{F14200595}|{F14200600}|
This is done by scaling the ray direction by the size of the cone. The implementation of `spot_light_attenuation()` in `spot.h` matches `spot_attenuation()` in `lights_lib.glsl`.
**Test file**:
{F14200728}
Differential Revision: https://developer.blender.org/D17129
===================================================================
M intern/cycles/blender/light.cpp
M intern/cycles/kernel/light/spot.h
M intern/cycles/kernel/svm/brick.h
M intern/cycles/kernel/types.h
M intern/cycles/scene/light.cpp
M intern/cycles/scene/light_tree.cpp
M intern/cycles/util/math.h
===================================================================
diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp
index b8db4c24eb3..d5aba2041ad 100644
--- a/intern/cycles/blender/light.cpp
+++ b/intern/cycles/blender/light.cpp
@@ -48,6 +48,8 @@ void BlenderSync::sync_light(BL::Object &b_parent,
case BL::Light::type_SPOT: {
BL::SpotLight b_spot_light(b_light);
light->set_size(b_spot_light.shadow_soft_size());
+ light->set_axisu(transform_get_column(&tfm, 0));
+ light->set_axisv(transform_get_column(&tfm, 1));
light->set_light_type(LIGHT_SPOT);
light->set_spot_angle(b_spot_light.spot_size());
light->set_spot_smooth(b_spot_light.spot_blend());
diff --git a/intern/cycles/kernel/light/spot.h b/intern/cycles/kernel/light/spot.h
index b1d652f13f9..1ffaebe7c17 100644
--- a/intern/cycles/kernel/light/spot.h
+++ b/intern/cycles/kernel/light/spot.h
@@ -7,24 +7,13 @@
CCL_NAMESPACE_BEGIN
-ccl_device float spot_light_attenuation(float3 dir,
- float cos_half_spot_angle,
- float spot_smooth,
- float3 N)
+ccl_device float spot_light_attenuation(const ccl_global KernelSpotLight *spot, float3 ray)
{
- float attenuation = dot(dir, N);
+ const float3 scaled_ray = safe_normalize(
+ make_float3(dot(ray, spot->axis_u), dot(ray, spot->axis_v), dot(ray, spot->dir)) /
+ spot->len);
- if (attenuation <= cos_half_spot_angle) {
- attenuation = 0.0f;
- }
- else {
- float t = attenuation - cos_half_spot_angle;
-
- if (t < spot_smooth && spot_smooth != 0.0f)
- attenuation *= smoothstepf(t / spot_smooth);
- }
-
- return attenuation;
+ return smoothstepf((scaled_ray.z - spot->cos_half_spot_angle) / spot->spot_smooth);
}
template<bool in_volume_segment>
@@ -57,8 +46,7 @@ ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight,
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
/* spot light attenuation */
- ls->eval_fac *= spot_light_attenuation(
- klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D);
+ ls->eval_fac *= spot_light_attenuation(&klight->spot, -ls->D);
if (!in_volume_segment && ls->eval_fac == 0.0f) {
return false;
}
@@ -87,8 +75,7 @@ ccl_device_forceinline void spot_light_update_position(const ccl_global KernelLi
ls->pdf = invarea;
/* spot light attenuation */
- ls->eval_fac *= spot_light_attenuation(
- klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, ls->Ng);
+ ls->eval_fac *= spot_light_attenuation(&klight->spot, ls->Ng);
}
ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight,
@@ -129,8 +116,7 @@ ccl_device_inline bool spot_light_sample_from_intersection(
ls->pdf = invarea;
/* spot light attenuation */
- ls->eval_fac *= spot_light_attenuation(
- klight->spot.dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D);
+ ls->eval_fac *= spot_light_attenuation(&klight->spot, -ls->D);
if (ls->eval_fac == 0.0f) {
return false;
diff --git a/intern/cycles/kernel/svm/brick.h b/intern/cycles/kernel/svm/brick.h
index f8fa4a4a84a..e64fc636334 100644
--- a/intern/cycles/kernel/svm/brick.h
+++ b/intern/cycles/kernel/svm/brick.h
@@ -46,17 +46,8 @@ ccl_device_noinline_cpu float2 svm_brick(float3 p,
float tint = saturatef((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias));
float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
- float mortar;
- if (min_dist >= mortar_size) {
- mortar = 0.0f;
- }
- else if (mortar_smooth == 0.0f) {
- mortar = 1.0f;
- }
- else {
- min_dist = 1.0f - min_dist / mortar_size;
- mortar = (min_dist < mortar_smooth) ? smoothstepf(min_dist / mortar_smooth) : 1.0f;
- }
+ min_dist = 1.0f - min_dist / mortar_size;
+ float mortar = smoothstepf(min_dist / mortar_smooth);
return make_float2(tint, mortar);
}
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 4fad62d757d..cfbaba20ec1 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1290,12 +1290,14 @@ typedef struct KernelCurveSegment {
static_assert_align(KernelCurveSegment, 8);
typedef struct KernelSpotLight {
+ packed_float3 axis_u;
float radius;
+ packed_float3 axis_v;
float invarea;
+ packed_float3 dir;
float cos_half_spot_angle;
+ packed_float3 len;
float spot_smooth;
- packed_float3 dir;
- float pad;
} KernelSpotLight;
/* PointLight is SpotLight with only radius and invarea being used. */
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index fa710e8b250..3c5698b4218 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -1076,23 +1076,31 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
else if (light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;
+ float3 len;
+ float3 axis_u = normalize_len(light->axisu, &len.x);
+ float3 axis_v = normalize_len(light->axisv, &len.y);
+ float3 dir = normalize_len(light->dir, &len.z);
+ if (len.z == 0.0f) {
+ dir = zero_float3();
+ }
+
float radius = light->size;
float invarea = (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 - cos_half_spot_angle) * light->spot_smooth;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
if (light->use_mis && radius > 0.0f)
shader_id |= SHADER_USE_MIS;
klights[light_index].co = co;
+ klights[light_index].spot.axis_u = axis_u;
klights[light_index].spot.radius = radius;
+ klights[light_index].spot.axis_v = 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.len = len;
klights[light_index].spot.spot_smooth = spot_smooth;
- klights[light_index].spot.dir = dir;
}
klights[light_index].shader_id = shader_id;
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 4fa4755479b..1261f09cda0 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -156,7 +156,13 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
}
else if (type == LIGHT_SPOT) {
bcone.theta_o = 0;
- bcone.theta_e = lamp->get_spot_angle() * 0.5f;
+
+ const float unscaled_theta_e = lamp->get_spot_angle() * 0.5f;
+ const float len_u = len(lamp->get_axisu());
+ const float len_v = len(lamp->get_axisv());
+ const float len_w = len(lamp->get_dir());
+
+ bcone.theta_e = fast_atanf(fast_tanf(unscaled_theta_e) * fmaxf(len_u, len_v) / len_w);
/* Point and spot lights can emit light from any point within its radius. */
const float3 radius = make_float3(size);
diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h
index 3618daa4ccb..df75e7bf2b5 100644
--- a/intern/cycles/util/math.h
+++ b/intern/cycles/util/math.h
@@ -483,6 +483,12 @@ ccl_device_inline float compatible_signf(float f)
ccl_device_inline float smoothstepf(float f)
{
+ if (f <= 0.0f) {
+ return 0.0f;
+ }
+ if (f >= 1.0f) {
+ return 1.0f;
+ }
float ff = f * f;
return (3.0f * ff - 2.0f * ff * f);
}
More information about the Bf-blender-cvs
mailing list