[Bf-blender-cvs] [a4260ac2197] master: Cycles: add a spread setting for area lights

Matteo Falduto noreply at git.blender.org
Thu Apr 1 12:32:48 CEST 2021


Commit: a4260ac21977acd5b9cd792f2a68c3aa78dd91cd
Author: Matteo Falduto
Date:   Thu Apr 1 05:35:56 2021 +0200
Branches: master
https://developer.blender.org/rBa4260ac21977acd5b9cd792f2a68c3aa78dd91cd

Cycles: add a spread setting for area lights

This simulates the effect of a honeycomb or grid placed in front of a softbox.
In practice, it works by attenuating rays coming off-angle as a function of the
provided spread angle parameter.

Setting the parameter to 180 degrees poses no restrictions to the rays, making
the light behave the same way as before this patch.

The total light power is normalized based on the spread angle, so that the
light strength remains the same.

Differential Revision: https://developer.blender.org/D10594

===================================================================

M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/blender_light.cpp
M	intern/cycles/kernel/kernel_light.h
M	intern/cycles/kernel/kernel_light_common.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/light.cpp
M	intern/cycles/render/light.h
M	source/blender/blenloader/intern/versioning_290.c
M	source/blender/makesdna/DNA_light_defaults.h
M	source/blender/makesdna/DNA_light_types.h
M	source/blender/makesrna/intern/rna_light.c

===================================================================

diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index c9b4dc25cf2..4e8527387c0 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1409,15 +1409,15 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
         panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
 
 
-class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
-    bl_label = "Spot Shape"
+class CYCLES_LIGHT_PT_beam_shape(CyclesButtonsPanel, Panel):
+    bl_label = "Beam Shape"
     bl_parent_id = "CYCLES_LIGHT_PT_light"
     bl_context = "data"
 
     @classmethod
     def poll(cls, context):
-        light = context.light
-        return (light and light.type == 'SPOT') and CyclesButtonsPanel.poll(context)
+        if context.light.type in {'SPOT', 'AREA'}:
+            return context.light and CyclesButtonsPanel.poll(context)
 
     def draw(self, context):
         layout = self.layout
@@ -1425,9 +1425,12 @@ class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
         layout.use_property_split = True
 
         col = layout.column()
-        col.prop(light, "spot_size", text="Size")
-        col.prop(light, "spot_blend", text="Blend", slider=True)
-        col.prop(light, "show_cone")
+        if light.type == 'SPOT':
+            col.prop(light, "spot_size", text="Spot Size")
+            col.prop(light, "spot_blend", text="Blend", slider=True)
+            col.prop(light, "show_cone")
+        elif light.type == 'AREA':
+            col.prop(light, "spread", text="Spread")
 
 
 class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel):
@@ -2284,7 +2287,7 @@ classes = (
     CYCLES_LIGHT_PT_preview,
     CYCLES_LIGHT_PT_light,
     CYCLES_LIGHT_PT_nodes,
-    CYCLES_LIGHT_PT_spot,
+    CYCLES_LIGHT_PT_beam_shape,
     CYCLES_WORLD_PT_preview,
     CYCLES_WORLD_PT_surface,
     CYCLES_WORLD_PT_volume,
@@ -2314,7 +2317,7 @@ classes = (
     node_panel(CYCLES_WORLD_PT_settings_surface),
     node_panel(CYCLES_WORLD_PT_settings_volume),
     node_panel(CYCLES_LIGHT_PT_light),
-    node_panel(CYCLES_LIGHT_PT_spot),
+    node_panel(CYCLES_LIGHT_PT_beam_shape)
 )
 
 
diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp
index ff4ecc5a3f9..283ed7d0adc 100644
--- a/intern/cycles/blender/blender_light.cpp
+++ b/intern/cycles/blender/blender_light.cpp
@@ -82,6 +82,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
       light->set_axisu(transform_get_column(&tfm, 0));
       light->set_axisv(transform_get_column(&tfm, 1));
       light->set_sizeu(b_area_light.size());
+      light->set_spread(b_area_light.spread());
       switch (b_area_light.shape()) {
         case BL::AreaLight::shape_SQUARE:
           light->set_sizev(light->get_sizeu());
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 9650b85a5c2..93b05f0ffce 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -147,6 +147,13 @@ ccl_device_inline bool lamp_light_sample(
       ls->D = normalize_len(ls->P - P, &ls->t);
 
       ls->eval_fac = 0.25f * invarea;
+
+      if (klight->area.tan_spread > 0.0f) {
+        /* Area Light spread angle attenuation */
+        ls->eval_fac *= light_spread_attenuation(
+            ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
+      }
+
       if (is_round) {
         ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t);
       }
@@ -286,6 +293,15 @@ ccl_device bool lamp_light_eval(
       ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
     }
     ls->eval_fac = 0.25f * invarea;
+
+    if (klight->area.tan_spread > 0.0f) {
+      /* Area Light spread angle attenuation */
+      ls->eval_fac *= light_spread_attenuation(
+          ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
+      if (ls->eval_fac == 0.0f) {
+        return false;
+      }
+    }
   }
   else {
     return false;
diff --git a/intern/cycles/kernel/kernel_light_common.h b/intern/cycles/kernel/kernel_light_common.h
index 39503a4b479..7efd1e74202 100644
--- a/intern/cycles/kernel/kernel_light_common.h
+++ b/intern/cycles/kernel/kernel_light_common.h
@@ -146,6 +146,17 @@ ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot
   return attenuation;
 }
 
+ccl_device float light_spread_attenuation(const float3 D,
+                                          const float3 Ng,
+                                          const float tan_spread,
+                                          const float normalize_spread)
+{
+  const float cos_a = -dot(D, Ng);
+  const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
+  const float tan_a = sin_a / cos_a;
+  return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f);
+}
+
 ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
 {
   float cos_pi = dot(Ng, I);
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index df56360b1df..ab54fda14af 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -1501,9 +1501,9 @@ typedef struct KernelAreaLight {
   float axisu[3];
   float invarea;
   float axisv[3];
-  float pad1;
+  float tan_spread;
   float dir[3];
-  float pad2;
+  float normalize_spread;
 } KernelAreaLight;
 
 typedef struct KernelDistantLight {
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 72450e2c546..858b177b69c 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -129,6 +129,7 @@ NODE_DEFINE(Light)
   SOCKET_VECTOR(axisv, "Axis V", zero_float3());
   SOCKET_FLOAT(sizev, "Size V", 1.0f);
   SOCKET_BOOLEAN(round, "Round", false);
+  SOCKET_FLOAT(spread, "Spread", M_PI_F);
 
   SOCKET_INT(map_resolution, "Map Resolution", 0);
 
@@ -858,6 +859,15 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
       float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
       float3 dir = light->dir;
 
+      /* Convert from spread angle 0..180 to 90..0, clamping to a minimum
+       * angle to avoid excessive noise. */
+      const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
+      const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
+      /* Normalization computed using:
+       * integrate cos(x) (1 - tan(x) * tan(a)) * sin(x) from x = a to pi/2. */
+      const float tan_spread = tanf(spread_angle);
+      const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);
+
       dir = safe_normalize(dir);
 
       if (light->use_mis && area != 0.0f)
@@ -877,6 +887,8 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
       klights[light_index].area.dir[0] = dir.x;
       klights[light_index].area.dir[1] = dir.y;
       klights[light_index].area.dir[2] = dir.z;
+      klights[light_index].area.tan_spread = tan_spread;
+      klights[light_index].area.normalize_spread = normalize_spread;
     }
     else if (light->light_type == LIGHT_SPOT) {
       shader_id &= ~SHADER_AREA_LIGHT;
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 39014b5d667..fbd709125ff 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -58,6 +58,7 @@ class Light : public Node {
   NODE_SOCKET_API(float3, axisv)
   NODE_SOCKET_API(float, sizev)
   NODE_SOCKET_API(bool, round)
+  NODE_SOCKET_API(float, spread)
 
   NODE_SOCKET_API(Transform, tfm)
 
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index d8f798a11cd..0c6817542d1 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1963,5 +1963,12 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
         arm->axes_position = 1.0;
       }
     }
+
+    /* Initialize the spread parameter for area lights*/
+    if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "area_spread")) {
+      LISTBASE_FOREACH (Light *, la, &bmain->lights) {
+        la->area_spread = DEG2RADF(180.0f);
+      }
+    }
   }
 }
diff --git a/source/blender/makesdna/DNA_light_defaults.h b/source/blender/makesdna/DNA_light_defaults.h
index f3ccf14ac5b..5e5ce4bf540 100644
--- a/source/blender/makesdna/DNA_light_defaults.h
+++ b/source/blender/makesdna/DNA_light_defaults.h
@@ -68,6 +68,7 @@
     .volume_fac = 1.0f, \
     .att_dist = 40.0f, \
     .sun_angle = DEG2RADF(0.526f), \
+    .area_spread = DEG2RADF(180.0f), \
   }
 
 /** \} */
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 3b7440aedd2..82ff3c95834 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -70,9 +70,9 @@ typedef struct Light {
 
   short area_shape;
   float area_size, area_sizey, area_sizez;
+  float area_spread;
 
   float sun_angle;
-  char _pad3[4];
 
   /* texact is for buttons */
   short texact, shadhalostep;
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index bb99e5c6c1d..0593db0dd56 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -480,6 +480,15 @@ static void rna_def_area_light(BlenderRNA *brna)
       "Size Y",
       "Size of the area of the area light in the Y direction for rectangle shapes");
   RNA_def_property_update(prop, 0, "rna_Light_draw_update");
+
+  prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_ANGLE);
+  RNA_def_property_float_sdna(prop, NULL, "area_spread");
+  RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
+  RNA_def_property_ui_text(
+      prop,
+      "Spread",
+      "How widely the emitted light fans out, as in the case of a gridded softbox");
+  RNA_def_property_update(prop, 0, "rna_Light_draw_update");
 }
 
 static void rna_def_spot_light(BlenderRNA *brna)



More information about the Bf-blender-cvs mailing list