Cycles/Eevee: unify light strength and color

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
This commit is contained in:
Brecht Van Lommel 2019-05-12 13:41:23 +02:00
parent 7ad802cf3a
commit 21854575a4
12 changed files with 131 additions and 31 deletions

View 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):

View 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);

View 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();

View 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;
}

View 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 {

View 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;

View File

@ -42,6 +42,7 @@ class Light : public Node {
Light();
LightType type;
float3 strength;
float3 co;
float3 dir;

View 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

View 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);
}
}
}

View 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 */

View 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;
}

View 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: