[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