Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/addon/engine.py4
-rw-r--r--intern/cycles/blender/addon/ui.py43
-rw-r--r--intern/cycles/blender/light.cpp3
-rw-r--r--intern/cycles/blender/object.cpp3
-rw-r--r--intern/cycles/blender/shader.cpp2
-rw-r--r--intern/cycles/blender/sync.cpp14
-rw-r--r--intern/cycles/integrator/pass_accessor.cpp17
-rw-r--r--intern/cycles/integrator/pass_accessor.h1
-rw-r--r--intern/cycles/kernel/film/accumulate.h38
-rw-r--r--intern/cycles/kernel/geom/object.h20
-rw-r--r--intern/cycles/kernel/integrator/shade_background.h3
-rw-r--r--intern/cycles/kernel/integrator/shade_light.h2
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h9
-rw-r--r--intern/cycles/kernel/integrator/shade_volume.h9
-rw-r--r--intern/cycles/kernel/integrator/shadow_state_template.h2
-rw-r--r--intern/cycles/kernel/light/light.h5
-rw-r--r--intern/cycles/kernel/types.h13
-rw-r--r--intern/cycles/scene/background.cpp11
-rw-r--r--intern/cycles/scene/background.h2
-rw-r--r--intern/cycles/scene/film.cpp41
-rw-r--r--intern/cycles/scene/film.h2
-rw-r--r--intern/cycles/scene/light.cpp10
-rw-r--r--intern/cycles/scene/light.h2
-rw-r--r--intern/cycles/scene/object.cpp16
-rw-r--r--intern/cycles/scene/object.h5
-rw-r--r--intern/cycles/scene/pass.cpp18
-rw-r--r--intern/cycles/scene/pass.h8
-rw-r--r--intern/cycles/scene/scene.cpp5
-rw-r--r--intern/cycles/scene/scene.h3
-rw-r--r--intern/cycles/session/buffers.cpp6
-rw-r--r--intern/cycles/session/buffers.h4
31 files changed, 279 insertions, 42 deletions
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 48dd26cc622..b7713dc7110 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -228,6 +228,10 @@ def list_render_passes(scene, srl):
else:
yield (aov.name, "RGB", 'COLOR')
+ # Light groups.
+ for lightgroup in srl.lightgroups:
+ yield ("Combined_%s" % lightgroup.name, "RGB", 'COLOR')
+
def register_passes(engine, scene, view_layer):
for name, channelids, channeltype in list_render_passes(scene, view_layer):
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index c86452e0a18..c97afa86fad 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -12,7 +12,7 @@ from bpy.types import Panel
from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel
from bl_ui.properties_render import draw_hair_settings
-from bl_ui.properties_view_layer import ViewLayerCryptomattePanel, ViewLayerAOVPanel
+from bl_ui.properties_view_layer import ViewLayerCryptomattePanel, ViewLayerAOVPanel, ViewLayerLightgroupsPanel
class CyclesPresetPanel(PresetPanel, Panel):
COMPAT_ENGINES = {'CYCLES'}
@@ -883,6 +883,12 @@ class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, ViewLayerAOVPanel):
bl_parent_id = "CYCLES_RENDER_PT_passes"
+class CYCLES_RENDER_PT_passes_lightgroups(CyclesButtonsPanel, ViewLayerLightgroupsPanel):
+ bl_label = "Light Groups"
+ bl_context = "view_layer"
+ bl_parent_id = "CYCLES_RENDER_PT_passes"
+
+
class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
@@ -1082,7 +1088,7 @@ class CYCLES_OBJECT_PT_shading(CyclesButtonsPanel, Panel):
return False
ob = context.object
- return ob and has_geometry_visibility(ob) and ob.type != 'LIGHT'
+ return ob and has_geometry_visibility(ob)
def draw(self, context):
pass
@@ -1093,6 +1099,10 @@ class CYCLES_OBJECT_PT_shading_shadow_terminator(CyclesButtonsPanel, Panel):
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_context = "object"
+ @classmethod
+ def poll(cls, context):
+ return context.object.type != 'LIGHT'
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1110,6 +1120,10 @@ class CYCLES_OBJECT_PT_shading_gi_approximation(CyclesButtonsPanel, Panel):
bl_parent_id = "CYCLES_OBJECT_PT_shading"
bl_context = "object"
+ @classmethod
+ def poll(cls, context):
+ return context.object.type != 'LIGHT'
+
def draw(self, context):
layout = self.layout
layout.use_property_split = True
@@ -1132,7 +1146,7 @@ class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return CyclesButtonsPanel.poll(context) and not use_metal(context)
+ return CyclesButtonsPanel.poll(context) and not use_metal(context) and context.object.type != 'LIGHT'
def draw(self, context):
layout = self.layout
@@ -1147,6 +1161,23 @@ class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel):
col.prop(cob, "is_caustics_receiver")
+class CYCLES_OBJECT_PT_lightgroup(CyclesButtonsPanel, Panel):
+ bl_label = "Light Group"
+ bl_parent_id = "CYCLES_OBJECT_PT_shading"
+ bl_context = "object"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ ob = context.object
+
+ view_layer = context.view_layer
+
+ col = layout.column(align=True)
+ col.prop_search(ob, "lightgroup", view_layer, "lightgroups", text="Light Group")
+
+
class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
bl_label = "Visibility"
bl_context = "object"
@@ -1399,10 +1430,14 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel):
layout.use_property_split = True
world = context.world
+ view_layer = context.view_layer
if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
layout.prop(world, "color")
+ col = layout.column(align=True)
+ col.prop_search(world, "lightgroup", view_layer, "lightgroups", text="Light Group")
+
class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
@@ -2209,6 +2244,7 @@ classes = (
CYCLES_RENDER_PT_passes_light,
CYCLES_RENDER_PT_passes_crypto,
CYCLES_RENDER_PT_passes_aov,
+ CYCLES_RENDER_PT_passes_lightgroups,
CYCLES_RENDER_PT_filter,
CYCLES_RENDER_PT_override,
CYCLES_PT_post_processing,
@@ -2220,6 +2256,7 @@ classes = (
CYCLES_OBJECT_PT_shading_shadow_terminator,
CYCLES_OBJECT_PT_shading_gi_approximation,
CYCLES_OBJECT_PT_shading_caustics,
+ CYCLES_OBJECT_PT_lightgroup,
CYCLES_OBJECT_PT_visibility,
CYCLES_OBJECT_PT_visibility_ray_visibility,
CYCLES_OBJECT_PT_visibility_culling,
diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp
index 04799443ceb..5359fa13505 100644
--- a/intern/cycles/blender/light.cpp
+++ b/intern/cycles/blender/light.cpp
@@ -143,6 +143,9 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
+ /* lightgroup */
+ light->set_lightgroup(ustring(b_ob_info.real_object.lightgroup()));
+
/* tag */
light->tag_update(scene);
}
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 16a6b3454ed..d8f236e0641 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -343,6 +343,9 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0));
}
+ /* lightgroup */
+ object->set_lightgroup(ustring(b_ob.lightgroup()));
+
object->tag_update(scene);
}
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 224cbea85f3..d3527567b96 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -1532,6 +1532,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
background->set_use_shader(view_layer.use_background_shader ||
viewport_parameters.use_custom_shader());
+ background->set_lightgroup(ustring(b_world ? b_world.lightgroup() : ""));
+
background->tag_update(scene);
}
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 8af2ee7a435..bd6bfafedeb 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -745,6 +745,20 @@ void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_v
}
}
+ /* Light Group passes. */
+ BL::ViewLayer::lightgroups_iterator b_lightgroup_iter;
+ for (b_view_layer.lightgroups.begin(b_lightgroup_iter);
+ b_lightgroup_iter != b_view_layer.lightgroups.end();
+ ++b_lightgroup_iter) {
+ BL::Lightgroup b_lightgroup(*b_lightgroup_iter);
+
+ string name = string_printf("Combined_%s", b_lightgroup.name().c_str());
+
+ b_engine.add_pass(name.c_str(), 3, "RGB", b_view_layer.name().c_str());
+ Pass *pass = pass_add(scene, PASS_COMBINED, name.c_str(), PassMode::NOISY);
+ pass->set_lightgroup(ustring(b_lightgroup.name()));
+ }
+
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
}
diff --git a/intern/cycles/integrator/pass_accessor.cpp b/intern/cycles/integrator/pass_accessor.cpp
index 0be3cf6860b..05318b7545b 100644
--- a/intern/cycles/integrator/pass_accessor.cpp
+++ b/intern/cycles/integrator/pass_accessor.cpp
@@ -18,7 +18,11 @@ CCL_NAMESPACE_BEGIN
*/
PassAccessor::PassAccessInfo::PassAccessInfo(const BufferPass &pass)
- : type(pass.type), mode(pass.mode), include_albedo(pass.include_albedo), offset(pass.offset)
+ : type(pass.type),
+ mode(pass.mode),
+ include_albedo(pass.include_albedo),
+ is_lightgroup(!pass.lightgroup.empty()),
+ offset(pass.offset)
{
}
@@ -127,7 +131,8 @@ bool PassAccessor::get_render_tile_pixels(const RenderBuffers *render_buffers,
const PassType type = pass_access_info_.type;
const PassMode mode = pass_access_info_.mode;
- const PassInfo pass_info = Pass::get_info(type, pass_access_info_.include_albedo);
+ const PassInfo pass_info = Pass::get_info(
+ type, pass_access_info_.include_albedo, pass_access_info_.is_lightgroup);
int num_written_components = pass_info.num_components;
if (pass_info.num_components == 1) {
@@ -215,8 +220,8 @@ void PassAccessor::init_kernel_film_convert(KernelFilmConvert *kfilm_convert,
const Destination &destination) const
{
const PassMode mode = pass_access_info_.mode;
- const PassInfo &pass_info = Pass::get_info(pass_access_info_.type,
- pass_access_info_.include_albedo);
+ const PassInfo &pass_info = Pass::get_info(
+ pass_access_info_.type, pass_access_info_.include_albedo, pass_access_info_.is_lightgroup);
kfilm_convert->pass_offset = pass_access_info_.offset;
kfilm_convert->pass_stride = buffer_params.pass_stride;
@@ -279,8 +284,8 @@ bool PassAccessor::set_render_tile_pixels(RenderBuffers *render_buffers, const S
return false;
}
- const PassInfo pass_info = Pass::get_info(pass_access_info_.type,
- pass_access_info_.include_albedo);
+ const PassInfo pass_info = Pass::get_info(
+ pass_access_info_.type, pass_access_info_.include_albedo, pass_access_info_.is_lightgroup);
const BufferParams &buffer_params = render_buffers->params;
diff --git a/intern/cycles/integrator/pass_accessor.h b/intern/cycles/integrator/pass_accessor.h
index 7de1d03961b..683d3a35272 100644
--- a/intern/cycles/integrator/pass_accessor.h
+++ b/intern/cycles/integrator/pass_accessor.h
@@ -28,6 +28,7 @@ class PassAccessor {
PassType type = PASS_NONE;
PassMode mode = PassMode::NOISY;
bool include_albedo = false;
+ bool is_lightgroup = false;
int offset = -1;
/* For the shadow catcher matte pass: whether to approximate shadow catcher pass into its
diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h
index d6a385a4bff..e10acfd7eb5 100644
--- a/intern/cycles/kernel/film/accumulate.h
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -320,12 +320,13 @@ ccl_device_inline void kernel_accum_combined_transparent_pass(KernelGlobals kg,
}
/* Write background or emission to appropriate pass. */
-ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg,
- ConstIntegratorState state,
- float3 contribution,
- ccl_global float *ccl_restrict
- buffer,
- const int pass)
+ccl_device_inline void kernel_accum_emission_or_background_pass(
+ KernelGlobals kg,
+ ConstIntegratorState state,
+ float3 contribution,
+ ccl_global float *ccl_restrict buffer,
+ const int pass,
+ const int lightgroup = LIGHTGROUP_NONE)
{
if (!(kernel_data.film.light_pass_flag & PASS_ANY)) {
return;
@@ -347,6 +348,11 @@ ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg
}
# endif /* __DENOISING_FEATURES__ */
+ if (lightgroup != LIGHTGROUP_NONE && kernel_data.film.pass_lightgroup != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup,
+ contribution);
+ }
+
if (!(path_flag & PATH_RAY_ANY_PASS)) {
/* Directly visible, write to emission or background pass. */
pass_offset = pass;
@@ -449,6 +455,13 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg,
return;
}
+ /* Write lightgroup pass. LIGHTGROUP_NONE is ~0 so decode from unsigned to signed */
+ const int lightgroup = (int)(INTEGRATOR_STATE(state, shadow_path, lightgroup)) - 1;
+ if (lightgroup != LIGHTGROUP_NONE && kernel_data.film.pass_lightgroup != PASS_UNUSED) {
+ kernel_write_pass_float3(buffer + kernel_data.film.pass_lightgroup + 3 * lightgroup,
+ contribution);
+ }
+
if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
int pass_offset = PASS_UNUSED;
@@ -566,15 +579,20 @@ ccl_device_inline void kernel_accum_background(KernelGlobals kg,
kernel_accum_combined_transparent_pass(
kg, path_flag, sample, contribution, transparent, buffer);
}
- kernel_accum_emission_or_background_pass(
- kg, state, contribution, buffer, kernel_data.film.pass_background);
+ kernel_accum_emission_or_background_pass(kg,
+ state,
+ contribution,
+ buffer,
+ kernel_data.film.pass_background,
+ kernel_data.background.lightgroup);
}
/* Write emission to render buffer. */
ccl_device_inline void kernel_accum_emission(KernelGlobals kg,
ConstIntegratorState state,
const float3 L,
- ccl_global float *ccl_restrict render_buffer)
+ ccl_global float *ccl_restrict render_buffer,
+ const int lightgroup = LIGHTGROUP_NONE)
{
float3 contribution = L;
kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1);
@@ -585,7 +603,7 @@ ccl_device_inline void kernel_accum_emission(KernelGlobals kg,
kernel_accum_combined_pass(kg, path_flag, sample, contribution, buffer);
kernel_accum_emission_or_background_pass(
- kg, state, contribution, buffer, kernel_data.film.pass_emission);
+ kg, state, contribution, buffer, kernel_data.film.pass_emission, lightgroup);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h
index 86c57c84b47..3faab7fa905 100644
--- a/intern/cycles/kernel/geom/object.h
+++ b/intern/cycles/kernel/geom/object.h
@@ -283,6 +283,26 @@ ccl_device_inline float object_pass_id(KernelGlobals kg, int object)
return kernel_tex_fetch(__objects, object).pass_id;
}
+/* Lightgroup of lamp */
+
+ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
+{
+ if (lamp == LAMP_NONE)
+ return LIGHTGROUP_NONE;
+
+ return kernel_tex_fetch(__lights, lamp).lightgroup;
+}
+
+/* Lightgroup of object */
+
+ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return LIGHTGROUP_NONE;
+
+ return kernel_tex_fetch(__objects, object).lightgroup;
+}
+
/* Per lamp random number for shader variation */
ccl_device_inline float lamp_random_number(KernelGlobals kg, int lamp)
diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h
index 4fd41121466..62b3ce1c15c 100644
--- a/intern/cycles/kernel/integrator/shade_background.h
+++ b/intern/cycles/kernel/integrator/shade_background.h
@@ -186,7 +186,8 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
/* Write to render buffer. */
const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput * light_eval, render_buffer);
+ kernel_accum_emission(
+ kg, state, throughput * light_eval, render_buffer, kernel_data.background.lightgroup);
}
}
}
diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h
index 4a519a76ed0..be926c78439 100644
--- a/intern/cycles/kernel/integrator/shade_light.h
+++ b/intern/cycles/kernel/integrator/shade_light.h
@@ -78,7 +78,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
/* Write to render buffer. */
const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput * light_eval, render_buffer);
+ kernel_accum_emission(kg, state, throughput * light_eval, render_buffer, ls.group);
}
ccl_device void integrator_shade_light(KernelGlobals kg,
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index c5dd9fe27f4..a9bf3b5b432 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -87,7 +87,8 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
}
const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
- kernel_accum_emission(kg, state, throughput * L, render_buffer);
+ kernel_accum_emission(
+ kg, state, throughput * L, render_buffer, object_lightgroup(kg, sd->object));
}
#endif /* __EMISSION__ */
@@ -258,6 +259,12 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_PASS) {
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
}
+
+ /* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */
+ INTEGRATOR_STATE_WRITE(
+ shadow_state, shadow_path, lightgroup) = (ls.type != LIGHT_BACKGROUND) ?
+ ls.group + 1 :
+ kernel_data.background.lightgroup + 1;
}
#endif
diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h
index acda4b8e9d1..4a5015946aa 100644
--- a/intern/cycles/kernel/integrator/shade_volume.h
+++ b/intern/cycles/kernel/integrator/shade_volume.h
@@ -653,7 +653,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
/* Write accumulated emission. */
if (!is_zero(accum_emission)) {
- kernel_accum_emission(kg, state, accum_emission, render_buffer);
+ kernel_accum_emission(
+ kg, state, accum_emission, render_buffer, object_lightgroup(kg, sd->object));
}
# ifdef __DENOISING_FEATURES__
@@ -833,6 +834,12 @@ ccl_device_forceinline void integrate_volume_direct_light(
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = throughput;
}
+ /* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */
+ INTEGRATOR_STATE_WRITE(
+ shadow_state, shadow_path, lightgroup) = (ls->type != LIGHT_BACKGROUND) ?
+ ls->group + 1 :
+ kernel_data.background.lightgroup + 1;
+
integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
}
# endif
diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h
index 9308df53e46..eaee65ada40 100644
--- a/intern/cycles/kernel/integrator/shadow_state_template.h
+++ b/intern/cycles/kernel/integrator/shadow_state_template.h
@@ -38,6 +38,8 @@ KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_diffuse_weight, KERNEL_FEA
KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES)
/* Number of intersections found by ray-tracing. */
KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, num_hits, KERNEL_FEATURE_PATH_TRACING)
+/* Light group. */
+KERNEL_STRUCT_MEMBER(shadow_path, uint8_t, lightgroup, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_END(shadow_path)
/********************************** Shadow Ray *******************************/
diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h
index fb637008ca4..1df1615ed99 100644
--- a/intern/cycles/kernel/light/light.h
+++ b/intern/cycles/kernel/light/light.h
@@ -23,6 +23,7 @@ typedef struct LightSample {
int prim; /* primitive id for triangle/curve lights */
int shader; /* shader id */
int lamp; /* lamp id */
+ int group; /* lightgroup */
LightType type; /* type of light */
} LightSample;
@@ -52,6 +53,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
ls->lamp = lamp;
ls->u = randu;
ls->v = randv;
+ ls->group = lamp_lightgroup(kg, lamp);
if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) {
/* Distant lights in a volume get a dummy sample, position will not actually
@@ -413,6 +415,7 @@ ccl_device bool light_sample_from_distant_ray(KernelGlobals kg,
ls->P = -ray_D;
ls->Ng = -ray_D;
ls->D = ray_D;
+ ls->group = lamp_lightgroup(kg, lamp);
/* compute pdf */
float invarea = klight->distant.invarea;
@@ -441,6 +444,7 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
ls->t = isect->t;
ls->P = ray_P + ray_D * ls->t;
ls->D = ray_D;
+ ls->group = lamp_lightgroup(kg, lamp);
if (type == LIGHT_SPOT) {
const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
@@ -706,6 +710,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
ls->lamp = LAMP_NONE;
ls->shader |= SHADER_USE_MIS;
ls->type = LIGHT_TRIANGLE;
+ ls->group = object_lightgroup(kg, object);
float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0));
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 00b5b007e11..9d9daaa0dda 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -46,6 +46,7 @@ CCL_NAMESPACE_BEGIN
#define LAMP_NONE (~0)
#define ID_NONE (0.0f)
#define PASS_UNUSED (~0)
+#define LIGHTGROUP_NONE (~0)
#define INTEGRATOR_SHADOW_ISECT_SIZE_CPU 1024U
#define INTEGRATOR_SHADOW_ISECT_SIZE_GPU 4U
@@ -1108,6 +1109,7 @@ typedef struct KernelFilm {
int pass_aov_color;
int pass_aov_value;
+ int pass_lightgroup;
/* XYZ to rendering color space transform. float4 instead of float3 to
* ensure consistent padding/alignment across devices. */
@@ -1192,8 +1194,10 @@ typedef struct KernelBackground {
int use_mis;
+ int lightgroup;
+
/* Padding */
- int pad1, pad2, pad3;
+ int pad1, pad2;
} KernelBackground;
static_assert_align(KernelBackground, 16);
@@ -1372,9 +1376,12 @@ typedef struct KernelObject {
float ao_distance;
+ int lightgroup;
+
uint visibility;
int primitive_type;
- int pad[2];
+
+ int pad1;
} KernelObject;
static_assert_align(KernelObject, 16);
@@ -1427,7 +1434,7 @@ typedef struct KernelLight {
float random;
float strength[3];
int use_caustics;
- float pad1;
+ int lightgroup;
Transform tfm;
Transform itfm;
union {
diff --git a/intern/cycles/scene/background.cpp b/intern/cycles/scene/background.cpp
index 1c3a9f9358d..bffc8895bfd 100644
--- a/intern/cycles/scene/background.cpp
+++ b/intern/cycles/scene/background.cpp
@@ -32,6 +32,8 @@ NODE_DEFINE(Background)
SOCKET_NODE(shader, "Shader", Shader::get_node_type());
+ SOCKET_STRING(lightgroup, "Light Group", ustring());
+
return type;
}
@@ -101,6 +103,15 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA;
}
+ /* Light group. */
+ auto it = scene->lightgroups.find(lightgroup);
+ if (it != scene->lightgroups.end()) {
+ kbackground->lightgroup = it->second;
+ }
+ else {
+ kbackground->lightgroup = LIGHTGROUP_NONE;
+ }
+
clear_modified();
}
diff --git a/intern/cycles/scene/background.h b/intern/cycles/scene/background.h
index bbffce6e30a..50b4368d708 100644
--- a/intern/cycles/scene/background.h
+++ b/intern/cycles/scene/background.h
@@ -30,6 +30,8 @@ class Background : public Node {
NODE_SOCKET_API(float, volume_step_size)
+ NODE_SOCKET_API(ustring, lightgroup)
+
Background();
~Background();
diff --git a/intern/cycles/scene/film.cpp b/intern/cycles/scene/film.cpp
index e17c839d60b..c3b126544c4 100644
--- a/intern/cycles/scene/film.cpp
+++ b/intern/cycles/scene/film.cpp
@@ -175,6 +175,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->pass_volume_direct = PASS_UNUSED;
kfilm->pass_volume_indirect = PASS_UNUSED;
kfilm->pass_shadow = PASS_UNUSED;
+ kfilm->pass_lightgroup = PASS_UNUSED;
/* Mark passes as unused so that the kernel knows the pass is inaccessible. */
kfilm->pass_denoising_normal = PASS_UNUSED;
@@ -189,6 +190,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
bool have_cryptomatte = false;
bool have_aov_color = false;
bool have_aov_value = false;
+ bool have_lightgroup = false;
for (size_t i = 0; i < scene->passes.size(); i++) {
const Pass *pass = scene->passes[i];
@@ -223,6 +225,15 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
assert(pass->get_type() <= PASS_CATEGORY_BAKE_END);
}
+ if (pass->get_lightgroup() != ustring()) {
+ if (!have_lightgroup) {
+ kfilm->pass_lightgroup = kfilm->pass_stride;
+ have_lightgroup = true;
+ }
+ kfilm->pass_stride += pass->get_info().num_components;
+ continue;
+ }
+
switch (pass->get_type()) {
case PASS_COMBINED:
kfilm->pass_combined = kfilm->pass_stride;
@@ -414,6 +425,26 @@ int Film::get_aov_offset(Scene *scene, string name, bool &is_color)
return -1;
}
+bool Film::update_lightgroups(Scene *scene)
+{
+ map<ustring, int> lightgroups;
+ int i = 0;
+ foreach (const Pass *pass, scene->passes) {
+ ustring lightgroup = pass->get_lightgroup();
+ if (!lightgroup.empty()) {
+ if (!lightgroups.count(lightgroup)) {
+ lightgroups[lightgroup] = i++;
+ }
+ }
+ }
+ if (scene->lightgroups != lightgroups) {
+ scene->lightgroups = lightgroups;
+ return true;
+ }
+
+ return false;
+}
+
void Film::update_passes(Scene *scene, bool add_sample_count_pass)
{
const Background *background = scene->background;
@@ -580,11 +611,19 @@ void Film::remove_auto_passes(Scene *scene)
static bool compare_pass_order(const Pass *a, const Pass *b)
{
+ /* On the highest level, sort by number of components.
+ * Within passes of the same component count, sort so that all non-lightgroup passes come first.
+ * Within that group, sort by type. */
const int num_components_a = a->get_info().num_components;
const int num_components_b = b->get_info().num_components;
if (num_components_a == num_components_b) {
- return (a->get_type() < b->get_type());
+ const int is_lightgroup_a = !a->get_lightgroup().empty();
+ const int is_lightgroup_b = !b->get_lightgroup().empty();
+ if (is_lightgroup_a == is_lightgroup_b) {
+ return (a->get_type() < b->get_type());
+ }
+ return is_lightgroup_b;
}
return num_components_a > num_components_b;
diff --git a/intern/cycles/scene/film.h b/intern/cycles/scene/film.h
index 43597b0fc79..f1e3237eb9e 100644
--- a/intern/cycles/scene/film.h
+++ b/intern/cycles/scene/film.h
@@ -68,6 +68,8 @@ class Film : public Node {
int get_aov_offset(Scene *scene, string name, bool &is_color);
+ bool update_lightgroups(Scene *scene);
+
/* Update passes so that they contain all passes required for the configured functionality.
*
* If `add_sample_count_pass` is true then the SAMPLE_COUNT pass is ensured to be added. */
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 85a7f37994c..5e311d3051f 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -134,6 +134,8 @@ NODE_DEFINE(Light)
SOCKET_NODE(shader, "Shader", Shader::get_node_type());
+ SOCKET_STRING(lightgroup, "Light Group", ustring());
+
return type;
}
@@ -902,6 +904,14 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].tfm = light->tfm;
klights[light_index].itfm = transform_inverse(light->tfm);
+ auto it = scene->lightgroups.find(light->lightgroup);
+ if (it != scene->lightgroups.end()) {
+ klights[light_index].lightgroup = it->second;
+ }
+ else {
+ klights[light_index].lightgroup = LIGHTGROUP_NONE;
+ }
+
light_index++;
}
diff --git a/intern/cycles/scene/light.h b/intern/cycles/scene/light.h
index 25190f6fb63..5b852f210fc 100644
--- a/intern/cycles/scene/light.h
+++ b/intern/cycles/scene/light.h
@@ -71,6 +71,8 @@ class Light : public Node {
NODE_SOCKET_API(int, max_bounces)
NODE_SOCKET_API(uint, random_id)
+ NODE_SOCKET_API(ustring, lightgroup)
+
void tag_update(Scene *scene);
/* Check whether the light has contribution the scene. */
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 9b19169880a..55d89fc3673 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -98,6 +98,8 @@ NODE_DEFINE(Object)
SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f);
+ SOCKET_STRING(lightgroup, "Light Group", ustring());
+
return type;
}
@@ -393,7 +395,8 @@ static float object_volume_density(const Transform &tfm, Geometry *geom)
void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state,
Object *ob,
- bool update_all)
+ bool update_all,
+ const Scene *scene)
{
KernelObject &kobject = state->objects[ob->index];
Transform *object_motion_pass = state->object_motion_pass;
@@ -532,6 +535,15 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
if (geom->geometry_type == Geometry::HAIR) {
state->have_curves = true;
}
+
+ /* Light group. */
+ auto it = scene->lightgroups.find(ob->lightgroup);
+ if (it != scene->lightgroups.end()) {
+ kobject.lightgroup = it->second;
+ }
+ else {
+ kobject.lightgroup = LIGHTGROUP_NONE;
+ }
}
void ObjectManager::device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene)
@@ -618,7 +630,7 @@ void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene,
[&](const blocked_range<size_t> &r) {
for (size_t i = r.begin(); i != r.end(); i++) {
Object *ob = state.scene->objects[i];
- device_update_object_transform(&state, ob, update_all);
+ device_update_object_transform(&state, ob, update_all, scene);
}
});
diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h
index 561ecd4e7e9..c41f1416180 100644
--- a/intern/cycles/scene/object.h
+++ b/intern/cycles/scene/object.h
@@ -66,6 +66,8 @@ class Object : public Node {
NODE_SOCKET_API(float, ao_distance)
+ NODE_SOCKET_API(ustring, lightgroup)
+
/* Set during device update. */
bool intersects_volume;
@@ -169,7 +171,8 @@ class ObjectManager {
protected:
void device_update_object_transform(UpdateObjectTransformState *state,
Object *ob,
- bool update_all);
+ bool update_all,
+ const Scene *scene);
void device_update_object_transform_task(UpdateObjectTransformState *state);
bool device_update_object_transform_pop_work(UpdateObjectTransformState *state,
int *start_index,
diff --git a/intern/cycles/scene/pass.cpp b/intern/cycles/scene/pass.cpp
index 41730cb189d..5f5b19e710d 100644
--- a/intern/cycles/scene/pass.cpp
+++ b/intern/cycles/scene/pass.cpp
@@ -124,6 +124,7 @@ NODE_DEFINE(Pass)
SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
SOCKET_STRING(name, "Name", ustring());
SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
+ SOCKET_STRING(lightgroup, "Light Group", ustring());
return type;
}
@@ -134,7 +135,7 @@ Pass::Pass() : Node(get_node_type()), is_auto_(false)
PassInfo Pass::get_info() const
{
- return get_info(type, include_albedo);
+ return get_info(type, include_albedo, !lightgroup.empty());
}
bool Pass::is_written() const
@@ -142,7 +143,7 @@ bool Pass::is_written() const
return get_info().is_written;
}
-PassInfo Pass::get_info(const PassType type, const bool include_albedo)
+PassInfo Pass::get_info(const PassType type, const bool include_albedo, const bool is_lightgroup)
{
PassInfo pass_info;
@@ -157,9 +158,9 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo)
pass_info.num_components = 0;
break;
case PASS_COMBINED:
- pass_info.num_components = 4;
+ pass_info.num_components = is_lightgroup ? 3 : 4;
pass_info.use_exposure = true;
- pass_info.support_denoise = true;
+ pass_info.support_denoise = !is_lightgroup;
break;
case PASS_DEPTH:
pass_info.num_components = 1;
@@ -369,13 +370,16 @@ const Pass *Pass::find(const vector<Pass *> &passes, const string &name)
return nullptr;
}
-const Pass *Pass::find(const vector<Pass *> &passes, PassType type, PassMode mode)
+const Pass *Pass::find(const vector<Pass *> &passes,
+ PassType type,
+ PassMode mode,
+ const ustring &lightgroup)
{
for (const Pass *pass : passes) {
- if (pass->get_type() != type || pass->get_mode() != mode) {
+ if (pass->get_type() != type || pass->get_mode() != mode ||
+ pass->get_lightgroup() != lightgroup) {
continue;
}
-
return pass;
}
diff --git a/intern/cycles/scene/pass.h b/intern/cycles/scene/pass.h
index c12df007b5d..e0689eba688 100644
--- a/intern/cycles/scene/pass.h
+++ b/intern/cycles/scene/pass.h
@@ -53,6 +53,7 @@ class Pass : public Node {
NODE_SOCKET_API(PassMode, mode)
NODE_SOCKET_API(ustring, name)
NODE_SOCKET_API(bool, include_albedo)
+ NODE_SOCKET_API(ustring, lightgroup)
Pass();
@@ -72,7 +73,9 @@ class Pass : public Node {
static const NodeEnum *get_type_enum();
static const NodeEnum *get_mode_enum();
- static PassInfo get_info(PassType type, const bool include_albedo = false);
+ static PassInfo get_info(PassType type,
+ const bool include_albedo = false,
+ const bool is_lightgroup = false);
static bool contains(const vector<Pass *> &passes, PassType type);
@@ -80,7 +83,8 @@ class Pass : public Node {
static const Pass *find(const vector<Pass *> &passes, const string &name);
static const Pass *find(const vector<Pass *> &passes,
PassType type,
- PassMode mode = PassMode::NOISY);
+ PassMode mode = PassMode::NOISY,
+ const ustring &lightgroup = ustring());
/* Returns PASS_UNUSED if there is no corresponding pass. */
static int get_offset(const vector<Pass *> &passes, const Pass *pass);
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index 359e2d8e2c3..b6b53004816 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -251,6 +251,11 @@ void Scene::device_update(Device *device_, Progress &progress)
* - Lookup tables are done a second time to handle film tables
*/
+ if (film->update_lightgroups(this)) {
+ light_manager->tag_update(this, ccl::LightManager::LIGHT_MODIFIED);
+ object_manager->tag_update(this, ccl::ObjectManager::OBJECT_MODIFIED);
+ }
+
progress.set_status("Updating Shaders");
shader_manager->device_update(device, &dscene, this, progress);
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
index e1b36899302..9e3e8d61b80 100644
--- a/intern/cycles/scene/scene.h
+++ b/intern/cycles/scene/scene.h
@@ -197,6 +197,9 @@ class Scene : public NodeOwner {
/* Optional name. Is used for logging and reporting. */
string name;
+ /* Maps from Light group names to their pass ID. */
+ map<ustring, int> lightgroups;
+
/* data */
BVH *bvh;
Camera *camera;
diff --git a/intern/cycles/session/buffers.cpp b/intern/cycles/session/buffers.cpp
index f9893ed1e1c..3bbc205ca7a 100644
--- a/intern/cycles/session/buffers.cpp
+++ b/intern/cycles/session/buffers.cpp
@@ -49,6 +49,7 @@ NODE_DEFINE(BufferPass)
SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
SOCKET_STRING(name, "Name", ustring());
SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
+ SOCKET_STRING(lightgroup, "Light Group", ustring());
SOCKET_INT(offset, "Offset", -1);
@@ -64,13 +65,14 @@ BufferPass::BufferPass(const Pass *scene_pass)
type(scene_pass->get_type()),
mode(scene_pass->get_mode()),
name(scene_pass->get_name()),
- include_albedo(scene_pass->get_include_albedo())
+ include_albedo(scene_pass->get_include_albedo()),
+ lightgroup(scene_pass->get_lightgroup())
{
}
PassInfo BufferPass::get_info() const
{
- return Pass::get_info(type, include_albedo);
+ return Pass::get_info(type, include_albedo, !lightgroup.empty());
}
/* --------------------------------------------------------------------
diff --git a/intern/cycles/session/buffers.h b/intern/cycles/session/buffers.h
index 1c4ec81e427..a8278388a28 100644
--- a/intern/cycles/session/buffers.h
+++ b/intern/cycles/session/buffers.h
@@ -30,6 +30,7 @@ class BufferPass : public Node {
PassMode mode = PassMode::NOISY;
ustring name;
bool include_albedo = false;
+ ustring lightgroup;
int offset = -1;
@@ -49,7 +50,8 @@ class BufferPass : public Node {
inline bool operator==(const BufferPass &other) const
{
return type == other.type && mode == other.mode && name == other.name &&
- include_albedo == other.include_albedo && offset == other.offset;
+ include_albedo == other.include_albedo && lightgroup == other.lightgroup &&
+ offset == other.offset;
}
inline bool operator!=(const BufferPass &other) const
{