Cycles/Eevee: unify light strength and color
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 12 May 2019 11:41:23 +0000 (13:41 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Mon, 13 May 2019 13:56:10 +0000 (15:56 +0200)
Cycles lights now use strength and color properties of the light outside
of the shading nodes, just like Eevee. The shading nodes then act as a
multiplier on this, and become optional unless textures, fallof or other
effects are desired.

Backwards compatibility is not exact, as we can't be sure which renderer
the .blend was designed for or even if it was designed for a single one.

If the render engine in the active scene is set to Cycles, lights are
converted to ensure overall light strength remains the same, and removing
unnecessary shader node setups that only included a single emission node.

If the engine is set to Eevee, we increase strength to remove the automatic
100x multiplier that was there to match Cycles.

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

12 files changed:
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/light.cpp
intern/cycles/render/light.h
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenloader/intern/versioning_cycles.c
source/blender/draw/engines/eevee/eevee_lights.c
source/blender/editors/object/object_add.c
source/blender/editors/space_node/node_edit.c

index 0845f56705627d56b75867bb060675b81c69507a..9714067b08e6ddcb2214dbb9e21af5f94bfd40e2 100644 (file)
@@ -1341,6 +1341,10 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
 
         col = layout.column()
 
+        col.prop(light, "color")
+        col.prop(light, "energy")
+        col.separator()
+
         if light.type in {'POINT', 'SUN', 'SPOT'}:
             col.prop(light, "shadow_soft_size", text="Size")
         elif light.type == 'AREA':
@@ -1384,8 +1388,7 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
         layout = self.layout
 
         light = context.light
-        if not panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface'):
-            layout.prop(light, "color")
+        panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
 
 
 class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
index 00f53804e389e4637451438b38476fd0c2de2e11..1094ff37afbbb3f86df0a1819ab9feaac5fb5727 100644 (file)
@@ -182,6 +182,10 @@ void BlenderSync::sync_light(BL::Object &b_parent,
     }
   }
 
+  /* strength */
+  light->strength = get_float3(b_light.color());
+  light->strength *= BL::PointLight(b_light).energy();
+
   /* location and (inverted!) direction */
   light->co = transform_get_column(&tfm, 3);
   light->dir = -transform_get_column(&tfm, 2);
index a08f767f96463042610f3f70828b8330900782ef..8321d0c088c667aabf020561fe0b517032a71fbb 100644 (file)
@@ -1409,16 +1409,9 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all)
         add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree);
       }
       else {
-        float strength = 1.0f;
-
-        if (b_light.type() == BL::Light::type_POINT || b_light.type() == BL::Light::type_SPOT ||
-            b_light.type() == BL::Light::type_AREA) {
-          strength = 100.0f;
-        }
-
         EmissionNode *emission = new EmissionNode();
-        emission->color = get_float3(b_light.color());
-        emission->strength = strength;
+        emission->color = make_float3(1.0f, 1.0f, 1.0f);
+        emission->strength = 1.0f;
         graph->add(emission);
 
         ShaderNode *out = graph->output();
index f2eaa7b50a5e3487560c312eeecc4dae3b7e1d3a..34300543f91693c1fbc4da3c8af57f2412254182 100644 (file)
@@ -90,6 +90,11 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
 
   eval *= ls->eval_fac;
 
+  if (ls->lamp != LAMP_NONE) {
+    const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
+    eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]);
+  }
+
   return eval;
 }
 
index 7d4f655a32e7fcebae11666c673bcb606d7c48e0..4070d5a89923a9a0af44a245eb4b1152d771ad9d 100644 (file)
@@ -1455,6 +1455,8 @@ typedef struct KernelLight {
   int samples;
   float max_bounces;
   float random;
+  float strength[3];
+  float pad1;
   Transform tfm;
   Transform itfm;
   union {
index d4c233e3bb32615b594df46a81363c2ff07d8b33..ef4bd4260c9155cde28970911e4ce852ae74df6d 100644 (file)
@@ -114,6 +114,8 @@ NODE_DEFINE(Light)
   type_enum.insert("spot", LIGHT_SPOT);
   SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
 
+  SOCKET_COLOR(strength, "Strength", make_float3(1.0f, 1.0f, 1.0f));
+
   SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f));
 
   SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f));
@@ -162,6 +164,9 @@ void Light::tag_update(Scene *scene)
 
 bool Light::has_contribution(Scene *scene)
 {
+  if (strength == make_float3(0.0f, 0.0f, 0.0f)) {
+    return false;
+  }
   if (is_portal) {
     return false;
   }
@@ -672,7 +677,6 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
     float3 co = light->co;
     Shader *shader = (light->shader) ? light->shader : scene->default_light;
     int shader_id = scene->shader_manager->get_shader_id(shader);
-    int samples = light->samples;
     int max_bounces = light->max_bounces;
     float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
 
@@ -697,7 +701,10 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
     }
 
     klights[light_index].type = light->type;
-    klights[light_index].samples = samples;
+    klights[light_index].samples = light->samples;
+    klights[light_index].strength[0] = light->strength.x;
+    klights[light_index].strength[1] = light->strength.y;
+    klights[light_index].strength[2] = light->strength.z;
 
     if (light->type == LIGHT_POINT) {
       shader_id &= ~SHADER_AREA_LIGHT;
index 66732000f3b7fd05d7e011bb541f75aa3cc0a5e5..a7bffde7a8db6485f913cdcd699007f0e81a8768 100644 (file)
@@ -42,6 +42,7 @@ class Light : public Node {
   Light();
 
   LightType type;
+  float3 strength;
   float3 co;
 
   float3 dir;
index 74d33a9c2752dc6dcda46f4cde96d9d1c3000968..a36ead4630e5898a6c45949269bb856a4293efe3 100644 (file)
@@ -27,7 +27,7 @@
  * \note Use #STRINGIFY() rather than defining with quotes.
  */
 #define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 63
+#define BLENDER_SUBVERSION 64
 /** Several breakages with 280, e.g. collections vs layers. */
 #define BLENDER_MINVERSION 280
 #define BLENDER_MINSUBVERSION 0
index 2bd379c6f198e23561ee939c03259864578eaafe..7616e62af9f0448dd57f66cb03731726e33d9ed8 100644 (file)
@@ -49,6 +49,12 @@ static float *cycles_node_socket_float_value(bNodeSocket *socket)
   return &socket_data->value;
 }
 
+static float *cycles_node_socket_rgba_value(bNodeSocket *socket)
+{
+  bNodeSocketValueRGBA *socket_data = socket->default_value;
+  return socket_data->value;
+}
+
 static IDProperty *cycles_properties_from_ID(ID *id)
 {
   IDProperty *idprop = IDP_GetProperties(id, false);
@@ -291,6 +297,87 @@ static void image_node_colorspace(bNode *node)
   }
 }
 
+static void light_emission_node_to_energy(Light *light, float *energy, float color[3])
+{
+  *energy = 1.0;
+  copy_v3_fl(color, 1.0f);
+
+  /* If nodetree has animation or drivers, don't try to convert. */
+  bNodeTree *ntree = light->nodetree;
+  if (ntree == NULL || ntree->adt) {
+    return;
+  }
+
+  /* Find emission node */
+  bNode *output_node = ntreeShaderOutputNode(ntree, SHD_OUTPUT_CYCLES);
+  if (output_node == NULL) {
+    return;
+  }
+
+  bNode *emission_node = NULL;
+  for (bNodeLink *link = ntree->links.first; link; link = link->next) {
+    if (link->tonode == output_node && link->fromnode->type == SH_NODE_EMISSION) {
+      emission_node = link->fromnode;
+      break;
+    }
+  }
+
+  if (emission_node == NULL) {
+    return;
+  }
+
+  /* Don't convert if anything is linked */
+  bNodeSocket *strength_socket = nodeFindSocket(emission_node, SOCK_IN, "Strength");
+  bNodeSocket *color_socket = nodeFindSocket(emission_node, SOCK_IN, "Color");
+
+  if ((strength_socket->flag & SOCK_IN_USE) || (color_socket->flag & SOCK_IN_USE)) {
+    return;
+  }
+
+  float *strength_value = cycles_node_socket_float_value(strength_socket);
+  float *color_value = cycles_node_socket_rgba_value(color_socket);
+
+  *energy = *strength_value;
+  copy_v3_v3(color, color_value);
+
+  *strength_value = 1.0f;
+  copy_v4_fl(color_value, 1.0f);
+  light->use_nodes = false;
+}
+
+static void light_emission_unify(Light *light, const char *engine)
+{
+  if (light->type != LA_SUN) {
+    light->energy *= 100.0f;
+  }
+
+  /* Attempt to extract constant energy and color from nodes. */
+  bool use_nodes = light->use_nodes;
+  float energy, color[3];
+  light_emission_node_to_energy(light, &energy, color);
+
+  if (STREQ(engine, "CYCLES")) {
+    if (use_nodes) {
+      /* Energy extracted from nodes */
+      light->energy = energy;
+      copy_v3_v3(&light->r, color);
+    }
+    else {
+      /* Default cycles multipliers if there are no nodes */
+      if (light->type == LA_SUN) {
+        light->energy = 1.0f;
+      }
+      else {
+        light->energy = 100.0f;
+      }
+    }
+  }
+  else {
+    /* Disable nodes if scene was configured for Eevee */
+    light->use_nodes = false;
+  }
+}
+
 void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
 {
   /* Particle shape shared with Eevee. */
@@ -364,4 +451,14 @@ void do_versions_after_linking_cycles(Main *bmain)
     }
     FOREACH_NODETREE_END;
   }
+
+  if (!MAIN_VERSION_ATLEAST(bmain, 280, 64)) {
+    /* Unfiy Cycles and Eevee settings. */
+    Scene *scene = bmain->scenes.first;
+    const char *engine = (scene) ? scene->r.engine : "CYCLES";
+
+    for (Light *light = bmain->lights.first; light; light = light->id.next) {
+      light_emission_unify(light, engine);
+    }
+  }
 }
index 6e6c23205feb64511813a6c6b2acf147b6f2dba9..0e24115f849dbce82d09bd00d8f4bd8cf9cdaed8 100644 (file)
@@ -645,7 +645,7 @@ float light_attenuation_radius_get(Light *la, float light_threshold)
 
   /* Compute max light power. */
   float power = max_fff(la->r, la->g, la->b);
-  power *= fabsf(la->energy);
+  power *= fabsf(la->energy / 100.0f);
   power *= max_ff(1.0f, la->spec_fac);
   /* Compute the distance (using the inverse square law)
    * at which the light power reaches the light_threshold. */
@@ -683,7 +683,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli)
   /* Make illumination power constant */
   if (la->type == LA_AREA) {
     power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */
-            80.0f; /* XXX : Empirical, Fit cycles power */
+            0.8f; /* XXX : Empirical, Fit cycles power */
     if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
       /* Scale power to account for the lower area of the ellipse compared to the surrounding
        * rectangle. */
@@ -691,8 +691,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli)
     }
   }
   else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
-    power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */
-            M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+    power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* 1/(4*r²*Pi²) */
 
     /* for point lights (a.k.a radius == 0.0) */
     // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
index e52eee0693d80b539ac9de6e56d22c1b8603c7b2..ef7c1d35609e20426a97810afedccc79b35d2991 100644 (file)
@@ -1176,7 +1176,6 @@ static const char *get_light_defname(int type)
 
 static int object_light_add_exec(bContext *C, wmOperator *op)
 {
-  Scene *scene = CTX_data_scene(C);
   Object *ob;
   Light *la;
   int type = RNA_enum_get(op->ptr, "type");
@@ -1207,11 +1206,6 @@ static int object_light_add_exec(bContext *C, wmOperator *op)
   la = (Light *)ob->data;
   la->type = type;
 
-  if (BKE_scene_uses_cycles(scene)) {
-    ED_node_shader_default(C, &la->id);
-    la->use_nodes = true;
-  }
-
   return OPERATOR_FINISHED;
 }
 
index 3e73cc52c527ec787726ee8b17ec00da0e869746..fb34d9dc45963b11595139213eee1448c96bd2dd 100644 (file)
@@ -453,13 +453,8 @@ void ED_node_shader_default(const bContext *C, ID *id)
       output_type = SH_NODE_OUTPUT_LIGHT;
       shader_type = SH_NODE_EMISSION;
 
-      copy_v3_v3(color, &la->r);
-      if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA) {
-        strength = 100.0f;
-      }
-      else {
-        strength = 1.0f;
-      }
+      copy_v3_fl3(color, 1.0f, 1.0f, 1.0f);
+      strength = 1.0f;
       break;
     }
     default: