diff --git a/intern/cycles/blender/geometry.cpp b/intern/cycles/blender/geometry.cpp index 8426eb7d0a8..bff90432e9d 100644 --- a/intern/cycles/blender/geometry.cpp +++ b/intern/cycles/blender/geometry.cpp @@ -4,6 +4,7 @@ #include "scene/curves.h" #include "scene/hair.h" +#include "scene/light.h" #include "scene/mesh.h" #include "scene/object.h" #include "scene/pointcloud.h" @@ -18,6 +19,10 @@ CCL_NAMESPACE_BEGIN static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair) { + if (b_ob_info.object_data.is_a(&RNA_Light)) { + return Geometry::LIGHT; + } + if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) { return Geometry::HAIR; } @@ -38,12 +43,17 @@ static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_parti array BlenderSync::find_used_shaders(BL::Object &b_ob) { + array used_shaders; + + if (b_ob.type() == BL::Object::type_LIGHT) { + find_shader(b_ob.data(), used_shaders, scene->default_light); + return used_shaders; + } + BL::Material material_override = view_layer.material_override; Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume : scene->default_surface; - array used_shaders; - for (BL::MaterialSlot &b_slot : b_ob.material_slots) { if (material_override) { find_shader(material_override, used_shaders, default_shader); @@ -95,7 +105,10 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, bool sync = true; if (geom == nullptr) { /* Add new geometry if it did not exist yet. */ - if (geom_type == Geometry::HAIR) { + if (geom_type == Geometry::LIGHT) { + geom = scene->create_node(); + } + else if (geom_type == Geometry::HAIR) { geom = scene->create_node(); } else if (geom_type == Geometry::VOLUME) { @@ -115,6 +128,11 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, } if (!sync) { + /* Need to determine this every sync. */ + if (geom->is_light() && static_cast(geom)->get_is_portal()) { + world_use_portal = true; + } + /* If transform was applied to geometry, need full update. */ if (object_updated && geom->transform_applied) { ; @@ -156,7 +174,11 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name()); - if (geom_type == Geometry::HAIR) { + if (geom_type == Geometry::LIGHT) { + Light *light = static_cast(geom); + sync_light(b_depsgraph, b_ob_info, light); + } + else if (geom_type == Geometry::HAIR) { Hair *hair = static_cast(geom); sync_hair(b_depsgraph, b_ob_info, hair); } @@ -209,6 +231,11 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, return; } + /* Nothing to do for lights. */ + if (geom->is_light()) { + return; + } + /* If the geometry already has motion blur from a velocity attribute, don't * set the geometry motion steps again. * diff --git a/intern/cycles/blender/light.cpp b/intern/cycles/blender/light.cpp index 2ab51147af1..7fe863a35d9 100644 --- a/intern/cycles/blender/light.cpp +++ b/intern/cycles/blender/light.cpp @@ -4,42 +4,16 @@ #include "scene/light.h" -#include "blender/light_linking.h" #include "blender/sync.h" #include "blender/util.h" - -#include "util/hash.h" +#include "scene/object.h" CCL_NAMESPACE_BEGIN -void BlenderSync::sync_light(BL::Object &b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BObjectInfo &b_ob_info, - const int random_id, - Transform &tfm, - bool *use_portal) +void BlenderSync::sync_light(BL::Depsgraph /*b_depsgraph*/, BObjectInfo &b_ob_info, Light *light) { - /* test if we need to sync */ - const ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false); BL::Light b_light(b_ob_info.object_data); - Light *light = light_map.find(key); - - /* Check if the transform was modified, in case a linked collection is moved we do not get a - * specific depsgraph update (#88515). This also mimics the behavior for Objects. */ - const bool tfm_updated = (light && light->get_tfm() != tfm); - - /* Update if either object or light data changed. */ - if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) { - Shader *shader; - if (!shader_map.add_or_update(&shader, b_light)) { - if (light->get_is_portal()) { - *use_portal = true; - } - return; - } - } - light->name = b_light.name().c_str(); /* type */ @@ -104,14 +78,6 @@ void BlenderSync::sync_light(BL::Object &b_parent, const float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy(); light->set_strength(strength); - /* location and (inverted!) direction */ - light->set_tfm(tfm); - - /* shader */ - array used_shaders; - find_shader(b_light, used_shaders, scene->default_light); - light->set_shader(static_cast(used_shaders[0])); - /* shadow */ PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); light->set_cast_shadow(b_light.use_shadow()); @@ -122,13 +88,6 @@ void BlenderSync::sync_light(BL::Object &b_parent, light->set_max_bounces(get_int(clight, "max_bounces")); - if (b_ob_info.real_object != b_ob_info.iter_object) { - light->set_random_id(random_id); - } - else { - light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0)); - } - if (light->get_light_type() == LIGHT_AREA) { light->set_is_portal(get_boolean(clight, "is_portal")); } @@ -137,7 +96,7 @@ void BlenderSync::sync_light(BL::Object &b_parent, } if (light->get_is_portal()) { - *use_portal = true; + world_use_portal = true; } /* visibility */ @@ -149,22 +108,11 @@ 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()); - /* Light group and linking. */ - string lightgroup = b_ob_info.real_object.lightgroup(); - if (lightgroup.empty()) { - lightgroup = b_parent.lightgroup(); - } - light->set_lightgroup(ustring(lightgroup)); - light->set_light_set_membership( - BlenderLightLink::get_light_set_membership(PointerRNA_NULL, b_ob_info.real_object)); - light->set_shadow_set_membership( - BlenderLightLink::get_shadow_set_membership(PointerRNA_NULL, b_ob_info.real_object)); - /* tag */ light->tag_update(scene); } -void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) +void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d) { BL::World b_world = view_layer.world_override ? view_layer.world_override : b_scene.world(); @@ -176,14 +124,29 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC); const bool sample_as_light = (sampling_method != SAMPLING_NONE); - if (sample_as_light || use_portal) { - /* test if we need to sync */ - Light *light; - const ObjectKey key(b_world, nullptr, b_world, false); + if (sample_as_light || world_use_portal) { + /* Create object. */ + Object *object; + const ObjectKey object_key(b_world, nullptr, b_world, false); + bool update = object_map.add_or_update(&object, b_world, b_world, object_key); + + /* Create geometry. */ + const GeometryKey geom_key{b_world.ptr.data, Geometry::LIGHT}; + Geometry *geom = geometry_map.find(geom_key); + if (geom) { + update |= geometry_map.update(geom, b_world); + } + else { + geom = scene->create_node(); + geometry_map.add(geom_key, geom); + object->set_geometry(geom); + update = true; + } + + if (update || world_recalc || b_world.ptr.data != world_map) { + /* Initialize light geometry. */ + Light *light = static_cast(geom); - if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc || - b_world.ptr.data != world_map) - { light->set_light_type(LIGHT_BACKGROUND); if (sampling_method == SAMPLING_MANUAL) { light->set_map_resolution(get_int(cworld, "sample_map_resolution")); @@ -191,7 +154,9 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) else { light->set_map_resolution(0); } - light->set_shader(scene->default_background); + array used_shaders; + used_shaders.push_back_slow(scene->default_background); + light->set_used_shaders(used_shaders); light->set_use_mis(sample_as_light); light->set_max_bounces(get_int(cworld, "max_bounces")); @@ -202,7 +167,7 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) light->set_use_caustics(get_boolean(cworld, "is_caustics_light")); light->tag_update(scene); - light_map.set_recalc(b_world); + geometry_map.set_recalc(b_world); } } } diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index efa9cd0aea2..ed9ea98a16e 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -62,9 +62,9 @@ bool BlenderSync::object_is_geometry(BObjectInfo &b_ob_info) const BL::Object::type_enum type = b_ob_info.iter_object.type(); if (type == BL::Object::type_VOLUME || type == BL::Object::type_CURVES || - type == BL::Object::type_POINTCLOUD) + type == BL::Object::type_POINTCLOUD || type == BL::Object::type_LIGHT) { - /* Will be exported attached to mesh. */ + /* Will be exported as geometry. */ return true; } @@ -152,7 +152,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, bool use_particle_hair, bool show_lights, BlenderObjectCulling &culling, - bool *use_portal, TaskPool *geom_task_pool) { const bool is_instance = b_instance.is_instance(); @@ -173,36 +172,18 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, } } - /* light is handled separately */ - if (!motion && object_is_light(b_ob)) { - if (!show_lights) { - return nullptr; - } - - /* TODO: don't use lights for excluded layers used as mask layer, - * when dynamic overrides are back. */ -#if 0 - if (!((layer_flag & view_layer.holdout_layer) && (layer_flag & view_layer.exclude_layer))) -#endif - { - sync_light(b_parent, - persistent_id, - b_ob_info, - is_instance ? b_instance.random_id() : 0, - tfm, - use_portal); - } - - return nullptr; - } - /* only interested in object that we can create geometry from */ if (!object_is_geometry(b_ob_info)) { return nullptr; } /* Perform object culling. */ - if (culling.test(scene, b_ob, tfm)) { + if (object_is_light(b_ob)) { + if (!show_lights) { + return nullptr; + } + } + else if (culling.test(scene, b_ob, tfm)) { return nullptr; } @@ -544,7 +525,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, if (!motion) { /* prepare for sync */ - light_map.pre_sync(); geometry_map.pre_sync(); object_map.pre_sync(); procedural_map.pre_sync(); @@ -555,6 +535,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, geometry_motion_synced.clear(); } + world_use_portal = false; + if (!motion) { /* Object to geometry instance mapping is built for the reference time, as other * times just look up the corresponding geometry. */ @@ -566,7 +548,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, /* object loop */ bool cancel = false; - bool use_portal = false; const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights; BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); @@ -623,7 +604,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, false, show_lights, culling, - &use_portal, sync_hair ? nullptr : &geom_task_pool); } } @@ -637,7 +617,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, true, show_lights, culling, - &use_portal, &geom_task_pool); } @@ -649,12 +628,12 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, progress.set_sync_status(""); if (!cancel && !motion) { - sync_background_light(b_v3d, use_portal); + /* After object for world_use_portal. */ + sync_background_light(b_v3d); /* Handle removed data and modified pointers, as this may free memory, delete Nodes in the * right order to ensure that dependent data is freed after their users. Objects should be * freed before particle systems and geometries. */ - light_map.post_sync(); object_map.post_sync(); geometry_map.post_sync(); particle_system_map.post_sync(); diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 04c363a1a76..2d85dc19bf1 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -30,7 +30,9 @@ using ProxyMap = map; /* Find */ -void BlenderSync::find_shader(BL::ID &id, array &used_shaders, Shader *default_shader) +void BlenderSync::find_shader(const BL::ID &id, + array &used_shaders, + Shader *default_shader) { Shader *synced_shader = (id) ? shader_map.find(id) : nullptr; Shader *shader = (synced_shader) ? synced_shader : default_shader; diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index c3d7620d47d..43b05113bab 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -53,7 +53,6 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine, object_map(scene), procedural_map(scene), geometry_map(scene), - light_map(scene), particle_system_map(scene), world_map(nullptr), world_recalc(false), @@ -206,11 +205,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d else if (is_light) { if (b_update.is_updated_transform() || b_update.is_updated_shading()) { object_map.set_recalc(b_ob); - light_map.set_recalc(b_ob); + geometry_map.set_recalc(b_ob); } if (updated_geometry) { - light_map.set_recalc(b_ob); + geometry_map.set_recalc(b_ob); } } } diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index 2a3a5b9d666..2ba340fe414 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -144,7 +144,6 @@ class BlenderSync { bool use_particle_hair, bool show_lights, BlenderObjectCulling &culling, - bool *use_portal, TaskPool *geom_task_pool); void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object); @@ -206,13 +205,8 @@ class BlenderSync { TaskPool *task_pool); /* Light */ - void sync_light(BL::Object &b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BObjectInfo &b_ob_info, - const int random_id, - Transform &tfm, - bool *use_portal); - void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal); + void sync_light(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Light *light); + void sync_background_light(BL::SpaceView3D &b_v3d); /* Particles */ bool sync_dupli_particle(BL::Object &b_ob, @@ -223,7 +217,7 @@ class BlenderSync { void sync_images(); /* util */ - void find_shader(BL::ID &id, array &used_shaders, Shader *default_shader); + void find_shader(const BL::ID &id, array &used_shaders, Shader *default_shader); bool BKE_object_is_modified(BL::Object &b_ob); bool object_is_geometry(BObjectInfo &b_ob_info); bool object_can_have_geometry(BL::Object &b_ob); @@ -242,7 +236,6 @@ class BlenderSync { id_map object_map; id_map procedural_map; id_map geometry_map; - id_map light_map; id_map particle_system_map; set geometry_synced; set geometry_motion_synced; @@ -252,6 +245,7 @@ class BlenderSync { set motion_times; void *world_map; bool world_recalc; + bool world_use_portal = false; BlenderViewportParameters viewport_parameters; Scene *scene; diff --git a/intern/cycles/hydra/light.cpp b/intern/cycles/hydra/light.cpp index cb36d4b8f59..7b5dd0def84 100644 --- a/intern/cycles/hydra/light.cpp +++ b/intern/cycles/hydra/light.cpp @@ -6,11 +6,13 @@ #include "hydra/light.h" #include "hydra/session.h" #include "scene/light.h" +#include "scene/object.h" #include "scene/scene.h" #include "scene/shader.h" #include "scene/shader_graph.h" #include "scene/shader_nodes.h" #include "util/hash.h" +#include "util/transform.h" #include #include @@ -64,7 +66,7 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate, sceneDelegate->GetLightParamValue(id, HdTokens->transform) .Get()); #endif - _light->set_tfm(tfm); + _object->set_tfm(tfm); } if (*dirtyBits & DirtyBits::DirtyParams) { @@ -175,8 +177,8 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate, PopulateShaderGraph(sceneDelegate); } // Need to update shader graph when transform changes in case transform was baked into it - else if (_light->tfm_is_modified() && (_lightType == HdPrimTypeTokens->domeLight || - _light->get_shader()->has_surface_spatial_varying)) + else if (_object->tfm_is_modified() && (_lightType == HdPrimTypeTokens->domeLight || + _light->get_shader()->has_surface_spatial_varying)) { PopulateShaderGraph(sceneDelegate); } @@ -266,7 +268,7 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate) } TextureCoordinateNode *coordNode = graph->create_node(); - coordNode->set_ob_tfm(_light->get_tfm()); + coordNode->set_ob_tfm(_object->get_tfm()); coordNode->set_use_transform(true); IESLightNode *iesNode = graph->create_node(); @@ -287,7 +289,7 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate) ImageSlotTextureNode *textureNode = nullptr; if (_lightType == HdPrimTypeTokens->domeLight) { - Transform tfm = _light->get_tfm(); + Transform tfm = _object->get_tfm(); transform_set_column(&tfm, 3, zero_float3()); // Remove translation TextureCoordinateNode *coordNode = graph->create_node(); @@ -352,9 +354,11 @@ void HdCyclesLight::Finalize(HdRenderParam *renderParam) if (!keep_nodes) { lock.scene->delete_node(_light); + lock.scene->delete_node(_object); } _light = nullptr; + _object = nullptr; } void HdCyclesLight::Initialize(HdRenderParam *renderParam) @@ -365,10 +369,14 @@ void HdCyclesLight::Initialize(HdRenderParam *renderParam) const SceneLock lock(renderParam); + _object = lock.scene->create_node(); + _object->name = GetId().GetString(); + _light = lock.scene->create_node(); _light->name = GetId().GetString(); + _object->set_geometry(_light); - _light->set_random_id(hash_uint2(hash_string(_light->name.c_str()), 0)); + _object->set_random_id(hash_uint2(hash_string(_light->name.c_str()), 0)); if (_lightType == HdPrimTypeTokens->domeLight) { _light->set_light_type(LIGHT_BACKGROUND); @@ -395,7 +403,9 @@ void HdCyclesLight::Initialize(HdRenderParam *renderParam) _light->set_use_camera(false); Shader *const shader = lock.scene->create_node(); - _light->set_shader(shader); + array used_shaders; + used_shaders.push_back_slow(shader); + _light->set_used_shaders(used_shaders); // Create default shader graph PopulateShaderGraph(nullptr); diff --git a/intern/cycles/hydra/light.h b/intern/cycles/hydra/light.h index 381f1c45939..4ed50e7c5a5 100644 --- a/intern/cycles/hydra/light.h +++ b/intern/cycles/hydra/light.h @@ -29,6 +29,7 @@ class HdCyclesLight final : public PXR_NS::HdLight { void PopulateShaderGraph(PXR_NS::HdSceneDelegate *sceneDelegate); + CCL_NS::Object *_object = nullptr; CCL_NS::Light *_light = nullptr; PXR_NS::TfToken _lightType; }; diff --git a/intern/cycles/hydra/session.cpp b/intern/cycles/hydra/session.cpp index abe5368cb31..602ef2b63a7 100644 --- a/intern/cycles/hydra/session.cpp +++ b/intern/cycles/hydra/session.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "hydra/session.h" +#include "scene/object.h" #include "scene/shader.h" // Have to include shader.h before background.h so that 'set_shader' uses the correct 'set' // overload taking a 'Node *', rather than the one taking a 'bool' @@ -99,7 +100,15 @@ void HdCyclesSession::UpdateScene() // Update background depending on presence of a background light if (scene->light_manager->need_update()) { Light *background_light = nullptr; - for (Light *light : scene->lights) { + bool have_lights = false; + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + have_lights = true; + + Light *light = static_cast(object->get_geometry()); if (light->get_light_type() == LIGHT_BACKGROUND) { background_light = light; break; @@ -115,7 +124,7 @@ void HdCyclesSession::UpdateScene() for (ShaderNode *node : scene->default_background->graph->nodes) { if (node->is_a(BackgroundNode::get_node_type())) { BackgroundNode *bgNode = static_cast(node); - bgNode->set_color((scene->lights.empty()) ? make_float3(0.5f) : zero_float3()); + bgNode->set_color((have_lights) ? zero_float3() : make_float3(0.5f)); } } } diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index 6e41c91ebce..09b6c201e20 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -260,10 +260,6 @@ ccl_device_inline bool intersection_skip_self_local(const ccl_ray_data RaySelfPr ccl_device_inline uint64_t ray_get_shadow_set_membership(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self) { - if (self.light != LAMP_NONE) { - return kernel_data_fetch(lights, self.light).shadow_set_membership; - } - if (self.light_object != OBJECT_NONE) { return kernel_data_fetch(objects, self.light_object).shadow_set_membership; } diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h index 33a8c626b3d..44a932ed117 100644 --- a/intern/cycles/kernel/geom/curve.h +++ b/intern/cycles/kernel/geom/curve.h @@ -85,9 +85,8 @@ ccl_device T curve_attribute(KernelGlobals kg, } # endif - if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { - const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim : desc.offset; - return attribute_data_fetch(kg, offset); + if (desc.element == ATTR_ELEMENT_CURVE) { + return attribute_data_fetch(kg, desc.offset + sd->prim); } return make_zero(); } diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h index e93b8968d89..3d0fb72a4d8 100644 --- a/intern/cycles/kernel/geom/object.h +++ b/intern/cycles/kernel/geom/object.h @@ -40,16 +40,6 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals kg, return kernel_data_fetch(objects, object).tfm; } -/* Lamp to world space transformation */ - -ccl_device_inline Transform lamp_fetch_transform(KernelGlobals kg, const int lamp, bool inverse) -{ - if (inverse) { - return kernel_data_fetch(lights, lamp).itfm; - } - return kernel_data_fetch(lights, lamp).tfm; -} - /* Object to world space transformation for motion vectors */ ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg, @@ -131,6 +121,13 @@ ccl_device_inline Transform object_get_inverse_transform(KernelGlobals kg, return object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); #endif } + +ccl_device_inline Transform lamp_get_inverse_transform(KernelGlobals kg, + const ccl_global KernelLight *klight) +{ + return object_fetch_transform(kg, klight->object_id, OBJECT_INVERSE_TRANSFORM); +} + /* Transform position from object to world space */ ccl_device_inline void object_position_transform(KernelGlobals kg, @@ -173,7 +170,7 @@ ccl_device_inline void object_inverse_normal_transform(KernelGlobals kg, { #ifdef __OBJECT_MOTION__ if (sd->object_flag & SD_OBJECT_MOTION) { - if ((sd->object != OBJECT_NONE) || (sd->type == PRIMITIVE_LAMP)) { + if (sd->object != OBJECT_NONE) { *N = safe_normalize(transform_direction_transposed_auto(&sd->ob_tfm_motion, *N)); } return; @@ -184,10 +181,6 @@ ccl_device_inline void object_inverse_normal_transform(KernelGlobals kg, const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM); *N = safe_normalize(transform_direction_transposed(&tfm, *N)); } - else if (sd->type == PRIMITIVE_LAMP) { - const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false); - *N = safe_normalize(transform_direction_transposed(&tfm, *N)); - } } /* Transform normal from object to world space */ @@ -207,10 +200,6 @@ ccl_device_inline void object_normal_transform(KernelGlobals kg, const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); *N = normalize(transform_direction_transposed(&tfm, *N)); } - else if (sd->type == PRIMITIVE_LAMP) { - const Transform tfm = lamp_fetch_transform(kg, sd->lamp, true); - *N = normalize(transform_direction_transposed(&tfm, *N)); - } } ccl_device_inline bool object_negative_scale_applied(const int object_flag) @@ -304,17 +293,6 @@ ccl_device_inline float object_pass_id(KernelGlobals kg, const int object) return kernel_data_fetch(objects, object).pass_id; } -/* Light-group of lamp. */ - -ccl_device_inline int lamp_lightgroup(KernelGlobals kg, const int lamp) -{ - if (lamp == LAMP_NONE) { - return LIGHTGROUP_NONE; - } - - return kernel_data_fetch(lights, lamp).lightgroup; -} - /* Light-group of object. */ ccl_device_inline int object_lightgroup(KernelGlobals kg, const int object) @@ -326,17 +304,6 @@ ccl_device_inline int object_lightgroup(KernelGlobals kg, const int object) return kernel_data_fetch(objects, object).lightgroup; } -/* Per lamp random number for shader variation */ - -ccl_device_inline float lamp_random_number(KernelGlobals kg, const int lamp) -{ - if (lamp == LAMP_NONE) { - return 0.0f; - } - - return kernel_data_fetch(lights, lamp).random; -} - /* Per object random number for shader variation */ ccl_device_inline float object_random_number(KernelGlobals kg, const int object) diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h index 0aca36040ae..95656315bbb 100644 --- a/intern/cycles/kernel/geom/primitive.h +++ b/intern/cycles/kernel/geom/primitive.h @@ -36,6 +36,17 @@ ccl_device_forceinline T primitive_surface_attribute(KernelGlobals kg, ccl_private T *dfdx, ccl_private T *dfdy) { + if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { + if (dfdx) { + *dfdx = make_zero(); + } + if (dfdy) { + *dfdy = make_zero(); + } + + return attribute_data_fetch(kg, desc.offset); + } + if (sd->type & PRIMITIVE_TRIANGLE) { if (subd_triangle_patch(kg, sd->prim) == ~0) { return triangle_attribute(kg, sd, desc, dfdx, dfdy); diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h index d2f76c0b1c4..a8cdaf46f29 100644 --- a/intern/cycles/kernel/geom/shader_data.h +++ b/intern/cycles/kernel/geom/shader_data.h @@ -53,7 +53,6 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg, sd->object = isect->object; sd->object_flag = kernel_data_fetch(object_flag, sd->object); sd->prim = isect->prim; - sd->lamp = LAMP_NONE; sd->flag = 0; /* Read matrices and time. */ @@ -139,8 +138,8 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg, const float v, const float t, const float time, - bool object_space, - const int lamp) + const bool object_space, + const bool is_lamp) { /* vectors */ sd->P = P; @@ -148,7 +147,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg, sd->Ng = Ng; sd->wi = I; sd->shader = shader; - if (lamp != LAMP_NONE) { + if (is_lamp) { sd->type = PRIMITIVE_LAMP; } else if (prim != PRIM_NONE) { @@ -160,7 +159,6 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg, /* primitive */ sd->object = object; - sd->lamp = LAMP_NONE; /* Currently no access to bvh prim index for strand sd->prim. */ sd->prim = prim; sd->u = u; @@ -213,9 +211,6 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg, } } else { - if (lamp != LAMP_NONE) { - sd->lamp = lamp; - } #ifdef __DPDU__ sd->dPdu = zero_float3(); sd->dPdv = zero_float3(); @@ -278,7 +273,7 @@ ccl_device void shader_setup_from_displace(KernelGlobals kg, 0.0f, 0.5f, !(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED), - LAMP_NONE); + false); } /* ShaderData setup for point on curve. */ @@ -293,7 +288,6 @@ ccl_device void shader_setup_from_curve(KernelGlobals kg, { /* Primitive */ sd->type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE_THICK, segment); - sd->lamp = LAMP_NONE; sd->prim = prim; sd->u = u; sd->v = 0.0f; @@ -381,7 +375,6 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals kg, sd->ray_length = FLT_MAX; sd->object = OBJECT_NONE; - sd->lamp = LAMP_NONE; sd->prim = PRIM_NONE; sd->type = PRIMITIVE_NONE; sd->u = 0.0f; @@ -424,7 +417,6 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals kg, /* TODO: fill relevant fields for texture coordinates. */ sd->object = object; - sd->lamp = LAMP_NONE; sd->prim = PRIM_NONE; sd->type = PRIMITIVE_VOLUME; diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h index 46aae6bfc29..bf9fe4d5645 100644 --- a/intern/cycles/kernel/geom/subd_triangle.h +++ b/intern/cycles/kernel/geom/subd_triangle.h @@ -253,16 +253,6 @@ ccl_device_noinline T subd_triangle_attribute(KernelGlobals kg, return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a; } - if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) { - if (dfdx) { - *dfdx = make_zero(); - } - if (dfdy) { - *dfdy = make_zero(); - } - - return attribute_data_fetch(kg, desc.offset); - } if (dfdx) { *dfdx = make_zero(); diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h index 30fbf8d2008..5237b34dc69 100644 --- a/intern/cycles/kernel/geom/triangle.h +++ b/intern/cycles/kernel/geom/triangle.h @@ -275,9 +275,8 @@ ccl_device T triangle_attribute(KernelGlobals kg, } #endif - if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { - const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim : desc.offset; - return attribute_data_fetch(kg, offset); + if (desc.element == ATTR_ELEMENT_FACE) { + return attribute_data_fetch(kg, desc.offset + sd->prim); } return make_zero(); } diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h index ea432ea3bb8..d078dd655f6 100644 --- a/intern/cycles/kernel/integrator/intersect_closest.h +++ b/intern/cycles/kernel/integrator/intersect_closest.h @@ -374,7 +374,6 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg, ray.self.prim = last_isect_prim; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; bool hit = scene_intersect(kg, &ray, visibility, &isect); /* TODO: remove this and do it in the various intersection functions instead. */ diff --git a/intern/cycles/kernel/integrator/intersect_dedicated_light.h b/intern/cycles/kernel/integrator/intersect_dedicated_light.h index 606fbf70c4e..dd055e6a3bc 100644 --- a/intern/cycles/kernel/integrator/intersect_dedicated_light.h +++ b/intern/cycles/kernel/integrator/intersect_dedicated_light.h @@ -189,7 +189,6 @@ ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state ray.self.object = INTEGRATOR_STATE(state, isect, object); ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; Intersection isect ccl_optional_struct_init; if (!shadow_linking_pick_light_intersection(kg, state, &ray, &isect)) { diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h index d751ad7022f..d539a558b2e 100644 --- a/intern/cycles/kernel/integrator/intersect_volume_stack.h +++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h @@ -34,7 +34,6 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg, volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim); volume_ray.self.light_object = OBJECT_NONE; volume_ray.self.light_prim = PRIM_NONE; - volume_ray.self.light = LAMP_NONE; /* Store to avoid global fetches on every intersection step. */ const uint volume_stack_size = kernel_data.volume_stack_size; @@ -98,7 +97,6 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s volume_ray.self.prim = PRIM_NONE; volume_ray.self.light_object = OBJECT_NONE; volume_ray.self.light_prim = PRIM_NONE; - volume_ray.self.light = LAMP_NONE; int stack_index = 0; int enclosed_index = 0; diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index f58623d7da4..81ac77994e5 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -422,7 +422,6 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg, Ray projection_ray; projection_ray.self.light_object = OBJECT_NONE; projection_ray.self.light_prim = PRIM_NONE; - projection_ray.self.light = LAMP_NONE; projection_ray.dP = differential_make_compact(sd->dP); projection_ray.dD = differential_zero_compact(); projection_ray.tmin = 0.0f; @@ -866,7 +865,6 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg, Ray probe_ray; probe_ray.self.light_object = ls->object; probe_ray.self.light_prim = ls->prim; - probe_ray.self.light = ls->lamp; probe_ray.tmin = 0.0f; probe_ray.dP = differential_make_compact(sd->dP); probe_ray.dD = differential_zero_compact(); @@ -915,7 +913,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg, wi_len, sd->time, false, - LAMP_NONE); + false); /* Set bounce info in case a light path node is used in the refractive interface * shader graph. */ @@ -968,7 +966,6 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg, probe_ray.self.prim = sd->prim; probe_ray.self.light_object = ls->object; probe_ray.self.light_prim = ls->prim; - probe_ray.self.light = ls->lamp; probe_ray.P = sd->P; probe_ray.tmin = 0.0f; if (ls->t == FLT_MAX) { @@ -1100,7 +1097,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg, /* Distant or environment light. */ bool light_fixed_direction = (ls->t == FLT_MAX); if (ls->type == LIGHT_AREA) { - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim); if (klight->area.tan_half_spread == 0.0f) { /* Area light with zero spread also has fixed direction. */ light_fixed_direction = true; diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h index f2dcc22a35f..99dc0a7d384 100644 --- a/intern/cycles/kernel/integrator/shade_background.h +++ b/intern/cycles/kernel/integrator/shade_background.h @@ -138,15 +138,18 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, } #endif + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); #ifdef __LIGHT_LINKING__ - if (!light_link_light_match(kg, light_link_receiver_forward(kg, state), lamp) && + if (!light_link_light_match(kg, light_link_receiver_forward(kg, state), klight->object_id) && !(path_flag & PATH_RAY_CAMERA)) { continue; } #endif #ifdef __SHADOW_LINKING__ - if (kernel_data_fetch(lights, lamp).shadow_set_membership != LIGHT_LINK_MASK_ALL) { + if (kernel_data_fetch(objects, klight->object_id).shadow_set_membership != + LIGHT_LINK_MASK_ALL) + { continue; } #endif @@ -155,7 +158,6 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, if (INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_CULL_LIGHT_CONNECTION) { /* This path should have been resolved with mnee, it will * generate a firefly for small lights since it is improbable. */ - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); if (klight->use_caustics) { continue; } diff --git a/intern/cycles/kernel/integrator/shade_dedicated_light.h b/intern/cycles/kernel/integrator/shade_dedicated_light.h index fc678fb2ff1..05752a26aff 100644 --- a/intern/cycles/kernel/integrator/shade_dedicated_light.h +++ b/intern/cycles/kernel/integrator/shade_dedicated_light.h @@ -67,16 +67,8 @@ ccl_device void shadow_linking_setup_ray_from_intersection( ray->self.object = INTEGRATOR_STATE(state, shadow_link, last_isect_object); ray->self.prim = INTEGRATOR_STATE(state, shadow_link, last_isect_prim); - if (isect->type == PRIMITIVE_LAMP) { - ray->self.light_object = OBJECT_NONE; - ray->self.light_prim = PRIM_NONE; - ray->self.light = isect->prim; - } - else { - ray->self.light_object = isect->object; - ray->self.light_prim = isect->prim; - ray->self.light = LAMP_NONE; - } + ray->self.light_object = isect->object; + ray->self.light_prim = isect->prim; } ccl_device bool shadow_linking_shade_light(KernelGlobals kg, diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h index f4039785d72..ea3a4e755dd 100644 --- a/intern/cycles/kernel/integrator/shade_shadow.h +++ b/intern/cycles/kernel/integrator/shade_shadow.h @@ -83,7 +83,6 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg, ray.self.prim = PRIM_NONE; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; /* Modify ray position and length to match current segment. */ ray.tmin = (hit == 0) ? ray.tmin : INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t); ray.tmax = (hit < num_recorded_hits) ? INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) : diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index 3e3ca72c3c6..a8571deb353 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -23,6 +23,7 @@ #include "kernel/integrator/subsurface.h" #include "kernel/integrator/volume_stack.h" +#include "kernel/types.h" #include "util/math_intersect.h" CCL_NAMESPACE_BEGIN @@ -348,9 +349,9 @@ ccl_device #ifdef __MNEE__ IF_KERNEL_FEATURE(MNEE) { - if (ls.lamp != LAMP_NONE) { + if (ls.type != LIGHT_TRIANGLE) { /* Is this a caustic light? */ - const bool use_caustics = kernel_data_fetch(lights, ls.lamp).use_caustics; + const bool use_caustics = kernel_data_fetch(lights, ls.prim).use_caustics; if (use_caustics) { /* Are we on a caustic caster? */ if (is_transmission && (sd->object_flag & SD_OBJECT_CAUSTICS_CASTER)) { @@ -647,7 +648,6 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg, ray.self.prim = (skip_self) ? sd->prim : PRIM_NONE; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; ray.dP = differential_zero_compact(); ray.dD = differential_zero_compact(); diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 50aa60d5fcd..bbadaaab2b7 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -337,11 +337,11 @@ ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg, const ccl_private LightSample *ls) { if (ls->type == LIGHT_SPOT) { - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); - return spot_light_valid_ray_segment(klight, ray_P, ray_D, t_range); + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim); + return spot_light_valid_ray_segment(kg, klight, ray_P, ray_D, t_range); } if (ls->type == LIGHT_AREA) { - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim); return area_light_valid_ray_segment(&klight->area, ray_P - klight->co, ray_D, t_range); } if (ls->type == LIGHT_TRIANGLE) { diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h index 8bb577d0cfa..02770b97099 100644 --- a/intern/cycles/kernel/integrator/shadow_state_template.h +++ b/intern/cycles/kernel/integrator/shadow_state_template.h @@ -63,7 +63,6 @@ KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, float, tmin, KERNEL_FEATURE_PATH_TRACING KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, float, tmax, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING) -KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, int, self_light, KERNEL_FEATURE_SHADOW_LINKING) KERNEL_STRUCT_END(shadow_ray) /*********************** Shadow Intersection result **************************/ diff --git a/intern/cycles/kernel/integrator/state_util.h b/intern/cycles/kernel/integrator/state_util.h index 2a5c7c636d8..3d773021bdb 100644 --- a/intern/cycles/kernel/integrator/state_util.h +++ b/intern/cycles/kernel/integrator/state_util.h @@ -98,10 +98,6 @@ ccl_device_forceinline void integrator_state_read_shadow_ray(ConstIntegratorShad ccl_device_forceinline void integrator_state_write_shadow_ray_self( KernelGlobals kg, IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray) { - if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) { - INTEGRATOR_STATE_WRITE(state, shadow_ray, self_light) = ray->self.light; - } - /* Save memory by storing the light and object indices in the shadow_isect. */ /* TODO(sergey): This optimization does not work on GPU where multiple iterations of intersection * is needed if there are more than 4 transparent intersections. The indices starts to conflict @@ -115,10 +111,6 @@ ccl_device_forceinline void integrator_state_write_shadow_ray_self( ccl_device_forceinline void integrator_state_read_shadow_ray_self( KernelGlobals kg, ConstIntegratorShadowState state, ccl_private Ray *ccl_restrict ray) { - if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) { - ray->self.light = INTEGRATOR_STATE(state, shadow_ray, self_light); - } - ray->self.object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, object); ray->self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim); ray->self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object); diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h index a4388ed96f4..c5c0df70436 100644 --- a/intern/cycles/kernel/integrator/subsurface_disk.h +++ b/intern/cycles/kernel/integrator/subsurface_disk.h @@ -111,7 +111,6 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg, ray.self.prim = PRIM_NONE; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; /* Intersect with the same object. if multiple intersections are found it * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */ diff --git a/intern/cycles/kernel/integrator/subsurface_random_walk.h b/intern/cycles/kernel/integrator/subsurface_random_walk.h index 2d3db49dd87..3b6cd5c63e4 100644 --- a/intern/cycles/kernel/integrator/subsurface_random_walk.h +++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h @@ -199,7 +199,6 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg, ray.self.prim = prim; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; /* Convert subsurface to volume coefficients. * The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */ diff --git a/intern/cycles/kernel/integrator/volume_shader.h b/intern/cycles/kernel/integrator/volume_shader.h index f3762e04db8..e5df58abe65 100644 --- a/intern/cycles/kernel/integrator/volume_shader.h +++ b/intern/cycles/kernel/integrator/volume_shader.h @@ -439,7 +439,6 @@ ccl_device_inline bool volume_shader_eval_entry(KernelGlobals kg, /* Setup shader-data from stack. It's mostly setup already in shader_setup_from_volume, this * switching should be quick. */ sd->object = entry.object; - sd->lamp = LAMP_NONE; sd->shader = entry.shader; sd->flag &= ~SD_SHADER_FLAGS; diff --git a/intern/cycles/kernel/light/common.h b/intern/cycles/kernel/light/common.h index 84d6623852a..697b0a2afc8 100644 --- a/intern/cycles/kernel/light/common.h +++ b/intern/cycles/kernel/light/common.h @@ -22,9 +22,8 @@ struct LightSample { float pdf_selection; /* pdf for selecting light */ float eval_fac; /* intensity multiplier */ int object; /* object id for triangle/curve lights */ - int prim; /* primitive id for triangle/curve lights */ + int prim; /* lamp id for lights, primitive id for triangle/curve lights */ int shader; /* shader id */ - int lamp; /* lamp id */ int group; /* lightgroup */ LightType type; /* type of light */ int emitter_id; /* index in the emitter array */ diff --git a/intern/cycles/kernel/light/distant.h b/intern/cycles/kernel/light/distant.h index 61e08946b36..b553a59f0b7 100644 --- a/intern/cycles/kernel/light/distant.h +++ b/intern/cycles/kernel/light/distant.h @@ -12,7 +12,8 @@ CCL_NAMESPACE_BEGIN -ccl_device_inline void distant_light_uv(const ccl_global KernelLight *klight, +ccl_device_inline void distant_light_uv(KernelGlobals kg, + const ccl_global KernelLight *klight, const float3 D, ccl_private float *u, ccl_private float *v) @@ -24,7 +25,7 @@ ccl_device_inline void distant_light_uv(const ccl_global KernelLight *klight, const float fac = klight->distant.half_inv_sin_half_angle / len(D - klight->co); /* Get u axis and v axis. */ - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); const float u_ = dot(D, make_float3(itfm.x)) * fac; const float v_ = dot(D, make_float3(itfm.y)) * fac; @@ -33,7 +34,8 @@ ccl_device_inline void distant_light_uv(const ccl_global KernelLight *klight, *v = -u_ - v_; } -ccl_device_inline bool distant_light_sample(const ccl_global KernelLight *klight, +ccl_device_inline bool distant_light_sample(KernelGlobals kg, + const ccl_global KernelLight *klight, const float2 rand, ccl_private LightSample *ls) { @@ -47,7 +49,7 @@ ccl_device_inline bool distant_light_sample(const ccl_global KernelLight *klight ls->eval_fac = klight->distant.eval_fac; - distant_light_uv(klight, ls->D, &ls->u, &ls->v); + distant_light_uv(kg, klight, ls->D, &ls->u, &ls->v); return true; } @@ -114,19 +116,18 @@ ccl_device bool distant_light_sample_from_intersection(KernelGlobals kg, #ifndef __HIP__ ls->shader = klight->shader_id; #endif - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; + ls->object = klight->object_id; + ls->prim = lamp; ls->t = FLT_MAX; ls->P = -ray_D; ls->Ng = -ray_D; ls->D = ray_D; - ls->group = lamp_lightgroup(kg, lamp); + ls->group = object_lightgroup(kg, ls->object); ls->pdf = klight->distant.pdf; ls->eval_fac = klight->distant.eval_fac; - distant_light_uv(klight, ray_D, &ls->u, &ls->v); + distant_light_uv(kg, klight, ray_D, &ls->u, &ls->v); return true; } diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h index bc5653c7276..9045818498c 100644 --- a/intern/cycles/kernel/light/light.h +++ b/intern/cycles/kernel/light/light.h @@ -4,6 +4,7 @@ #pragma once +#include "kernel/geom/object.h" #include "kernel/globals.h" #include "kernel/integrator/state.h" @@ -57,14 +58,14 @@ ccl_device_inline int light_link_receiver_forward(KernelGlobals kg, IntegratorSt ccl_device_inline bool light_link_light_match(KernelGlobals kg, const int object_receiver, - const int light_emitter) + const int object_emitter) { #ifdef __LIGHT_LINKING__ if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) { return true; } - const uint64_t set_membership = kernel_data_fetch(lights, light_emitter).light_set_membership; + const uint64_t set_membership = kernel_data_fetch(objects, object_emitter).light_set_membership; const uint receiver_set = (object_receiver != OBJECT_NONE) ? kernel_data_fetch(objects, object_receiver).receiver_light_set : 0; @@ -122,12 +123,11 @@ ccl_device_inline bool light_sample(KernelGlobals kg, const LightType type = (LightType)klight->type; ls->type = type; ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; + ls->object = klight->object_id; + ls->prim = lamp; ls->u = rand.x; ls->v = rand.y; - ls->group = lamp_lightgroup(kg, lamp); + ls->group = object_lightgroup(kg, ls->object); if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) { /* Distant lights in a volume get a dummy sample, position will not actually @@ -143,7 +143,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg, } if (type == LIGHT_DISTANT) { - if (!distant_light_sample(klight, rand, ls)) { + if (!distant_light_sample(kg, klight, rand, ls)) { return false; } } @@ -158,12 +158,12 @@ ccl_device_inline bool light_sample(KernelGlobals kg, ls->eval_fac = 1.0f; } else if (type == LIGHT_SPOT) { - if (!spot_light_sample(klight, rand, P, N, shader_flags, ls)) { + if (!spot_light_sample(kg, klight, rand, P, N, shader_flags, ls)) { return false; } } else if (type == LIGHT_POINT) { - if (!point_light_sample(klight, rand, P, N, shader_flags, ls)) { + if (!point_light_sample(kg, klight, rand, P, N, shader_flags, ls)) { return false; } } @@ -196,14 +196,15 @@ ccl_device_noinline bool light_sample(KernelGlobals kg, const float2 rand = make_float2(rand_light); int prim; - MeshLight mesh_light; + int shader_flag; + int object_id; #ifdef __LIGHT_TREE__ if (kernel_data.integrator.use_light_tree) { const ccl_global KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters, ls->emitter_id); prim = kemitter->light.id; - mesh_light.shader_flag = kemitter->mesh_light.shader_flag; - mesh_light.object_id = ls->object; + shader_flag = kemitter->shader_flag; + object_id = (prim >= 0) ? ls->object : kemitter->object_id; } else #endif @@ -211,26 +212,25 @@ ccl_device_noinline bool light_sample(KernelGlobals kg, const ccl_global KernelLightDistribution *kdistribution = &kernel_data_fetch( light_distribution, ls->emitter_id); prim = kdistribution->prim; - mesh_light = kdistribution->mesh_light; + object_id = kdistribution->object_id; + shader_flag = 0; + } + + if (!light_link_object_match(kg, object_receiver, object_id)) { + return false; } if (prim >= 0) { /* Mesh light. */ - const int object = mesh_light.object_id; - - if (!light_link_object_match(kg, object_receiver, object)) { - return false; - } /* Exclude synthetic meshes from shadow catcher pass. */ if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) && - !(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) + !(kernel_data_fetch(object_flag, object_id) & SD_OBJECT_SHADOW_CATCHER)) { return false; } - const int shader_flag = mesh_light.shader_flag; - if (!triangle_light_sample(kg, prim, object, rand, time, ls, P)) { + if (!triangle_light_sample(kg, prim, object_id, rand, time, ls, P)) { return false; } ls->shader |= shader_flag; @@ -238,10 +238,6 @@ ccl_device_noinline bool light_sample(KernelGlobals kg, else { const int light = ~prim; - if (!light_link_light_match(kg, object_receiver, light)) { - return false; - } - if (UNLIKELY(light_select_reached_max_bounces(kg, light, bounce))) { return false; } @@ -278,6 +274,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) { const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); + const int object = klight->object_id; if (path_flag & PATH_RAY_CAMERA) { if (klight->shader_id & SHADER_EXCLUDE_CAMERA) { @@ -312,12 +309,12 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) { if (is_main_path) { if (is_indirect_ray && - kernel_data_fetch(lights, lamp).shadow_set_membership != LIGHT_LINK_MASK_ALL) + kernel_data_fetch(objects, object).shadow_set_membership != LIGHT_LINK_MASK_ALL) { continue; } } - else if (kernel_data_fetch(lights, lamp).shadow_set_membership == LIGHT_LINK_MASK_ALL) { + else if (kernel_data_fetch(objects, object).shadow_set_membership == LIGHT_LINK_MASK_ALL) { continue; } } @@ -325,7 +322,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, #ifdef __LIGHT_LINKING__ /* Light linking. */ - if (!light_link_light_match(kg, receiver_forward, lamp) && !(path_flag & PATH_RAY_CAMERA)) { + if (!light_link_light_match(kg, receiver_forward, object) && !(path_flag & PATH_RAY_CAMERA)) { continue; } #endif @@ -363,7 +360,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, } /* Avoid self-intersections. */ - if (last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP) { + if (last_prim == lamp && last_object == object && last_type == PRIMITIVE_LAMP) { continue; } @@ -391,7 +388,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, isect->v = v; isect->type = PRIMITIVE_LAMP; isect->prim = lamp; - isect->object = OBJECT_NONE; + isect->object = object; } return num_hits; @@ -465,26 +462,24 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg, const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls) { - const int lamp = isect->prim; - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, isect->prim); const LightType type = (LightType)klight->type; ls->type = type; ls->shader = klight->shader_id; ls->object = isect->object; ls->prim = isect->prim; - ls->lamp = lamp; ls->t = isect->t; ls->P = ray_P + ray_D * ls->t; ls->D = ray_D; - ls->group = lamp_lightgroup(kg, lamp); + ls->group = object_lightgroup(kg, ls->object); if (type == LIGHT_SPOT) { - if (!spot_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) { + if (!spot_light_sample_from_intersection(kg, klight, ray_P, ray_D, N, path_flag, ls)) { return false; } } else if (type == LIGHT_POINT) { - if (!point_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) { + if (!point_light_sample_from_intersection(kg, klight, ray_P, ray_D, N, path_flag, ls)) { return false; } } diff --git a/intern/cycles/kernel/light/point.h b/intern/cycles/kernel/light/point.h index 1f9a80f447c..8346351a920 100644 --- a/intern/cycles/kernel/light/point.h +++ b/intern/cycles/kernel/light/point.h @@ -4,13 +4,16 @@ #pragma once +#include "kernel/globals.h" + #include "kernel/light/common.h" #include "util/math_intersect.h" CCL_NAMESPACE_BEGIN -ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight, +ccl_device_inline bool point_light_sample(KernelGlobals kg, + const ccl_global KernelLight *klight, const float2 rand, const float3 P, const float3 N, @@ -72,7 +75,7 @@ ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight, } /* Texture coordinates. */ - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ ls->u = uv.y; @@ -92,7 +95,8 @@ ccl_device_forceinline float sphere_light_pdf( return has_transmission ? M_1_2PI_F * 0.5f : pdf_cos_hemisphere(N, D); } -ccl_device_forceinline void point_light_mnee_sample_update(const ccl_global KernelLight *klight, +ccl_device_forceinline void point_light_mnee_sample_update(KernelGlobals kg, + const ccl_global KernelLight *klight, ccl_private LightSample *ls, const float3 P, const float3 N, @@ -122,7 +126,7 @@ ccl_device_forceinline void point_light_mnee_sample_update(const ccl_global Kern } /* Texture coordinates. */ - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ ls->u = uv.y; @@ -149,7 +153,8 @@ ccl_device_inline bool point_light_intersect(const ccl_global KernelLight *kligh ray->P, ray->D, ray->tmin, ray->tmax, klight->co, diskN, radius, &P, t); } -ccl_device_inline bool point_light_sample_from_intersection(const ccl_global KernelLight *klight, +ccl_device_inline bool point_light_sample_from_intersection(KernelGlobals kg, + const ccl_global KernelLight *klight, const float3 ray_P, const float3 ray_D, const float3 N, @@ -179,7 +184,7 @@ ccl_device_inline bool point_light_sample_from_intersection(const ccl_global Ker } /* Texture coordinates. */ - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng)); /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */ ls->u = uv.y; diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index fe55b60bea2..7e2434b72dd 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -8,6 +8,7 @@ #include "kernel/light/distribution.h" #include "kernel/light/light.h" +#include "kernel/types.h" #ifdef __LIGHT_TREE__ # include "kernel/light/tree.h" @@ -56,7 +57,7 @@ light_sample_shader_eval(KernelGlobals kg, ls->t, time, false, - ls->lamp); + ls->type != LIGHT_TRIANGLE); ls->Ng = emission_sd->Ng; } @@ -80,8 +81,8 @@ light_sample_shader_eval(KernelGlobals kg, eval *= ls->eval_fac; - if (ls->lamp != LAMP_NONE) { - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); + if (ls->type != LIGHT_TRIANGLE) { + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim); eval *= rgb_to_spectrum( make_float3(klight->strength[0], klight->strength[1], klight->strength[2])); } @@ -251,7 +252,6 @@ ccl_device_inline void shadow_ray_setup(const ccl_private ShaderData *ccl_restri ray->self.prim = (skip_self) ? sd->prim : PRIM_NONE; ray->self.light_object = ls->object; ray->self.light_prim = ls->prim; - ray->self.light = ls->lamp; } /* Create shadow ray towards light sample. */ @@ -392,13 +392,13 @@ ccl_device_forceinline void light_sample_update(KernelGlobals kg, const float3 N, const uint32_t path_flag) { - const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp); + const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim); if (ls->type == LIGHT_POINT) { - point_light_mnee_sample_update(klight, ls, P, N, path_flag); + point_light_mnee_sample_update(kg, klight, ls, P, N, path_flag); } else if (ls->type == LIGHT_SPOT) { - spot_light_mnee_sample_update(klight, ls, P, N, path_flag); + spot_light_mnee_sample_update(kg, klight, ls, P, N, path_flag); } else if (ls->type == LIGHT_AREA) { area_light_mnee_sample_update(klight, ls, P); @@ -487,7 +487,7 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg, dt, path_flag, 0, - kernel_data_fetch(light_to_tree, ls->lamp), + kernel_data_fetch(light_to_tree, ls->prim), light_link_receiver_forward(kg, state)); } else diff --git a/intern/cycles/kernel/light/spot.h b/intern/cycles/kernel/light/spot.h index 5c3340eba0e..9fb4f1498df 100644 --- a/intern/cycles/kernel/light/spot.h +++ b/intern/cycles/kernel/light/spot.h @@ -13,9 +13,11 @@ CCL_NAMESPACE_BEGIN /* Transform vector to spot light's local coordinate system. */ -ccl_device float3 spot_light_to_local(const ccl_global KernelLight *klight, const float3 ray) +ccl_device float3 spot_light_to_local(KernelGlobals kg, + const ccl_global KernelLight *klight, + const float3 ray) { - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); float3 transformed_ray = safe_normalize(transform_direction(&itfm, ray)); transformed_ray.z = -transformed_ray.z; @@ -42,7 +44,8 @@ ccl_device void spot_light_uv(const float3 ray, } template -ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight, +ccl_device_inline bool spot_light_sample(KernelGlobals kg, + const ccl_global KernelLight *klight, const float2 rand, const float3 P, const float3 N, @@ -98,7 +101,7 @@ ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight, } /* Attenuation. */ - const float3 local_ray = spot_light_to_local(klight, -ls->D); + const float3 local_ray = spot_light_to_local(kg, klight, -ls->D); if (d_sq > r_sq) { ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray); } @@ -134,7 +137,7 @@ ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight, ls->Ng = -ls->D; /* Attenuation. */ - const float3 local_ray = spot_light_to_local(klight, -ls->D); + const float3 local_ray = spot_light_to_local(kg, klight, -ls->D); ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray); if (!in_volume_segment && ls->eval_fac == 0.0f) { return false; @@ -167,7 +170,8 @@ ccl_device_forceinline float spot_light_pdf(const ccl_global KernelSpotLight *sp return has_transmission ? M_1_2PI_F * 0.5f : pdf_cos_hemisphere(N, D); } -ccl_device_forceinline void spot_light_mnee_sample_update(const ccl_global KernelLight *klight, +ccl_device_forceinline void spot_light_mnee_sample_update(KernelGlobals kg, + const ccl_global KernelLight *klight, ccl_private LightSample *ls, const float3 P, const float3 N, @@ -203,7 +207,7 @@ ccl_device_forceinline void spot_light_mnee_sample_update(const ccl_global Kerne } /* Attenuation. */ - const float3 local_ray = spot_light_to_local(klight, -ls->D); + const float3 local_ray = spot_light_to_local(kg, klight, -ls->D); if (use_attenuation) { ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray); } @@ -224,7 +228,8 @@ ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight return point_light_intersect(klight, ray, t); } -ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global KernelLight *klight, +ccl_device_inline bool spot_light_sample_from_intersection(KernelGlobals kg, + const ccl_global KernelLight *klight, const float3 ray_P, const float3 ray_D, const float3 N, @@ -254,7 +259,7 @@ ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global Kern } /* Attenuation. */ - const float3 local_ray = spot_light_to_local(klight, -ray_D); + const float3 local_ray = spot_light_to_local(kg, klight, -ray_D); if (!klight->spot.is_sphere || d_sq > r_sq) { ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray); } @@ -269,13 +274,14 @@ ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global Kern } /* Find the ray segment lit by the spot light. */ -ccl_device_inline bool spot_light_valid_ray_segment(const ccl_global KernelLight *klight, +ccl_device_inline bool spot_light_valid_ray_segment(KernelGlobals kg, + const ccl_global KernelLight *klight, const float3 P, const float3 D, ccl_private Interval *t_range) { /* Convert to local space of the spot light. */ - const Transform itfm = klight->itfm; + const Transform itfm = lamp_get_inverse_transform(kg, klight); float3 local_P = P + klight->spot.dir * klight->spot.ray_segment_dp; local_P = transform_point(&itfm, local_P); const float3 local_D = transform_direction(&itfm, D); diff --git a/intern/cycles/kernel/light/tree.h b/intern/cycles/kernel/light/tree.h index 54b2113d77f..98b76033edf 100644 --- a/intern/cycles/kernel/light/tree.h +++ b/intern/cycles/kernel/light/tree.h @@ -73,12 +73,12 @@ ccl_device_inline bool is_light(const ccl_global KernelLightTreeEmitter *kemitte ccl_device_inline bool is_mesh(const ccl_global KernelLightTreeEmitter *kemitter) { - return !is_light(kemitter) && kemitter->mesh_light.object_id == OBJECT_NONE; + return !is_light(kemitter) && kemitter->object_id == OBJECT_NONE; } ccl_device_inline bool is_triangle(const ccl_global KernelLightTreeEmitter *kemitter) { - return !is_light(kemitter) && kemitter->mesh_light.object_id != OBJECT_NONE; + return !is_light(kemitter) && kemitter->object_id != OBJECT_NONE; } ccl_device_inline bool is_leaf(const ccl_global KernelLightTreeNode *knode) @@ -274,7 +274,7 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg, } else { kernel_assert(is_triangle(kemitter)); - const int object = kemitter->mesh_light.object_id; + const int object = kemitter->object_id; float3 vertices[3]; triangle_vertices(kg, kemitter->triangle.id, vertices); centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f; diff --git a/intern/cycles/kernel/light/triangle.h b/intern/cycles/kernel/light/triangle.h index f690882bd24..6621a5267c0 100644 --- a/intern/cycles/kernel/light/triangle.h +++ b/intern/cycles/kernel/light/triangle.h @@ -168,7 +168,6 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg, ls->eval_fac = 1.0f; ls->object = object; ls->prim = prim; - ls->lamp = LAMP_NONE; ls->shader |= SHADER_USE_MIS; ls->type = LIGHT_TRIANGLE; ls->group = object_lightgroup(kg, object); diff --git a/intern/cycles/kernel/osl/closures.cpp b/intern/cycles/kernel/osl/closures.cpp index e01effe1f91..4f542151224 100644 --- a/intern/cycles/kernel/osl/closures.cpp +++ b/intern/cycles/kernel/osl/closures.cpp @@ -104,7 +104,7 @@ void osl_eval_nodes(const ThreadKernelGlobalsCPU *kg, OSL::ShadingContext *octx = kg->osl.context; const int shader = sd->shader & SHADER_MASK; - if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) { + if (sd->object == OBJECT_NONE) { /* background */ if (kg->osl.globals->background_state) { ss->execute(*octx, diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp index 468caaf3034..766c1cad44a 100644 --- a/intern/cycles/kernel/osl/services.cpp +++ b/intern/cycles/kernel/osl/services.cpp @@ -75,7 +75,6 @@ ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated"); ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv"); ustring OSLRenderServices::u_material_index("material:index"); ustring OSLRenderServices::u_object_random("object:random"); -ustring OSLRenderServices::u_light_random("light:random"); ustring OSLRenderServices::u_particle_index("particle:index"); ustring OSLRenderServices::u_particle_random("particle:random"); ustring OSLRenderServices::u_particle_age("particle:age"); @@ -177,12 +176,6 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, return true; } - if (sd->type == PRIMITIVE_LAMP) { - const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false); - copy_matrix(result, tfm); - - return true; - } return false; } @@ -221,12 +214,6 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, return true; } - if (sd->type == PRIMITIVE_LAMP) { - const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true); - copy_matrix(result, itfm); - - return true; - } return false; } @@ -317,12 +304,6 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, return true; } - if (sd->type == PRIMITIVE_LAMP) { - const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false); - copy_matrix(result, tfm); - - return true; - } return false; } @@ -349,12 +330,6 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, return true; } - if (sd->type == PRIMITIVE_LAMP) { - const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true); - copy_matrix(result, itfm); - - return true; - } return false; } @@ -754,10 +729,6 @@ bool OSLRenderServices::get_object_standard_attribute( const float f = object_random_number(kg, sd->object); return set_attribute(f, type, derivatives, val); } - if (name == u_light_random) { - const float f = lamp_random_number(kg, sd->lamp); - return set_attribute(f, type, derivatives, val); - } /* Particle Attributes */ if (name == u_particle_index) { @@ -1571,7 +1542,6 @@ bool OSLRenderServices::trace(TraceOpt &options, ray.self.prim = PRIM_NONE; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; if (options.mindist == 0.0f) { /* avoid self-intersections */ diff --git a/intern/cycles/kernel/osl/services.h b/intern/cycles/kernel/osl/services.h index acbdcea2c8f..621be16713c 100644 --- a/intern/cycles/kernel/osl/services.h +++ b/intern/cycles/kernel/osl/services.h @@ -275,7 +275,6 @@ class OSLRenderServices : public OSL::RendererServices { static ustring u_geom_dupli_uv; static ustring u_material_index; static ustring u_object_random; - static ustring u_light_random; static ustring u_particle_index; static ustring u_particle_random; static ustring u_particle_age; diff --git a/intern/cycles/kernel/osl/services_gpu.h b/intern/cycles/kernel/osl/services_gpu.h index 1698f66f6bc..8237aeae993 100644 --- a/intern/cycles/kernel/osl/services_gpu.h +++ b/intern/cycles/kernel/osl/services_gpu.h @@ -80,8 +80,6 @@ ccl_device_constant DeviceString u_geom_dupli_uv = 1294253317490155849ull; ccl_device_constant DeviceString u_material_index = 741770758159634623ull; /* "object:random" */ ccl_device_constant DeviceString u_object_random = 15789063994977955884ull; -/* "light:random" */ -ccl_device_constant DeviceString u_light_random = 1743557801140685447ull; /* "particle:index" */ ccl_device_constant DeviceString u_particle_index = 9489711748229903784ull; /* "particle:random" */ @@ -628,11 +626,6 @@ ccl_device_extern bool osl_get_matrix(ccl_private ShaderGlobals *sg, copy_matrix(res, tfm); return true; } - else if (sd->type == PRIMITIVE_LAMP) { - const Transform tfm = lamp_fetch_transform(kg, sd->lamp, false); - copy_matrix(res, tfm); - return true; - } } else if (from == DeviceStrings::u_ndc) { copy_matrix(res, kernel_data.cam.ndctoworld); @@ -672,11 +665,6 @@ ccl_device_extern bool osl_get_inverse_matrix(ccl_private ShaderGlobals *sg, copy_matrix(res, itfm); return true; } - else if (sd->type == PRIMITIVE_LAMP) { - const Transform itfm = lamp_fetch_transform(kg, sd->lamp, true); - copy_matrix(res, itfm); - return true; - } } else if (to == DeviceStrings::u_ndc) { copy_matrix(res, kernel_data.cam.worldtondc); @@ -1245,11 +1233,6 @@ ccl_device_inline bool get_object_standard_attribute(KernelGlobals kg, return set_attribute(f, type, derivatives, val); } - else if (name == DeviceStrings::u_light_random) { - const float f = lamp_random_number(kg, sd->lamp); - - return set_attribute(f, type, derivatives, val); - } /* Particle attributes */ else if (name == DeviceStrings::u_particle_index) { diff --git a/intern/cycles/kernel/osl/shaders/node_object_info.osl b/intern/cycles/kernel/osl/shaders/node_object_info.osl index 916b491e714..72e31c50f80 100644 --- a/intern/cycles/kernel/osl/shaders/node_object_info.osl +++ b/intern/cycles/kernel/osl/shaders/node_object_info.osl @@ -16,13 +16,5 @@ shader node_object_info(output point Location = point(0.0, 0.0, 0.0), getattribute("object:alpha", Alpha); getattribute("object:index", ObjectIndex); getattribute("material:index", MaterialIndex); - - float is_light; - getattribute("object:is_light", is_light); - if (is_light) { - getattribute("light:random", Random); - } - else { - getattribute("object:random", Random); - } + getattribute("object:random", Random); } diff --git a/intern/cycles/kernel/svm/ao.h b/intern/cycles/kernel/svm/ao.h index 483ccb75916..eb45e0f3702 100644 --- a/intern/cycles/kernel/svm/ao.h +++ b/intern/cycles/kernel/svm/ao.h @@ -76,7 +76,6 @@ ccl_device float svm_ao( ray.self.prim = sd->prim; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; ray.dP = differential_zero_compact(); ray.dD = differential_zero_compact(); diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h index f82937cfa3a..3cc4fef4049 100644 --- a/intern/cycles/kernel/svm/bevel.h +++ b/intern/cycles/kernel/svm/bevel.h @@ -201,7 +201,6 @@ ccl_device float3 svm_bevel( ray.self.prim = PRIM_NONE; ray.self.light_object = OBJECT_NONE; ray.self.light_prim = PRIM_NONE; - ray.self.light = LAMP_NONE; /* Intersect with the same object. if multiple intersections are found it * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */ diff --git a/intern/cycles/kernel/svm/geometry.h b/intern/cycles/kernel/svm/geometry.h index 7e54279c56e..12a9f989793 100644 --- a/intern/cycles/kernel/svm/geometry.h +++ b/intern/cycles/kernel/svm/geometry.h @@ -141,12 +141,7 @@ ccl_device_noinline void svm_node_object_info(KernelGlobals kg, data = shader_pass_id(kg, sd); break; case NODE_INFO_OB_RANDOM: { - if (sd->lamp != LAMP_NONE) { - data = lamp_random_number(kg, sd->lamp); - } - else { - data = object_random_number(kg, sd->object); - } + data = object_random_number(kg, sd->object); break; } default: diff --git a/intern/cycles/kernel/svm/vector_transform.h b/intern/cycles/kernel/svm/vector_transform.h index ec8039a51c2..ba4b7100308 100644 --- a/intern/cycles/kernel/svm/vector_transform.h +++ b/intern/cycles/kernel/svm/vector_transform.h @@ -32,7 +32,7 @@ ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg, const NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito; Transform tfm; - const bool is_object = (sd->object != OBJECT_NONE) || (sd->type == PRIMITIVE_LAMP); + const bool is_object = (sd->object != OBJECT_NONE); const bool is_normal = (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL); const bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR); diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index fb1de5507a7..4eb4f497b65 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -724,7 +724,6 @@ struct RaySelfPrimitives { int object; /* Instance prim is a part of */ int light_prim; /* Light primitive */ int light_object; /* Light object */ - int light; /* Light ID (the light the shadow ray is traced towards to) */ }; struct Ray { @@ -1151,8 +1150,6 @@ struct ccl_align(16) ShaderData float v; /* object id if there is one, ~0 otherwise */ int object; - /* lamp id if there is one, ~0 otherwise */ - int lamp; /* motion blur sample time */ float time; @@ -1606,32 +1603,24 @@ struct KernelLight { int type; packed_float3 co; int shader_id; + int object_id; float max_bounces; - float random; float strength[3]; int use_caustics; - int lightgroup; - Transform tfm; - Transform itfm; + int pad; union { KernelSpotLight spot; KernelAreaLight area; KernelDistantLight distant; }; - uint64_t light_set_membership; - uint64_t shadow_set_membership; }; static_assert_align(KernelLight, 16); -struct MeshLight { - int shader_flag; - int object_id; -}; - struct KernelLightDistribution { float totarea; int prim; - MeshLight mesh_light; + int shader_flag; + int object_id; }; static_assert_align(KernelLightDistribution, 16); @@ -1718,7 +1707,9 @@ struct KernelLightTreeEmitter { } mesh; }; - MeshLight mesh_light; + /* Object and shader. */ + int object_id; + int shader_flag; /* Bit trail from root node to leaf node containing emitter. */ int bit_trail; diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 6c9598bbb8f..6f09c7374ea 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -75,6 +75,7 @@ class Geometry : public Node { HAIR, VOLUME, POINTCLOUD, + LIGHT, }; Type geometry_type; @@ -185,6 +186,11 @@ class Geometry : public Node { return geometry_type == VOLUME; } + bool is_light() const + { + return geometry_type == LIGHT; + } + /* Updates */ void tag_update(Scene *scene, bool rebuild); }; diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index 899ec6466d2..49ff6aa7d53 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -84,7 +84,7 @@ static void shade_background_pixels(Device *device, NODE_DEFINE(Light) { - NodeType *type = NodeType::add("light", create); + NodeType *type = NodeType::add("light", create, NodeType::NONE, Geometry::get_node_base_type()); static NodeEnum type_enum; type_enum.insert("point", LIGHT_POINT); @@ -112,8 +112,6 @@ NODE_DEFINE(Light) SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F); SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f); - SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true); SOCKET_BOOLEAN(use_mis, "Use Mis", false); SOCKET_BOOLEAN(use_camera, "Use Camera", true); @@ -124,24 +122,17 @@ NODE_DEFINE(Light) SOCKET_BOOLEAN(use_caustics, "Shadow Caustics", false); SOCKET_INT(max_bounces, "Max Bounces", 1024); - SOCKET_UINT(random_id, "Random ID", 0); SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", true); SOCKET_BOOLEAN(is_portal, "Is Portal", false); SOCKET_BOOLEAN(is_enabled, "Is Enabled", true); - SOCKET_NODE(shader, "Shader", Shader::get_node_type()); - - SOCKET_STRING(lightgroup, "Light Group", ustring()); - SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL); - SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL); - SOCKET_BOOLEAN(normalize, "Normalize", true); return type; } -Light::Light() : Node(get_node_type()) +Light::Light() : Geometry(get_node_type(), Geometry::LIGHT) { dereference_all_used_nodes(); } @@ -165,46 +156,33 @@ bool Light::has_contribution(Scene *scene) return true; } - const Shader *effective_shader = (shader) ? shader : scene->default_light; + const Shader *effective_shader = (get_shader()) ? get_shader() : scene->default_light; return !is_zero(effective_shader->emission_estimate); } -bool Light::has_light_linking() const +Shader *Light::get_shader() const { - if (get_light_set_membership() != LIGHT_LINK_MASK_ALL) { - return true; - } - - return false; + return (used_shaders.empty()) ? nullptr : static_cast(used_shaders[0]); } -bool Light::has_shadow_linking() const +void Light::compute_bounds() { - if (get_shadow_set_membership() != LIGHT_LINK_MASK_ALL) { - return true; - } - - return false; + /* To be implemented when this becomes actual geometry. */ } -float3 Light::get_co() const +void Light::apply_transform(const Transform & /*tfm*/, const bool /*apply_to_motion*/) { - return transform_get_column(&tfm, 3); + /* To be implemented when this becomes actual geometry. */ } -float3 Light::get_dir() const +void Light::get_uv_tiles(ustring /*map*/, unordered_set & /*tiles*/) { - return -transform_get_column(&tfm, 2); + /* To be implemented when this becomes actual geometry. */ } -float3 Light::get_axisu() const +PrimitiveType Light::primitive_type() const { - return transform_get_column(&tfm, 0); -} - -float3 Light::get_axisv() const -{ - return transform_get_column(&tfm, 1); + return PRIMITIVE_LAMP; } /* Light Manager */ @@ -219,7 +197,12 @@ LightManager::LightManager() bool LightManager::has_background_light(Scene *scene) { - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) { return true; } @@ -233,18 +216,31 @@ void LightManager::test_enabled_lights(Scene *scene) * needed for finer-tuning of settings (for example, check whether we've * got portals or not). */ + vector background_lights; + size_t num_lights = 0; bool has_portal = false; - bool has_background = false; - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); light->is_enabled = light->has_contribution(scene); has_portal |= light->is_portal; - has_background |= light->light_type == LIGHT_BACKGROUND; + + if (light->light_type == LIGHT_BACKGROUND) { + background_lights.push_back(light); + } + + num_lights++; } + VLOG_INFO << "Total " << num_lights << " lights."; + bool background_enabled = false; int background_resolution = 0; - if (has_background) { + if (!background_lights.empty()) { /* Ignore background light if: * - If unsupported on a device * - If we don't need it (no HDRs etc.) @@ -254,12 +250,10 @@ void LightManager::test_enabled_lights(Scene *scene) if (disable_mis) { VLOG_INFO << "Background MIS has been disabled.\n"; } - for (Light *light : scene->lights) { - if (light->light_type == LIGHT_BACKGROUND) { - light->is_enabled = !disable_mis; - background_enabled = !disable_mis; - background_resolution = light->map_resolution; - } + for (Light *light : background_lights) { + light->is_enabled = !disable_mis; + background_enabled = !disable_mis; + background_resolution = light->map_resolution; } } @@ -335,7 +329,6 @@ void LightManager::device_update_distribution(Device * /*unused*/, /* Triangles. */ size_t offset = 0; - int j = 0; for (Object *object : scene->objects) { if (progress.get_cancel()) { @@ -343,14 +336,12 @@ void LightManager::device_update_distribution(Device * /*unused*/, } if (!object->usable_as_light()) { - j++; continue; } /* Sum area. */ Mesh *mesh = static_cast(object->get_geometry()); const bool transform_applied = mesh->transform_applied; const Transform tfm = object->get_tfm(); - const int object_id = j; int shader_flag = 0; if (!(object->get_visibility() & PATH_RAY_CAMERA)) { @@ -382,8 +373,8 @@ void LightManager::device_update_distribution(Device * /*unused*/, if (shader->emission_sampling != EMISSION_SAMPLING_NONE) { distribution[offset].totarea = totarea; distribution[offset].prim = i + mesh->prim_offset; - distribution[offset].mesh_light.shader_flag = shader_flag; - distribution[offset].mesh_light.object_id = object_id; + distribution[offset].shader_flag = shader_flag; + distribution[offset].object_id = object->index; offset++; const Mesh::Triangle t = mesh->get_triangle(i); @@ -403,8 +394,6 @@ void LightManager::device_update_distribution(Device * /*unused*/, totarea += triangle_area(p1, p2, p3); } } - - j++; } const float trianglearea = totarea; @@ -414,15 +403,20 @@ void LightManager::device_update_distribution(Device * /*unused*/, if (num_lights > 0) { const float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f; - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); if (!light->is_enabled) { continue; } distribution[offset].totarea = totarea; distribution[offset].prim = ~light_index; - distribution[offset].mesh_light.object_id = OBJECT_NONE; - distribution[offset].mesh_light.shader_flag = 0; + distribution[offset].object_id = object->index; + distribution[offset].shader_flag = 0; totarea += lightarea; light_index++; @@ -433,8 +427,8 @@ void LightManager::device_update_distribution(Device * /*unused*/, /* normalize cumulative distribution functions */ distribution[num_distribution].totarea = totarea; distribution[num_distribution].prim = 0; - distribution[num_distribution].mesh_light.object_id = OBJECT_NONE; - distribution[num_distribution].mesh_light.shader_flag = 0; + distribution[num_distribution].object_id = OBJECT_NONE; + distribution[num_distribution].shader_flag = 0; if (totarea > 0.0f) { for (size_t i = 0; i < num_distribution; i++) { @@ -566,8 +560,8 @@ static void light_tree_leaf_emitters_copy_and_flatten(LightTreeFlatten &flatten, } kemitter.triangle.id = emitter.prim_id + mesh->prim_offset; - kemitter.mesh_light.shader_flag = shader_flag; - kemitter.mesh_light.object_id = emitter.object_id; + kemitter.shader_flag = shader_flag; + kemitter.object_id = emitter.object_id; kemitter.triangle.emission_sampling = shader->emission_sampling; flatten.triangle_array[emitter.prim_id + flatten.object_lookup_offset[emitter.object_id]] = emitter_index; @@ -575,16 +569,16 @@ static void light_tree_leaf_emitters_copy_and_flatten(LightTreeFlatten &flatten, else if (emitter.is_light()) { /* Light object. */ kemitter.light.id = emitter.light_id; - kemitter.mesh_light.shader_flag = 0; - kemitter.mesh_light.object_id = OBJECT_NONE; + kemitter.shader_flag = 0; + kemitter.object_id = emitter.object_id; flatten.light_array[~emitter.light_id] = emitter_index; } else { /* Mesh instance. */ assert(emitter.is_mesh()); kemitter.mesh.object_id = emitter.object_id; - kemitter.mesh_light.shader_flag = 0; - kemitter.mesh_light.object_id = OBJECT_NONE; + kemitter.shader_flag = 0; + kemitter.object_id = OBJECT_NONE; flatten.mesh_array[emitter.object_id] = emitter_index; /* Create instance node. One instance node will be the same as the @@ -595,7 +589,8 @@ static void light_tree_leaf_emitters_copy_and_flatten(LightTreeFlatten &flatten, auto map_it = flatten.instances.find(reference_node); if (map_it == flatten.instances.end()) { if (instance_node != reference_node) { - /* Flatten the node with the subtree first so the subsequent instances know the index. */ + /* Flatten the node with the subtree first so the subsequent instances know the index. + */ std::swap(instance_node->type, reference_node->type); std::swap(instance_node->variant_type, reference_node->variant_type); } @@ -727,8 +722,8 @@ static std::pair light_tree_specialize_nodes_flatten( assert(first_emitter != -1); - /* Preserve the type of the node, so that the kernel can do proper decision when sampling node - * with multiple distant lights in it. */ + /* Preserve the type of the node, so that the kernel can do proper decision when sampling + * node with multiple distant lights in it. */ if (node->is_leaf()) { new_node.make_leaf(first_emitter, num_emitters); } @@ -951,7 +946,12 @@ void LightManager::device_update_background(Device *device, bool background_mis = false; /* find background light */ - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) { background_light = light; background_mis |= light->use_mis; @@ -1125,7 +1125,12 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) size_t num_distant_lights = 0; bool use_light_mis = false; - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); if (light->is_enabled) { num_lights++; @@ -1165,14 +1170,24 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) int light_index = 0; int portal_index = num_lights; - for (Light *light : scene->lights) { + for (Object *object : scene->objects) { + if (!object->get_geometry()->is_light()) { + continue; + } + + Light *light = static_cast(object->get_geometry()); + const float3 axisu = transform_get_column(&object->get_tfm(), 0); + const float3 axisv = transform_get_column(&object->get_tfm(), 1); + const float3 dir = -transform_get_column(&object->get_tfm(), 2); + const float3 co = transform_get_column(&object->get_tfm(), 3); + /* Consider moving portals update to their own function * keeping this one more manageable. */ if (light->is_portal) { assert(light->light_type == LIGHT_AREA); - const float3 extentu = light->get_axisu() * (light->sizeu * light->size); - const float3 extentv = light->get_axisv() * (light->sizev * light->size); + const float3 extentu = axisu * (light->sizeu * light->size); + const float3 extentv = axisv * (light->sizev * light->size); float len_u; float len_v; @@ -1188,17 +1203,14 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) invarea = -invarea; } - const float3 dir = safe_normalize(light->get_dir()); - - klights[portal_index].co = light->get_co(); + klights[portal_index].co = co; klights[portal_index].area.axis_u = axis_u; klights[portal_index].area.len_u = len_u; klights[portal_index].area.axis_v = axis_v; klights[portal_index].area.len_v = len_v; klights[portal_index].area.invarea = invarea; - klights[portal_index].area.dir = dir; - klights[portal_index].tfm = light->tfm; - klights[portal_index].itfm = transform_inverse(light->tfm); + klights[portal_index].area.dir = safe_normalize(dir); + klights[portal_index].object_id = object->index; portal_index++; continue; @@ -1208,9 +1220,8 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) continue; } - Shader *shader = (light->shader) ? light->shader : scene->default_light; + Shader *shader = (light->get_shader()) ? light->get_shader() : scene->default_light; int shader_id = scene->shader_manager->get_shader_id(shader); - const float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF); if (!light->cast_shadow) { shader_id &= ~SHADER_CAST_SHADOW; @@ -1255,7 +1266,7 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) shader_id |= SHADER_USE_MIS; } - klights[light_index].co = light->get_co(); + klights[light_index].co = co; klights[light_index].spot.radius = radius; klights[light_index].spot.eval_fac = eval_fac; klights[light_index].spot.is_sphere = light->get_is_sphere() && radius != 0.0f; @@ -1263,7 +1274,6 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) else if (light->light_type == LIGHT_DISTANT) { shader_id &= ~SHADER_AREA_LIGHT; - const float3 dir = safe_normalize(light->get_dir()); const float angle = light->angle / 2.0f; if (light->use_mis && angle > 0.0f) { @@ -1273,7 +1283,7 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) const float one_minus_cosangle = 2.0f * sqr(sinf(0.5f * angle)); const float pdf = (angle > 0.0f) ? (M_1_2PI_F / one_minus_cosangle) : 1.0f; - klights[light_index].co = dir; + klights[light_index].co = safe_normalize(dir); klights[light_index].distant.angle = angle; klights[light_index].distant.one_minus_cosangle = one_minus_cosangle; klights[light_index].distant.pdf = pdf; @@ -1307,8 +1317,8 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) } else if (light->light_type == LIGHT_AREA) { const float light_size = light->size; - const float3 extentu = light->get_axisu() * (light->sizeu * light_size); - const float3 extentv = light->get_axisv() * (light->sizev * light_size); + const float3 extentu = axisu * (light->sizeu * light_size); + const float3 extentv = axisv * (light->sizev * light_size); float len_u; float len_v; @@ -1336,19 +1346,17 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) 3.0f / powf(half_spread, 3.0f)) : FLT_MAX; - const float3 dir = safe_normalize(light->get_dir()); - if (light->use_mis && area != 0.0f && light->spread > 0.0f) { shader_id |= SHADER_USE_MIS; } - klights[light_index].co = light->get_co(); + klights[light_index].co = co; klights[light_index].area.axis_u = axis_u; klights[light_index].area.len_u = len_u; klights[light_index].area.axis_v = axis_v; klights[light_index].area.len_v = len_v; klights[light_index].area.invarea = invarea; - klights[light_index].area.dir = dir; + klights[light_index].area.dir = safe_normalize(dir); klights[light_index].area.tan_half_spread = tan_half_spread; klights[light_index].area.normalize_spread = normalize_spread; } @@ -1357,12 +1365,12 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) const float spot_smooth = 1.0f / ((1.0f - cos_half_spot_angle) * light->spot_smooth); const float tan_half_spot_angle = tanf(light->spot_angle * 0.5f); - const float len_w_sq = len_squared(light->get_dir()); - const float len_u_sq = len_squared(light->get_axisu()); - const float len_v_sq = len_squared(light->get_axisv()); + const float len_w_sq = len_squared(dir); + const float len_u_sq = len_squared(axisu); + const float len_v_sq = len_squared(axisv); const float tan_sq = sqr(tan_half_spot_angle); - klights[light_index].spot.dir = safe_normalize(light->get_dir()); + klights[light_index].spot.dir = safe_normalize(dir); klights[light_index].spot.cos_half_spot_angle = cos_half_spot_angle; klights[light_index].spot.half_cot_half_spot_angle = 0.5f / tan_half_spot_angle; klights[light_index].spot.spot_smooth = spot_smooth; @@ -1375,31 +1383,11 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene) } klights[light_index].shader_id = shader_id; + klights[light_index].object_id = object->index; klights[light_index].max_bounces = light->max_bounces; - klights[light_index].random = random; klights[light_index].use_caustics = light->use_caustics; - klights[light_index].tfm = light->tfm; - klights[light_index].itfm = transform_inverse(light->tfm); - - /* Light group. */ - if (light->light_type == LIGHT_BACKGROUND) { - klights[light_index].lightgroup = dscene->data.background.lightgroup; - } - else { - 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; - } - } - - klights[light_index].light_set_membership = light->light_set_membership; - klights[light_index].shadow_set_membership = light->shadow_set_membership; - light_index++; } @@ -1423,8 +1411,6 @@ void LightManager::device_update(Device *device, } }); - VLOG_INFO << "Total " << scene->lights.size() << " lights."; - /* Detect which lights are enabled, also determines if we need to update the background. */ test_enabled_lights(scene); diff --git a/intern/cycles/scene/light.h b/intern/cycles/scene/light.h index b70b22f507d..3a37a83fa05 100644 --- a/intern/cycles/scene/light.h +++ b/intern/cycles/scene/light.h @@ -8,9 +8,7 @@ #include "graph/node.h" -/* included as Light::set_shader defined through NODE_SOCKET_API does not select - * the right Node::set overload as it does not know that Shader is a Node */ -#include "scene/shader.h" +#include "scene/geometry.h" #include "util/ies.h" #include "util/thread.h" @@ -26,7 +24,7 @@ class Progress; class Scene; class Shader; -class Light : public Node { +class Light : public Geometry { public: NODE_DECLARE; @@ -43,8 +41,6 @@ class Light : public Node { NODE_SOCKET_API(bool, ellipse) NODE_SOCKET_API(float, spread) - NODE_SOCKET_API(Transform, tfm) - NODE_SOCKET_API(int, map_resolution) NODE_SOCKET_API(float, average_radiance) @@ -66,13 +62,7 @@ class Light : public Node { NODE_SOCKET_API(bool, is_portal) NODE_SOCKET_API(bool, is_enabled) - NODE_SOCKET_API(Shader *, shader) NODE_SOCKET_API(int, max_bounces) - NODE_SOCKET_API(uint, random_id) - - NODE_SOCKET_API(ustring, lightgroup) - NODE_SOCKET_API(uint64_t, light_set_membership); - NODE_SOCKET_API(uint64_t, shadow_set_membership); /* Normalize power by the surface area of the light. */ NODE_SOCKET_API(bool, normalize) @@ -82,15 +72,14 @@ class Light : public Node { /* Check whether the light has contribution the scene. */ bool has_contribution(Scene *scene); - /* Check whether this light participates in light or shadow linking. */ - bool has_light_linking() const; - bool has_shadow_linking() const; + /* Shader */ + Shader *get_shader() const; - /* Convenience access to transform. */ - float3 get_co() const; - float3 get_dir() const; - float3 get_axisu() const; - float3 get_axisv() const; + /* Geometry */ + void compute_bounds() override; + void apply_transform(const Transform &tfm, const bool apply_to_motion) override; + void get_uv_tiles(ustring map, unordered_set &tiles) override; + PrimitiveType primitive_type() const override; friend class LightManager; friend class LightTree; diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp index 8d920a460ff..b3ff8e36dae 100644 --- a/intern/cycles/scene/light_tree.cpp +++ b/intern/cycles/scene/light_tree.cpp @@ -88,9 +88,10 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene, bool need_transformation) : prim_id(prim_id), object_id(object_id) { + Object *object = scene->objects[object_id]; + if (is_triangle()) { float3 vertices[3]; - Object *object = scene->objects[object_id]; Mesh *mesh = static_cast(object->get_geometry()); const Mesh::Triangle triangle = mesh->get_triangle(prim_id); Shader *shader = static_cast(mesh->get_used_shaders()[mesh->get_shader()[prim_id]]); @@ -148,13 +149,13 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene, } else { assert(is_light()); - Light *lamp = scene->lights[object_id]; + Light *lamp = static_cast(object->get_geometry()); const LightType type = lamp->get_light_type(); const float size = lamp->get_size(); float3 strength = lamp->get_strength(); - centroid = lamp->get_co(); - measure.bcone.axis = safe_normalize(lamp->get_dir()); + centroid = transform_get_column(&object->get_tfm(), 3); + measure.bcone.axis = -safe_normalize(transform_get_column(&object->get_tfm(), 2)); if (type == LIGHT_AREA) { measure.bcone.theta_o = 0; @@ -163,8 +164,10 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene, /* For an area light, sizeu and sizev determine the 2 dimensions of the area light, * while axisu and axisv determine the orientation of the 2 dimensions. * We want to add all 4 corners to our bounding box. */ - const float3 half_extentu = 0.5f * lamp->get_sizeu() * lamp->get_axisu() * size; - const float3 half_extentv = 0.5f * lamp->get_sizev() * lamp->get_axisv() * size; + const float3 axisu = transform_get_column(&object->get_tfm(), 0); + const float3 axisv = transform_get_column(&object->get_tfm(), 1); + const float3 half_extentu = 0.5f * lamp->get_sizeu() * axisu * size; + const float3 half_extentv = 0.5f * lamp->get_sizev() * axisv * size; measure.bbox.grow(centroid + half_extentu + half_extentv); measure.bbox.grow(centroid + half_extentu - half_extentv); measure.bbox.grow(centroid - half_extentu + half_extentv); @@ -188,9 +191,9 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene, measure.bcone.theta_o = 0; float theta_e = min(lamp->get_spot_angle() * 0.5f, M_PI_2_F); - const float len_u = len(lamp->get_axisu()); - const float len_v = len(lamp->get_axisv()); - const float len_w = len(lamp->get_dir()); + const float len_u = len(transform_get_column(&object->get_tfm(), 0)); + const float len_v = len(transform_get_column(&object->get_tfm(), 1)); + const float len_w = len(transform_get_column(&object->get_tfm(), 2)); /* As `theta_e` approaches `pi/2`, the behavior of `atan(tan(theta_e))` can become quite * unpredictable as `tan(x)` has an asymptote at `x = pi/2`. To avoid this, we skip the back @@ -236,7 +239,7 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene, * light tree. */ measure.energy = average(fabs(strength)); - light_set_membership = lamp->get_light_set_membership(); + light_set_membership = object->get_light_set_membership(); } } @@ -289,45 +292,42 @@ LightTree::LightTree(Scene *scene, * Therefore, we want to keep track of the light's index on the device. * However, we also need the light's index in the scene when we're constructing the tree. */ int device_light_index = 0; - int scene_light_index = 0; - for (Light *light : scene->lights) { - if (light->is_enabled) { - if (light->light_type == LIGHT_BACKGROUND || light->light_type == LIGHT_DISTANT) { - distant_lights_.emplace_back(scene, ~device_light_index, scene_light_index); - } - else { - local_lights_.emplace_back(scene, ~device_light_index, scene_light_index); - } - - device_light_index++; - } - - scene_light_index++; - } - - /* Similarly, we also want to keep track of the index of triangles of emissive objects. */ - int object_id = 0; for (Object *object : scene->objects) { if (progress_.get_cancel()) { return; } - light_link_receiver_used |= (uint64_t(1) << object->get_receiver_light_set()); + if (object->get_geometry()->is_light()) { + /* Regular lights. */ + Light *light = static_cast(object->get_geometry()); + if (light->is_enabled) { + if (light->light_type == LIGHT_BACKGROUND || light->light_type == LIGHT_DISTANT) { + distant_lights_.emplace_back(scene, ~device_light_index, object->index); + } + else { + local_lights_.emplace_back(scene, ~device_light_index, object->index); + } - if (!object->usable_as_light()) { - object_id++; - continue; + device_light_index++; + } } + else { + /* Emissive triangles. */ + light_link_receiver_used |= (uint64_t(1) << object->get_receiver_light_set()); - mesh_lights_.emplace_back(object, object_id); - object_id++; + if (!object->usable_as_light()) { + continue; + } - /* Only count unique meshes. */ - Mesh *mesh = static_cast(object->get_geometry()); - auto map_it = offset_map_.find(mesh); - if (map_it == offset_map_.end()) { - offset_map_[mesh] = num_triangles; - num_triangles += mesh->num_triangles(); + mesh_lights_.emplace_back(object, object->index); + + /* Only count unique meshes. */ + Mesh *mesh = static_cast(object->get_geometry()); + auto map_it = offset_map_.find(mesh); + if (map_it == offset_map_.end()) { + offset_map_[mesh] = num_triangles; + num_triangles += mesh->num_triangles(); + } } } } diff --git a/intern/cycles/scene/light_tree_debug.cpp b/intern/cycles/scene/light_tree_debug.cpp index e5bde5ceb12..ffebe627122 100644 --- a/intern/cycles/scene/light_tree_debug.cpp +++ b/intern/cycles/scene/light_tree_debug.cpp @@ -75,8 +75,8 @@ static void recursive_print_node(FILE *file, const LightTreeNode &node) fprintf(file, "];\n"); if (node.is_inner()) { - const LightTreeNode &left_node = *node.get_inner().children[LightTree::left].get(); - const LightTreeNode &right_node = *node.get_inner().children[LightTree::right].get(); + const LightTreeNode &left_node = *node.get_inner().children[LightTree::left]; + const LightTreeNode &right_node = *node.get_inner().children[LightTree::right]; recursive_print_node(file, left_node); recursive_print_node(file, right_node); @@ -95,21 +95,17 @@ static void print_emitters(FILE *file, const Scene &scene, const LightTree &tree string label = string_printf(" emitter %s", field++, std::to_string(i).c_str()); /* Emitter details (type, object or light name). */ + const Object &object = *scene.objects[emitter.object_id]; if (emitter.is_light()) { - const Light &lamp = *scene.lights[emitter.object_id]; label += string_printf("| light", field++); - label += string_printf("| %s", field++, lamp.name.c_str()); } else if (emitter.is_triangle()) { - const Object &object = *scene.objects[emitter.object_id]; label += string_printf("| triangle", field++); - label += string_printf("| %s", field++, object.name.c_str()); } else if (emitter.is_mesh()) { - const Object &object = *scene.objects[emitter.object_id]; label += string_printf("| mesh", field++); - label += string_printf("| %s", field++, object.name.c_str()); } + label += string_printf("| %s", field++, object.name.c_str()); /* Light linking. */ if (emitter.light_set_membership == ~uint64_t(0)) { @@ -176,8 +172,8 @@ static void recursive_print_node_relations(FILE *file, return; } - const LightTreeNode &left_node = *node.get_inner().children[LightTree::left].get(); - const LightTreeNode &right_node = *node.get_inner().children[LightTree::right].get(); + const LightTreeNode &left_node = *node.get_inner().children[LightTree::left]; + const LightTreeNode &right_node = *node.get_inner().children[LightTree::right]; const string left_node_id = get_node_id(left_node); const string right_node_id = get_node_id(right_node); diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp index caa3f12281d..f491719238d 100644 --- a/intern/cycles/scene/object.cpp +++ b/intern/cycles/scene/object.cpp @@ -272,6 +272,10 @@ int Object::motion_step(const float time) const bool Object::is_traceable() const { + /* Not supported for lights yet. */ + if (geometry->is_light()) { + return false; + } /* Mesh itself can be empty,can skip all such objects. */ if (!bounds.valid() || bounds.size() == zero_float3()) { return false; diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h index ae0648d0904..026bc8dbcc2 100644 --- a/intern/cycles/scene/object.h +++ b/intern/cycles/scene/object.h @@ -77,6 +77,10 @@ class Object : public Node { /* Set during device update. */ bool intersects_volume; + /* Specifies the position of the object in scene->objects and + * in the device vectors. Gets set in device_update. */ + int index; + Object(); ~Object() override; @@ -120,10 +124,6 @@ class Object : public Node { bool has_shadow_linking() const; protected: - /* Specifies the position of the object in scene->objects and - * in the device vectors. Gets set in device_update. */ - int index; - /* Reference to the attribute map with object attributes, * or 0 if none. Set in update_svm_attributes. */ size_t attr_map_offset; diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index 2b66123d5f3..7dbd053ee9b 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -99,7 +99,6 @@ void Scene::free_memory(bool final) procedurals.clear(); objects.clear(); geometry.clear(); - lights.clear(); particle_systems.clear(); passes.clear(); @@ -511,6 +510,12 @@ void Scene::update_kernel_features() else if (geom->is_pointcloud()) { kernel_features |= KERNEL_FEATURE_POINTCLOUD; } + else if (geom->is_light()) { + const Light *light = static_cast(object->get_geometry()); + if (light->get_use_caustics()) { + has_caustics_light = true; + } + } if (object->has_light_linking()) { kernel_features |= KERNEL_FEATURE_LIGHT_LINKING; } @@ -519,19 +524,6 @@ void Scene::update_kernel_features() } } - for (Light *light : lights) { - if (light->get_use_caustics()) { - has_caustics_light = true; - } - - if (light->has_light_linking()) { - kernel_features |= KERNEL_FEATURE_LIGHT_LINKING; - } - if (light->has_shadow_linking()) { - kernel_features |= KERNEL_FEATURE_SHADOW_LINKING; - } - } - dscene.data.integrator.use_caustics = false; if (device->info.has_mnee && has_caustics_caster && has_caustics_receiver && has_caustics_light) { @@ -741,7 +733,7 @@ template<> Light *Scene::create_node() unique_ptr node = make_unique(); Light *node_ptr = node.get(); node->set_owner(this); - lights.push_back(std::move(node)); + geometry.push_back(std::move(node)); light_manager->tag_update(this, LightManager::LIGHT_ADDED); return node_ptr; } @@ -879,7 +871,7 @@ template<> Film *Scene::create_node() template<> void Scene::delete_node(Light *node) { assert(node->get_owner() == this); - lights.erase_by_swap(node); + geometry.erase_by_swap(node); light_manager->tag_update(this, LightManager::LIGHT_REMOVED); } @@ -983,18 +975,12 @@ template static void assert_same_owner(const set &nodes, const #endif } -template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner) -{ - assert_same_owner(nodes, owner); - lights.erase_in_set(nodes); - light_manager->tag_update(this, LightManager::LIGHT_REMOVED); -} - template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner) { assert_same_owner(nodes, owner); geometry.erase_in_set(nodes); geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED); + light_manager->tag_update(this, LightManager::LIGHT_REMOVED); } template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner) diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 2777949cae8..4b231270d86 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -136,7 +136,6 @@ class Scene : public NodeOwner { unique_ptr_vector shaders; unique_ptr_vector passes; unique_ptr_vector particle_systems; - unique_ptr_vector lights; unique_ptr_vector geometry; unique_ptr_vector objects; unique_ptr_vector procedurals; @@ -281,7 +280,6 @@ template<> void Scene::delete_node(Procedural *node); template<> void Scene::delete_node(AlembicProcedural *node); template<> void Scene::delete_node(Pass *node); -template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner); template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner); template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner); template<> void Scene::delete_nodes(const set &nodes, const NodeOwner *owner);