Cycles: Refactor lights to be objects
This is an intermediate steps towards making lights actual geometry. Light is now a subclass of Geometry, which simplifies some code. The geometry is not added to the BVH yet, which would be the next step and improve light intersection performance with many lights. This makes object attributes work on lights. Co-authored-by: Lukas Stockner <lukas@lukasstockner.de> Pull Request: https://projects.blender.org/blender/blender/pulls/134846
This commit is contained in:
committed by
Lukas Stockner
parent
92c0eb5e66
commit
e813e46327
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "scene/curves.h"
|
#include "scene/curves.h"
|
||||||
#include "scene/hair.h"
|
#include "scene/hair.h"
|
||||||
|
#include "scene/light.h"
|
||||||
#include "scene/mesh.h"
|
#include "scene/mesh.h"
|
||||||
#include "scene/object.h"
|
#include "scene/object.h"
|
||||||
#include "scene/pointcloud.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)
|
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) {
|
if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
|
||||||
return Geometry::HAIR;
|
return Geometry::HAIR;
|
||||||
}
|
}
|
||||||
@@ -38,12 +43,17 @@ static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_parti
|
|||||||
|
|
||||||
array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
|
array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
|
||||||
{
|
{
|
||||||
|
array<Node *> 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;
|
BL::Material material_override = view_layer.material_override;
|
||||||
Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
|
Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
|
||||||
scene->default_surface;
|
scene->default_surface;
|
||||||
|
|
||||||
array<Node *> used_shaders;
|
|
||||||
|
|
||||||
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
|
for (BL::MaterialSlot &b_slot : b_ob.material_slots) {
|
||||||
if (material_override) {
|
if (material_override) {
|
||||||
find_shader(material_override, used_shaders, default_shader);
|
find_shader(material_override, used_shaders, default_shader);
|
||||||
@@ -95,7 +105,10 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||||||
bool sync = true;
|
bool sync = true;
|
||||||
if (geom == nullptr) {
|
if (geom == nullptr) {
|
||||||
/* Add new geometry if it did not exist yet. */
|
/* Add new geometry if it did not exist yet. */
|
||||||
if (geom_type == Geometry::HAIR) {
|
if (geom_type == Geometry::LIGHT) {
|
||||||
|
geom = scene->create_node<Light>();
|
||||||
|
}
|
||||||
|
else if (geom_type == Geometry::HAIR) {
|
||||||
geom = scene->create_node<Hair>();
|
geom = scene->create_node<Hair>();
|
||||||
}
|
}
|
||||||
else if (geom_type == Geometry::VOLUME) {
|
else if (geom_type == Geometry::VOLUME) {
|
||||||
@@ -115,6 +128,11 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!sync) {
|
if (!sync) {
|
||||||
|
/* Need to determine this every sync. */
|
||||||
|
if (geom->is_light() && static_cast<const Light *>(geom)->get_is_portal()) {
|
||||||
|
world_use_portal = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* If transform was applied to geometry, need full update. */
|
/* If transform was applied to geometry, need full update. */
|
||||||
if (object_updated && geom->transform_applied) {
|
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());
|
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<Light *>(geom);
|
||||||
|
sync_light(b_depsgraph, b_ob_info, light);
|
||||||
|
}
|
||||||
|
else if (geom_type == Geometry::HAIR) {
|
||||||
Hair *hair = static_cast<Hair *>(geom);
|
Hair *hair = static_cast<Hair *>(geom);
|
||||||
sync_hair(b_depsgraph, b_ob_info, hair);
|
sync_hair(b_depsgraph, b_ob_info, hair);
|
||||||
}
|
}
|
||||||
@@ -209,6 +231,11 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Nothing to do for lights. */
|
||||||
|
if (geom->is_light()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the geometry already has motion blur from a velocity attribute, don't
|
/* If the geometry already has motion blur from a velocity attribute, don't
|
||||||
* set the geometry motion steps again.
|
* set the geometry motion steps again.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,42 +4,16 @@
|
|||||||
|
|
||||||
#include "scene/light.h"
|
#include "scene/light.h"
|
||||||
|
|
||||||
#include "blender/light_linking.h"
|
|
||||||
#include "blender/sync.h"
|
#include "blender/sync.h"
|
||||||
#include "blender/util.h"
|
#include "blender/util.h"
|
||||||
|
#include "scene/object.h"
|
||||||
#include "util/hash.h"
|
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void BlenderSync::sync_light(BL::Object &b_parent,
|
void BlenderSync::sync_light(BL::Depsgraph /*b_depsgraph*/, BObjectInfo &b_ob_info, Light *light)
|
||||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
|
||||||
BObjectInfo &b_ob_info,
|
|
||||||
const int random_id,
|
|
||||||
Transform &tfm,
|
|
||||||
bool *use_portal)
|
|
||||||
{
|
{
|
||||||
/* 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);
|
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();
|
light->name = b_light.name().c_str();
|
||||||
|
|
||||||
/* type */
|
/* 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();
|
const float3 strength = get_float3(b_light.color()) * BL::PointLight(b_light).energy();
|
||||||
light->set_strength(strength);
|
light->set_strength(strength);
|
||||||
|
|
||||||
/* location and (inverted!) direction */
|
|
||||||
light->set_tfm(tfm);
|
|
||||||
|
|
||||||
/* shader */
|
|
||||||
array<Node *> used_shaders;
|
|
||||||
find_shader(b_light, used_shaders, scene->default_light);
|
|
||||||
light->set_shader(static_cast<Shader *>(used_shaders[0]));
|
|
||||||
|
|
||||||
/* shadow */
|
/* shadow */
|
||||||
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
|
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
|
||||||
light->set_cast_shadow(b_light.use_shadow());
|
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"));
|
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) {
|
if (light->get_light_type() == LIGHT_AREA) {
|
||||||
light->set_is_portal(get_boolean(clight, "is_portal"));
|
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()) {
|
if (light->get_is_portal()) {
|
||||||
*use_portal = true;
|
world_use_portal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* visibility */
|
/* 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_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
|
||||||
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
|
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 */
|
/* tag */
|
||||||
light->tag_update(scene);
|
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();
|
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);
|
cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
|
||||||
const bool sample_as_light = (sampling_method != SAMPLING_NONE);
|
const bool sample_as_light = (sampling_method != SAMPLING_NONE);
|
||||||
|
|
||||||
if (sample_as_light || use_portal) {
|
if (sample_as_light || world_use_portal) {
|
||||||
/* test if we need to sync */
|
/* Create object. */
|
||||||
Light *light;
|
Object *object;
|
||||||
const ObjectKey key(b_world, nullptr, b_world, false);
|
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<Light>();
|
||||||
|
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<Light *>(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);
|
light->set_light_type(LIGHT_BACKGROUND);
|
||||||
if (sampling_method == SAMPLING_MANUAL) {
|
if (sampling_method == SAMPLING_MANUAL) {
|
||||||
light->set_map_resolution(get_int(cworld, "sample_map_resolution"));
|
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 {
|
else {
|
||||||
light->set_map_resolution(0);
|
light->set_map_resolution(0);
|
||||||
}
|
}
|
||||||
light->set_shader(scene->default_background);
|
array<Node *> 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_use_mis(sample_as_light);
|
||||||
light->set_max_bounces(get_int(cworld, "max_bounces"));
|
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->set_use_caustics(get_boolean(cworld, "is_caustics_light"));
|
||||||
|
|
||||||
light->tag_update(scene);
|
light->tag_update(scene);
|
||||||
light_map.set_recalc(b_world);
|
geometry_map.set_recalc(b_world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
const BL::Object::type_enum type = b_ob_info.iter_object.type();
|
||||||
|
|
||||||
if (type == BL::Object::type_VOLUME || type == BL::Object::type_CURVES ||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +152,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
|||||||
bool use_particle_hair,
|
bool use_particle_hair,
|
||||||
bool show_lights,
|
bool show_lights,
|
||||||
BlenderObjectCulling &culling,
|
BlenderObjectCulling &culling,
|
||||||
bool *use_portal,
|
|
||||||
TaskPool *geom_task_pool)
|
TaskPool *geom_task_pool)
|
||||||
{
|
{
|
||||||
const bool is_instance = b_instance.is_instance();
|
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 */
|
/* only interested in object that we can create geometry from */
|
||||||
if (!object_is_geometry(b_ob_info)) {
|
if (!object_is_geometry(b_ob_info)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform object culling. */
|
/* 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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +525,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
|
|
||||||
if (!motion) {
|
if (!motion) {
|
||||||
/* prepare for sync */
|
/* prepare for sync */
|
||||||
light_map.pre_sync();
|
|
||||||
geometry_map.pre_sync();
|
geometry_map.pre_sync();
|
||||||
object_map.pre_sync();
|
object_map.pre_sync();
|
||||||
procedural_map.pre_sync();
|
procedural_map.pre_sync();
|
||||||
@@ -555,6 +535,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
geometry_motion_synced.clear();
|
geometry_motion_synced.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
world_use_portal = false;
|
||||||
|
|
||||||
if (!motion) {
|
if (!motion) {
|
||||||
/* Object to geometry instance mapping is built for the reference time, as other
|
/* Object to geometry instance mapping is built for the reference time, as other
|
||||||
* times just look up the corresponding geometry. */
|
* times just look up the corresponding geometry. */
|
||||||
@@ -566,7 +548,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
|
|
||||||
/* object loop */
|
/* object loop */
|
||||||
bool cancel = false;
|
bool cancel = false;
|
||||||
bool use_portal = false;
|
|
||||||
const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
|
const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
|
||||||
|
|
||||||
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
|
||||||
@@ -623,7 +604,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
false,
|
false,
|
||||||
show_lights,
|
show_lights,
|
||||||
culling,
|
culling,
|
||||||
&use_portal,
|
|
||||||
sync_hair ? nullptr : &geom_task_pool);
|
sync_hair ? nullptr : &geom_task_pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,7 +617,6 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
true,
|
true,
|
||||||
show_lights,
|
show_lights,
|
||||||
culling,
|
culling,
|
||||||
&use_portal,
|
|
||||||
&geom_task_pool);
|
&geom_task_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,12 +628,12 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
progress.set_sync_status("");
|
progress.set_sync_status("");
|
||||||
|
|
||||||
if (!cancel && !motion) {
|
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
|
/* 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
|
* right order to ensure that dependent data is freed after their users. Objects should be
|
||||||
* freed before particle systems and geometries. */
|
* freed before particle systems and geometries. */
|
||||||
light_map.post_sync();
|
|
||||||
object_map.post_sync();
|
object_map.post_sync();
|
||||||
geometry_map.post_sync();
|
geometry_map.post_sync();
|
||||||
particle_system_map.post_sync();
|
particle_system_map.post_sync();
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ using ProxyMap = map<string, ConvertNode *>;
|
|||||||
|
|
||||||
/* Find */
|
/* Find */
|
||||||
|
|
||||||
void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
|
void BlenderSync::find_shader(const BL::ID &id,
|
||||||
|
array<Node *> &used_shaders,
|
||||||
|
Shader *default_shader)
|
||||||
{
|
{
|
||||||
Shader *synced_shader = (id) ? shader_map.find(id) : nullptr;
|
Shader *synced_shader = (id) ? shader_map.find(id) : nullptr;
|
||||||
Shader *shader = (synced_shader) ? synced_shader : default_shader;
|
Shader *shader = (synced_shader) ? synced_shader : default_shader;
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
|
|||||||
object_map(scene),
|
object_map(scene),
|
||||||
procedural_map(scene),
|
procedural_map(scene),
|
||||||
geometry_map(scene),
|
geometry_map(scene),
|
||||||
light_map(scene),
|
|
||||||
particle_system_map(scene),
|
particle_system_map(scene),
|
||||||
world_map(nullptr),
|
world_map(nullptr),
|
||||||
world_recalc(false),
|
world_recalc(false),
|
||||||
@@ -206,11 +205,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
|
|||||||
else if (is_light) {
|
else if (is_light) {
|
||||||
if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
|
if (b_update.is_updated_transform() || b_update.is_updated_shading()) {
|
||||||
object_map.set_recalc(b_ob);
|
object_map.set_recalc(b_ob);
|
||||||
light_map.set_recalc(b_ob);
|
geometry_map.set_recalc(b_ob);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated_geometry) {
|
if (updated_geometry) {
|
||||||
light_map.set_recalc(b_ob);
|
geometry_map.set_recalc(b_ob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ class BlenderSync {
|
|||||||
bool use_particle_hair,
|
bool use_particle_hair,
|
||||||
bool show_lights,
|
bool show_lights,
|
||||||
BlenderObjectCulling &culling,
|
BlenderObjectCulling &culling,
|
||||||
bool *use_portal,
|
|
||||||
TaskPool *geom_task_pool);
|
TaskPool *geom_task_pool);
|
||||||
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
|
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
|
||||||
|
|
||||||
@@ -206,13 +205,8 @@ class BlenderSync {
|
|||||||
TaskPool *task_pool);
|
TaskPool *task_pool);
|
||||||
|
|
||||||
/* Light */
|
/* Light */
|
||||||
void sync_light(BL::Object &b_parent,
|
void sync_light(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Light *light);
|
||||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
void sync_background_light(BL::SpaceView3D &b_v3d);
|
||||||
BObjectInfo &b_ob_info,
|
|
||||||
const int random_id,
|
|
||||||
Transform &tfm,
|
|
||||||
bool *use_portal);
|
|
||||||
void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal);
|
|
||||||
|
|
||||||
/* Particles */
|
/* Particles */
|
||||||
bool sync_dupli_particle(BL::Object &b_ob,
|
bool sync_dupli_particle(BL::Object &b_ob,
|
||||||
@@ -223,7 +217,7 @@ class BlenderSync {
|
|||||||
void sync_images();
|
void sync_images();
|
||||||
|
|
||||||
/* util */
|
/* util */
|
||||||
void find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader);
|
void find_shader(const BL::ID &id, array<Node *> &used_shaders, Shader *default_shader);
|
||||||
bool BKE_object_is_modified(BL::Object &b_ob);
|
bool BKE_object_is_modified(BL::Object &b_ob);
|
||||||
bool object_is_geometry(BObjectInfo &b_ob_info);
|
bool object_is_geometry(BObjectInfo &b_ob_info);
|
||||||
bool object_can_have_geometry(BL::Object &b_ob);
|
bool object_can_have_geometry(BL::Object &b_ob);
|
||||||
@@ -242,7 +236,6 @@ class BlenderSync {
|
|||||||
id_map<ObjectKey, Object> object_map;
|
id_map<ObjectKey, Object> object_map;
|
||||||
id_map<void *, Procedural> procedural_map;
|
id_map<void *, Procedural> procedural_map;
|
||||||
id_map<GeometryKey, Geometry> geometry_map;
|
id_map<GeometryKey, Geometry> geometry_map;
|
||||||
id_map<ObjectKey, Light> light_map;
|
|
||||||
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
||||||
set<Geometry *> geometry_synced;
|
set<Geometry *> geometry_synced;
|
||||||
set<Geometry *> geometry_motion_synced;
|
set<Geometry *> geometry_motion_synced;
|
||||||
@@ -252,6 +245,7 @@ class BlenderSync {
|
|||||||
set<float> motion_times;
|
set<float> motion_times;
|
||||||
void *world_map;
|
void *world_map;
|
||||||
bool world_recalc;
|
bool world_recalc;
|
||||||
|
bool world_use_portal = false;
|
||||||
BlenderViewportParameters viewport_parameters;
|
BlenderViewportParameters viewport_parameters;
|
||||||
|
|
||||||
Scene *scene;
|
Scene *scene;
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
#include "hydra/light.h"
|
#include "hydra/light.h"
|
||||||
#include "hydra/session.h"
|
#include "hydra/session.h"
|
||||||
#include "scene/light.h"
|
#include "scene/light.h"
|
||||||
|
#include "scene/object.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "scene/shader.h"
|
#include "scene/shader.h"
|
||||||
#include "scene/shader_graph.h"
|
#include "scene/shader_graph.h"
|
||||||
#include "scene/shader_nodes.h"
|
#include "scene/shader_nodes.h"
|
||||||
#include "util/hash.h"
|
#include "util/hash.h"
|
||||||
|
#include "util/transform.h"
|
||||||
|
|
||||||
#include <pxr/imaging/hd/sceneDelegate.h>
|
#include <pxr/imaging/hd/sceneDelegate.h>
|
||||||
#include <pxr/usd/sdf/assetPath.h>
|
#include <pxr/usd/sdf/assetPath.h>
|
||||||
@@ -64,7 +66,7 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate,
|
|||||||
sceneDelegate->GetLightParamValue(id, HdTokens->transform)
|
sceneDelegate->GetLightParamValue(id, HdTokens->transform)
|
||||||
.Get<GfMatrix4d>());
|
.Get<GfMatrix4d>());
|
||||||
#endif
|
#endif
|
||||||
_light->set_tfm(tfm);
|
_object->set_tfm(tfm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*dirtyBits & DirtyBits::DirtyParams) {
|
if (*dirtyBits & DirtyBits::DirtyParams) {
|
||||||
@@ -175,8 +177,8 @@ void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate,
|
|||||||
PopulateShaderGraph(sceneDelegate);
|
PopulateShaderGraph(sceneDelegate);
|
||||||
}
|
}
|
||||||
// Need to update shader graph when transform changes in case transform was baked into it
|
// Need to update shader graph when transform changes in case transform was baked into it
|
||||||
else if (_light->tfm_is_modified() && (_lightType == HdPrimTypeTokens->domeLight ||
|
else if (_object->tfm_is_modified() && (_lightType == HdPrimTypeTokens->domeLight ||
|
||||||
_light->get_shader()->has_surface_spatial_varying))
|
_light->get_shader()->has_surface_spatial_varying))
|
||||||
{
|
{
|
||||||
PopulateShaderGraph(sceneDelegate);
|
PopulateShaderGraph(sceneDelegate);
|
||||||
}
|
}
|
||||||
@@ -266,7 +268,7 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
|
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
|
||||||
coordNode->set_ob_tfm(_light->get_tfm());
|
coordNode->set_ob_tfm(_object->get_tfm());
|
||||||
coordNode->set_use_transform(true);
|
coordNode->set_use_transform(true);
|
||||||
|
|
||||||
IESLightNode *iesNode = graph->create_node<IESLightNode>();
|
IESLightNode *iesNode = graph->create_node<IESLightNode>();
|
||||||
@@ -287,7 +289,7 @@ void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
|
|||||||
|
|
||||||
ImageSlotTextureNode *textureNode = nullptr;
|
ImageSlotTextureNode *textureNode = nullptr;
|
||||||
if (_lightType == HdPrimTypeTokens->domeLight) {
|
if (_lightType == HdPrimTypeTokens->domeLight) {
|
||||||
Transform tfm = _light->get_tfm();
|
Transform tfm = _object->get_tfm();
|
||||||
transform_set_column(&tfm, 3, zero_float3()); // Remove translation
|
transform_set_column(&tfm, 3, zero_float3()); // Remove translation
|
||||||
|
|
||||||
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
|
TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
|
||||||
@@ -352,9 +354,11 @@ void HdCyclesLight::Finalize(HdRenderParam *renderParam)
|
|||||||
|
|
||||||
if (!keep_nodes) {
|
if (!keep_nodes) {
|
||||||
lock.scene->delete_node(_light);
|
lock.scene->delete_node(_light);
|
||||||
|
lock.scene->delete_node(_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
_light = nullptr;
|
_light = nullptr;
|
||||||
|
_object = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HdCyclesLight::Initialize(HdRenderParam *renderParam)
|
void HdCyclesLight::Initialize(HdRenderParam *renderParam)
|
||||||
@@ -365,10 +369,14 @@ void HdCyclesLight::Initialize(HdRenderParam *renderParam)
|
|||||||
|
|
||||||
const SceneLock lock(renderParam);
|
const SceneLock lock(renderParam);
|
||||||
|
|
||||||
|
_object = lock.scene->create_node<Object>();
|
||||||
|
_object->name = GetId().GetString();
|
||||||
|
|
||||||
_light = lock.scene->create_node<Light>();
|
_light = lock.scene->create_node<Light>();
|
||||||
_light->name = GetId().GetString();
|
_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) {
|
if (_lightType == HdPrimTypeTokens->domeLight) {
|
||||||
_light->set_light_type(LIGHT_BACKGROUND);
|
_light->set_light_type(LIGHT_BACKGROUND);
|
||||||
@@ -395,7 +403,9 @@ void HdCyclesLight::Initialize(HdRenderParam *renderParam)
|
|||||||
_light->set_use_camera(false);
|
_light->set_use_camera(false);
|
||||||
|
|
||||||
Shader *const shader = lock.scene->create_node<Shader>();
|
Shader *const shader = lock.scene->create_node<Shader>();
|
||||||
_light->set_shader(shader);
|
array<Node *> used_shaders;
|
||||||
|
used_shaders.push_back_slow(shader);
|
||||||
|
_light->set_used_shaders(used_shaders);
|
||||||
|
|
||||||
// Create default shader graph
|
// Create default shader graph
|
||||||
PopulateShaderGraph(nullptr);
|
PopulateShaderGraph(nullptr);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class HdCyclesLight final : public PXR_NS::HdLight {
|
|||||||
|
|
||||||
void PopulateShaderGraph(PXR_NS::HdSceneDelegate *sceneDelegate);
|
void PopulateShaderGraph(PXR_NS::HdSceneDelegate *sceneDelegate);
|
||||||
|
|
||||||
|
CCL_NS::Object *_object = nullptr;
|
||||||
CCL_NS::Light *_light = nullptr;
|
CCL_NS::Light *_light = nullptr;
|
||||||
PXR_NS::TfToken _lightType;
|
PXR_NS::TfToken _lightType;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0 */
|
* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
|
||||||
#include "hydra/session.h"
|
#include "hydra/session.h"
|
||||||
|
#include "scene/object.h"
|
||||||
#include "scene/shader.h"
|
#include "scene/shader.h"
|
||||||
// Have to include shader.h before background.h so that 'set_shader' uses the correct 'set'
|
// 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'
|
// 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
|
// Update background depending on presence of a background light
|
||||||
if (scene->light_manager->need_update()) {
|
if (scene->light_manager->need_update()) {
|
||||||
Light *background_light = nullptr;
|
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<Light *>(object->get_geometry());
|
||||||
if (light->get_light_type() == LIGHT_BACKGROUND) {
|
if (light->get_light_type() == LIGHT_BACKGROUND) {
|
||||||
background_light = light;
|
background_light = light;
|
||||||
break;
|
break;
|
||||||
@@ -115,7 +124,7 @@ void HdCyclesSession::UpdateScene()
|
|||||||
for (ShaderNode *node : scene->default_background->graph->nodes) {
|
for (ShaderNode *node : scene->default_background->graph->nodes) {
|
||||||
if (node->is_a(BackgroundNode::get_node_type())) {
|
if (node->is_a(BackgroundNode::get_node_type())) {
|
||||||
BackgroundNode *bgNode = static_cast<BackgroundNode *>(node);
|
BackgroundNode *bgNode = static_cast<BackgroundNode *>(node);
|
||||||
bgNode->set_color((scene->lights.empty()) ? make_float3(0.5f) : zero_float3());
|
bgNode->set_color((have_lights) ? zero_float3() : make_float3(0.5f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,10 +260,6 @@ ccl_device_inline bool intersection_skip_self_local(const ccl_ray_data RaySelfPr
|
|||||||
ccl_device_inline uint64_t
|
ccl_device_inline uint64_t
|
||||||
ray_get_shadow_set_membership(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self)
|
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) {
|
if (self.light_object != OBJECT_NONE) {
|
||||||
return kernel_data_fetch(objects, self.light_object).shadow_set_membership;
|
return kernel_data_fetch(objects, self.light_object).shadow_set_membership;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,9 +85,8 @@ ccl_device T curve_attribute(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
|
if (desc.element == ATTR_ELEMENT_CURVE) {
|
||||||
const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim : desc.offset;
|
return attribute_data_fetch<T>(kg, desc.offset + sd->prim);
|
||||||
return attribute_data_fetch<T>(kg, offset);
|
|
||||||
}
|
}
|
||||||
return make_zero<T>();
|
return make_zero<T>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,16 +40,6 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals kg,
|
|||||||
return kernel_data_fetch(objects, object).tfm;
|
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 */
|
/* Object to world space transformation for motion vectors */
|
||||||
|
|
||||||
ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg,
|
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);
|
return object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
|
||||||
#endif
|
#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 */
|
/* Transform position from object to world space */
|
||||||
|
|
||||||
ccl_device_inline void object_position_transform(KernelGlobals kg,
|
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__
|
#ifdef __OBJECT_MOTION__
|
||||||
if (sd->object_flag & SD_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));
|
*N = safe_normalize(transform_direction_transposed_auto(&sd->ob_tfm_motion, *N));
|
||||||
}
|
}
|
||||||
return;
|
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);
|
const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
|
||||||
*N = safe_normalize(transform_direction_transposed(&tfm, *N));
|
*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 */
|
/* 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);
|
const Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
|
||||||
*N = normalize(transform_direction_transposed(&tfm, *N));
|
*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)
|
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;
|
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. */
|
/* Light-group of object. */
|
||||||
|
|
||||||
ccl_device_inline int object_lightgroup(KernelGlobals kg, const int 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;
|
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 */
|
/* Per object random number for shader variation */
|
||||||
|
|
||||||
ccl_device_inline float object_random_number(KernelGlobals kg, const int object)
|
ccl_device_inline float object_random_number(KernelGlobals kg, const int object)
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ ccl_device_forceinline T primitive_surface_attribute(KernelGlobals kg,
|
|||||||
ccl_private T *dfdx,
|
ccl_private T *dfdx,
|
||||||
ccl_private T *dfdy)
|
ccl_private T *dfdy)
|
||||||
{
|
{
|
||||||
|
if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
|
||||||
|
if (dfdx) {
|
||||||
|
*dfdx = make_zero<T>();
|
||||||
|
}
|
||||||
|
if (dfdy) {
|
||||||
|
*dfdy = make_zero<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attribute_data_fetch<T>(kg, desc.offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (sd->type & PRIMITIVE_TRIANGLE) {
|
if (sd->type & PRIMITIVE_TRIANGLE) {
|
||||||
if (subd_triangle_patch(kg, sd->prim) == ~0) {
|
if (subd_triangle_patch(kg, sd->prim) == ~0) {
|
||||||
return triangle_attribute<T>(kg, sd, desc, dfdx, dfdy);
|
return triangle_attribute<T>(kg, sd, desc, dfdx, dfdy);
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
|
|||||||
sd->object = isect->object;
|
sd->object = isect->object;
|
||||||
sd->object_flag = kernel_data_fetch(object_flag, sd->object);
|
sd->object_flag = kernel_data_fetch(object_flag, sd->object);
|
||||||
sd->prim = isect->prim;
|
sd->prim = isect->prim;
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
sd->flag = 0;
|
sd->flag = 0;
|
||||||
|
|
||||||
/* Read matrices and time. */
|
/* Read matrices and time. */
|
||||||
@@ -139,8 +138,8 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||||||
const float v,
|
const float v,
|
||||||
const float t,
|
const float t,
|
||||||
const float time,
|
const float time,
|
||||||
bool object_space,
|
const bool object_space,
|
||||||
const int lamp)
|
const bool is_lamp)
|
||||||
{
|
{
|
||||||
/* vectors */
|
/* vectors */
|
||||||
sd->P = P;
|
sd->P = P;
|
||||||
@@ -148,7 +147,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||||||
sd->Ng = Ng;
|
sd->Ng = Ng;
|
||||||
sd->wi = I;
|
sd->wi = I;
|
||||||
sd->shader = shader;
|
sd->shader = shader;
|
||||||
if (lamp != LAMP_NONE) {
|
if (is_lamp) {
|
||||||
sd->type = PRIMITIVE_LAMP;
|
sd->type = PRIMITIVE_LAMP;
|
||||||
}
|
}
|
||||||
else if (prim != PRIM_NONE) {
|
else if (prim != PRIM_NONE) {
|
||||||
@@ -160,7 +159,6 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||||||
|
|
||||||
/* primitive */
|
/* primitive */
|
||||||
sd->object = object;
|
sd->object = object;
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
/* Currently no access to bvh prim index for strand sd->prim. */
|
/* Currently no access to bvh prim index for strand sd->prim. */
|
||||||
sd->prim = prim;
|
sd->prim = prim;
|
||||||
sd->u = u;
|
sd->u = u;
|
||||||
@@ -213,9 +211,6 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (lamp != LAMP_NONE) {
|
|
||||||
sd->lamp = lamp;
|
|
||||||
}
|
|
||||||
#ifdef __DPDU__
|
#ifdef __DPDU__
|
||||||
sd->dPdu = zero_float3();
|
sd->dPdu = zero_float3();
|
||||||
sd->dPdv = zero_float3();
|
sd->dPdv = zero_float3();
|
||||||
@@ -278,7 +273,7 @@ ccl_device void shader_setup_from_displace(KernelGlobals kg,
|
|||||||
0.0f,
|
0.0f,
|
||||||
0.5f,
|
0.5f,
|
||||||
!(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
|
!(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
|
||||||
LAMP_NONE);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ShaderData setup for point on curve. */
|
/* ShaderData setup for point on curve. */
|
||||||
@@ -293,7 +288,6 @@ ccl_device void shader_setup_from_curve(KernelGlobals kg,
|
|||||||
{
|
{
|
||||||
/* Primitive */
|
/* Primitive */
|
||||||
sd->type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE_THICK, segment);
|
sd->type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE_THICK, segment);
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
sd->prim = prim;
|
sd->prim = prim;
|
||||||
sd->u = u;
|
sd->u = u;
|
||||||
sd->v = 0.0f;
|
sd->v = 0.0f;
|
||||||
@@ -381,7 +375,6 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals kg,
|
|||||||
sd->ray_length = FLT_MAX;
|
sd->ray_length = FLT_MAX;
|
||||||
|
|
||||||
sd->object = OBJECT_NONE;
|
sd->object = OBJECT_NONE;
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
sd->prim = PRIM_NONE;
|
sd->prim = PRIM_NONE;
|
||||||
sd->type = PRIMITIVE_NONE;
|
sd->type = PRIMITIVE_NONE;
|
||||||
sd->u = 0.0f;
|
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. */
|
/* TODO: fill relevant fields for texture coordinates. */
|
||||||
sd->object = object;
|
sd->object = object;
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
sd->prim = PRIM_NONE;
|
sd->prim = PRIM_NONE;
|
||||||
sd->type = PRIMITIVE_VOLUME;
|
sd->type = PRIMITIVE_VOLUME;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
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<T>();
|
|
||||||
}
|
|
||||||
if (dfdy) {
|
|
||||||
*dfdy = make_zero<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return attribute_data_fetch<T>(kg, desc.offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dfdx) {
|
if (dfdx) {
|
||||||
*dfdx = make_zero<T>();
|
*dfdx = make_zero<T>();
|
||||||
|
|||||||
@@ -275,9 +275,8 @@ ccl_device T triangle_attribute(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
|
if (desc.element == ATTR_ELEMENT_FACE) {
|
||||||
const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim : desc.offset;
|
return attribute_data_fetch<T>(kg, desc.offset + sd->prim);
|
||||||
return attribute_data_fetch<T>(kg, offset);
|
|
||||||
}
|
}
|
||||||
return make_zero<T>();
|
return make_zero<T>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,7 +374,6 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
|
|||||||
ray.self.prim = last_isect_prim;
|
ray.self.prim = last_isect_prim;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
||||||
|
|
||||||
/* TODO: remove this and do it in the various intersection functions instead. */
|
/* TODO: remove this and do it in the various intersection functions instead. */
|
||||||
|
|||||||
@@ -189,7 +189,6 @@ ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state
|
|||||||
ray.self.object = INTEGRATOR_STATE(state, isect, object);
|
ray.self.object = INTEGRATOR_STATE(state, isect, object);
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
Intersection isect ccl_optional_struct_init;
|
Intersection isect ccl_optional_struct_init;
|
||||||
if (!shadow_linking_pick_light_intersection(kg, state, &ray, &isect)) {
|
if (!shadow_linking_pick_light_intersection(kg, state, &ray, &isect)) {
|
||||||
|
|||||||
@@ -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.prim = INTEGRATOR_STATE(state, isect, prim);
|
||||||
volume_ray.self.light_object = OBJECT_NONE;
|
volume_ray.self.light_object = OBJECT_NONE;
|
||||||
volume_ray.self.light_prim = PRIM_NONE;
|
volume_ray.self.light_prim = PRIM_NONE;
|
||||||
volume_ray.self.light = LAMP_NONE;
|
|
||||||
/* Store to avoid global fetches on every intersection step. */
|
/* Store to avoid global fetches on every intersection step. */
|
||||||
const uint volume_stack_size = kernel_data.volume_stack_size;
|
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.prim = PRIM_NONE;
|
||||||
volume_ray.self.light_object = OBJECT_NONE;
|
volume_ray.self.light_object = OBJECT_NONE;
|
||||||
volume_ray.self.light_prim = PRIM_NONE;
|
volume_ray.self.light_prim = PRIM_NONE;
|
||||||
volume_ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
int stack_index = 0;
|
int stack_index = 0;
|
||||||
int enclosed_index = 0;
|
int enclosed_index = 0;
|
||||||
|
|||||||
@@ -422,7 +422,6 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
|
|||||||
Ray projection_ray;
|
Ray projection_ray;
|
||||||
projection_ray.self.light_object = OBJECT_NONE;
|
projection_ray.self.light_object = OBJECT_NONE;
|
||||||
projection_ray.self.light_prim = PRIM_NONE;
|
projection_ray.self.light_prim = PRIM_NONE;
|
||||||
projection_ray.self.light = LAMP_NONE;
|
|
||||||
projection_ray.dP = differential_make_compact(sd->dP);
|
projection_ray.dP = differential_make_compact(sd->dP);
|
||||||
projection_ray.dD = differential_zero_compact();
|
projection_ray.dD = differential_zero_compact();
|
||||||
projection_ray.tmin = 0.0f;
|
projection_ray.tmin = 0.0f;
|
||||||
@@ -866,7 +865,6 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
|
|||||||
Ray probe_ray;
|
Ray probe_ray;
|
||||||
probe_ray.self.light_object = ls->object;
|
probe_ray.self.light_object = ls->object;
|
||||||
probe_ray.self.light_prim = ls->prim;
|
probe_ray.self.light_prim = ls->prim;
|
||||||
probe_ray.self.light = ls->lamp;
|
|
||||||
probe_ray.tmin = 0.0f;
|
probe_ray.tmin = 0.0f;
|
||||||
probe_ray.dP = differential_make_compact(sd->dP);
|
probe_ray.dP = differential_make_compact(sd->dP);
|
||||||
probe_ray.dD = differential_zero_compact();
|
probe_ray.dD = differential_zero_compact();
|
||||||
@@ -915,7 +913,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
|
|||||||
wi_len,
|
wi_len,
|
||||||
sd->time,
|
sd->time,
|
||||||
false,
|
false,
|
||||||
LAMP_NONE);
|
false);
|
||||||
|
|
||||||
/* Set bounce info in case a light path node is used in the refractive interface
|
/* Set bounce info in case a light path node is used in the refractive interface
|
||||||
* shader graph. */
|
* 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.prim = sd->prim;
|
||||||
probe_ray.self.light_object = ls->object;
|
probe_ray.self.light_object = ls->object;
|
||||||
probe_ray.self.light_prim = ls->prim;
|
probe_ray.self.light_prim = ls->prim;
|
||||||
probe_ray.self.light = ls->lamp;
|
|
||||||
probe_ray.P = sd->P;
|
probe_ray.P = sd->P;
|
||||||
probe_ray.tmin = 0.0f;
|
probe_ray.tmin = 0.0f;
|
||||||
if (ls->t == FLT_MAX) {
|
if (ls->t == FLT_MAX) {
|
||||||
@@ -1100,7 +1097,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
|
|||||||
/* Distant or environment light. */
|
/* Distant or environment light. */
|
||||||
bool light_fixed_direction = (ls->t == FLT_MAX);
|
bool light_fixed_direction = (ls->t == FLT_MAX);
|
||||||
if (ls->type == LIGHT_AREA) {
|
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) {
|
if (klight->area.tan_half_spread == 0.0f) {
|
||||||
/* Area light with zero spread also has fixed direction. */
|
/* Area light with zero spread also has fixed direction. */
|
||||||
light_fixed_direction = true;
|
light_fixed_direction = true;
|
||||||
|
|||||||
@@ -138,15 +138,18 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
||||||
#ifdef __LIGHT_LINKING__
|
#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))
|
!(path_flag & PATH_RAY_CAMERA))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef __SHADOW_LINKING__
|
#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;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_CULL_LIGHT_CONNECTION) {
|
||||||
/* This path should have been resolved with mnee, it will
|
/* This path should have been resolved with mnee, it will
|
||||||
* generate a firefly for small lights since it is improbable. */
|
* generate a firefly for small lights since it is improbable. */
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
|
||||||
if (klight->use_caustics) {
|
if (klight->use_caustics) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.object = INTEGRATOR_STATE(state, shadow_link, last_isect_object);
|
||||||
ray->self.prim = INTEGRATOR_STATE(state, shadow_link, last_isect_prim);
|
ray->self.prim = INTEGRATOR_STATE(state, shadow_link, last_isect_prim);
|
||||||
|
|
||||||
if (isect->type == PRIMITIVE_LAMP) {
|
ray->self.light_object = isect->object;
|
||||||
ray->self.light_object = OBJECT_NONE;
|
ray->self.light_prim = isect->prim;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ccl_device bool shadow_linking_shade_light(KernelGlobals kg,
|
ccl_device bool shadow_linking_shade_light(KernelGlobals kg,
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg,
|
|||||||
ray.self.prim = PRIM_NONE;
|
ray.self.prim = PRIM_NONE;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
/* Modify ray position and length to match current segment. */
|
/* 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.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) :
|
ray.tmax = (hit < num_recorded_hits) ? INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) :
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "kernel/integrator/subsurface.h"
|
#include "kernel/integrator/subsurface.h"
|
||||||
#include "kernel/integrator/volume_stack.h"
|
#include "kernel/integrator/volume_stack.h"
|
||||||
|
|
||||||
|
#include "kernel/types.h"
|
||||||
#include "util/math_intersect.h"
|
#include "util/math_intersect.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
@@ -348,9 +349,9 @@ ccl_device
|
|||||||
#ifdef __MNEE__
|
#ifdef __MNEE__
|
||||||
IF_KERNEL_FEATURE(MNEE)
|
IF_KERNEL_FEATURE(MNEE)
|
||||||
{
|
{
|
||||||
if (ls.lamp != LAMP_NONE) {
|
if (ls.type != LIGHT_TRIANGLE) {
|
||||||
/* Is this a caustic light? */
|
/* 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) {
|
if (use_caustics) {
|
||||||
/* Are we on a caustic caster? */
|
/* Are we on a caustic caster? */
|
||||||
if (is_transmission && (sd->object_flag & SD_OBJECT_CAUSTICS_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.prim = (skip_self) ? sd->prim : PRIM_NONE;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
ray.dP = differential_zero_compact();
|
ray.dP = differential_zero_compact();
|
||||||
ray.dD = differential_zero_compact();
|
ray.dD = differential_zero_compact();
|
||||||
|
|
||||||
|
|||||||
@@ -337,11 +337,11 @@ ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg,
|
|||||||
const ccl_private LightSample *ls)
|
const ccl_private LightSample *ls)
|
||||||
{
|
{
|
||||||
if (ls->type == LIGHT_SPOT) {
|
if (ls->type == LIGHT_SPOT) {
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
|
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim);
|
||||||
return spot_light_valid_ray_segment(klight, ray_P, ray_D, t_range);
|
return spot_light_valid_ray_segment(kg, klight, ray_P, ray_D, t_range);
|
||||||
}
|
}
|
||||||
if (ls->type == LIGHT_AREA) {
|
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);
|
return area_light_valid_ray_segment(&klight->area, ray_P - klight->co, ray_D, t_range);
|
||||||
}
|
}
|
||||||
if (ls->type == LIGHT_TRIANGLE) {
|
if (ls->type == LIGHT_TRIANGLE) {
|
||||||
|
|||||||
@@ -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, tmax, KERNEL_FEATURE_PATH_TRACING)
|
||||||
KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, float, time, 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, float, dP, KERNEL_FEATURE_PATH_TRACING)
|
||||||
KERNEL_STRUCT_MEMBER_PACKED(shadow_ray, int, self_light, KERNEL_FEATURE_SHADOW_LINKING)
|
|
||||||
KERNEL_STRUCT_END(shadow_ray)
|
KERNEL_STRUCT_END(shadow_ray)
|
||||||
|
|
||||||
/*********************** Shadow Intersection result **************************/
|
/*********************** Shadow Intersection result **************************/
|
||||||
|
|||||||
@@ -98,10 +98,6 @@ ccl_device_forceinline void integrator_state_read_shadow_ray(ConstIntegratorShad
|
|||||||
ccl_device_forceinline void integrator_state_write_shadow_ray_self(
|
ccl_device_forceinline void integrator_state_write_shadow_ray_self(
|
||||||
KernelGlobals kg, IntegratorShadowState state, const ccl_private Ray *ccl_restrict ray)
|
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. */
|
/* 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
|
/* 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
|
* 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(
|
ccl_device_forceinline void integrator_state_read_shadow_ray_self(
|
||||||
KernelGlobals kg, ConstIntegratorShadowState state, ccl_private Ray *ccl_restrict ray)
|
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.object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, object);
|
||||||
ray->self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim);
|
ray->self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim);
|
||||||
ray->self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object);
|
ray->self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object);
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
|
|||||||
ray.self.prim = PRIM_NONE;
|
ray.self.prim = PRIM_NONE;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
/* Intersect with the same object. if multiple intersections are found it
|
/* 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. */
|
* will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */
|
||||||
|
|||||||
@@ -199,7 +199,6 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
|
|||||||
ray.self.prim = prim;
|
ray.self.prim = prim;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
/* Convert subsurface to volume coefficients.
|
/* Convert subsurface to volume coefficients.
|
||||||
* The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */
|
* The single-scattering albedo is named alpha to avoid confusion with the surface albedo. */
|
||||||
|
|||||||
@@ -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
|
/* Setup shader-data from stack. It's mostly setup already in shader_setup_from_volume, this
|
||||||
* switching should be quick. */
|
* switching should be quick. */
|
||||||
sd->object = entry.object;
|
sd->object = entry.object;
|
||||||
sd->lamp = LAMP_NONE;
|
|
||||||
sd->shader = entry.shader;
|
sd->shader = entry.shader;
|
||||||
|
|
||||||
sd->flag &= ~SD_SHADER_FLAGS;
|
sd->flag &= ~SD_SHADER_FLAGS;
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ struct LightSample {
|
|||||||
float pdf_selection; /* pdf for selecting light */
|
float pdf_selection; /* pdf for selecting light */
|
||||||
float eval_fac; /* intensity multiplier */
|
float eval_fac; /* intensity multiplier */
|
||||||
int object; /* object id for triangle/curve lights */
|
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 shader; /* shader id */
|
||||||
int lamp; /* lamp id */
|
|
||||||
int group; /* lightgroup */
|
int group; /* lightgroup */
|
||||||
LightType type; /* type of light */
|
LightType type; /* type of light */
|
||||||
int emitter_id; /* index in the emitter array */
|
int emitter_id; /* index in the emitter array */
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
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,
|
const float3 D,
|
||||||
ccl_private float *u,
|
ccl_private float *u,
|
||||||
ccl_private float *v)
|
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);
|
const float fac = klight->distant.half_inv_sin_half_angle / len(D - klight->co);
|
||||||
|
|
||||||
/* Get u axis and v axis. */
|
/* 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 u_ = dot(D, make_float3(itfm.x)) * fac;
|
||||||
const float v_ = dot(D, make_float3(itfm.y)) * 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_;
|
*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,
|
const float2 rand,
|
||||||
ccl_private LightSample *ls)
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -114,19 +116,18 @@ ccl_device bool distant_light_sample_from_intersection(KernelGlobals kg,
|
|||||||
#ifndef __HIP__
|
#ifndef __HIP__
|
||||||
ls->shader = klight->shader_id;
|
ls->shader = klight->shader_id;
|
||||||
#endif
|
#endif
|
||||||
ls->object = PRIM_NONE;
|
ls->object = klight->object_id;
|
||||||
ls->prim = PRIM_NONE;
|
ls->prim = lamp;
|
||||||
ls->lamp = lamp;
|
|
||||||
ls->t = FLT_MAX;
|
ls->t = FLT_MAX;
|
||||||
ls->P = -ray_D;
|
ls->P = -ray_D;
|
||||||
ls->Ng = -ray_D;
|
ls->Ng = -ray_D;
|
||||||
ls->D = 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->pdf = klight->distant.pdf;
|
||||||
ls->eval_fac = klight->distant.eval_fac;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "kernel/geom/object.h"
|
||||||
#include "kernel/globals.h"
|
#include "kernel/globals.h"
|
||||||
|
|
||||||
#include "kernel/integrator/state.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,
|
ccl_device_inline bool light_link_light_match(KernelGlobals kg,
|
||||||
const int object_receiver,
|
const int object_receiver,
|
||||||
const int light_emitter)
|
const int object_emitter)
|
||||||
{
|
{
|
||||||
#ifdef __LIGHT_LINKING__
|
#ifdef __LIGHT_LINKING__
|
||||||
if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
|
if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
|
||||||
return true;
|
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) ?
|
const uint receiver_set = (object_receiver != OBJECT_NONE) ?
|
||||||
kernel_data_fetch(objects, object_receiver).receiver_light_set :
|
kernel_data_fetch(objects, object_receiver).receiver_light_set :
|
||||||
0;
|
0;
|
||||||
@@ -122,12 +123,11 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
|||||||
const LightType type = (LightType)klight->type;
|
const LightType type = (LightType)klight->type;
|
||||||
ls->type = type;
|
ls->type = type;
|
||||||
ls->shader = klight->shader_id;
|
ls->shader = klight->shader_id;
|
||||||
ls->object = PRIM_NONE;
|
ls->object = klight->object_id;
|
||||||
ls->prim = PRIM_NONE;
|
ls->prim = lamp;
|
||||||
ls->lamp = lamp;
|
|
||||||
ls->u = rand.x;
|
ls->u = rand.x;
|
||||||
ls->v = rand.y;
|
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)) {
|
if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) {
|
||||||
/* Distant lights in a volume get a dummy sample, position will not actually
|
/* 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 (type == LIGHT_DISTANT) {
|
||||||
if (!distant_light_sample(klight, rand, ls)) {
|
if (!distant_light_sample(kg, klight, rand, ls)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,12 +158,12 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
|
|||||||
ls->eval_fac = 1.0f;
|
ls->eval_fac = 1.0f;
|
||||||
}
|
}
|
||||||
else if (type == LIGHT_SPOT) {
|
else if (type == LIGHT_SPOT) {
|
||||||
if (!spot_light_sample<in_volume_segment>(klight, rand, P, N, shader_flags, ls)) {
|
if (!spot_light_sample<in_volume_segment>(kg, klight, rand, P, N, shader_flags, ls)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == LIGHT_POINT) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,14 +196,15 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
|||||||
const float2 rand = make_float2(rand_light);
|
const float2 rand = make_float2(rand_light);
|
||||||
|
|
||||||
int prim;
|
int prim;
|
||||||
MeshLight mesh_light;
|
int shader_flag;
|
||||||
|
int object_id;
|
||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
if (kernel_data.integrator.use_light_tree) {
|
if (kernel_data.integrator.use_light_tree) {
|
||||||
const ccl_global KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
const ccl_global KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
|
||||||
ls->emitter_id);
|
ls->emitter_id);
|
||||||
prim = kemitter->light.id;
|
prim = kemitter->light.id;
|
||||||
mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
|
shader_flag = kemitter->shader_flag;
|
||||||
mesh_light.object_id = ls->object;
|
object_id = (prim >= 0) ? ls->object : kemitter->object_id;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@@ -211,26 +212,25 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
|||||||
const ccl_global KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
const ccl_global KernelLightDistribution *kdistribution = &kernel_data_fetch(
|
||||||
light_distribution, ls->emitter_id);
|
light_distribution, ls->emitter_id);
|
||||||
prim = kdistribution->prim;
|
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) {
|
if (prim >= 0) {
|
||||||
/* Mesh light. */
|
/* 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. */
|
/* Exclude synthetic meshes from shadow catcher pass. */
|
||||||
if ((path_flag & PATH_RAY_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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int shader_flag = mesh_light.shader_flag;
|
if (!triangle_light_sample<in_volume_segment>(kg, prim, object_id, rand, time, ls, P)) {
|
||||||
if (!triangle_light_sample<in_volume_segment>(kg, prim, object, rand, time, ls, P)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ls->shader |= shader_flag;
|
ls->shader |= shader_flag;
|
||||||
@@ -238,10 +238,6 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
|
|||||||
else {
|
else {
|
||||||
const int light = ~prim;
|
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))) {
|
if (UNLIKELY(light_select_reached_max_bounces(kg, light, bounce))) {
|
||||||
return false;
|
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++) {
|
for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) {
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(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 (path_flag & PATH_RAY_CAMERA) {
|
||||||
if (klight->shader_id & SHADER_EXCLUDE_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 (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) {
|
||||||
if (is_main_path) {
|
if (is_main_path) {
|
||||||
if (is_indirect_ray &&
|
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;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,7 +322,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
|
|||||||
|
|
||||||
#ifdef __LIGHT_LINKING__
|
#ifdef __LIGHT_LINKING__
|
||||||
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -363,7 +360,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Avoid self-intersections. */
|
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +388,7 @@ ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg,
|
|||||||
isect->v = v;
|
isect->v = v;
|
||||||
isect->type = PRIMITIVE_LAMP;
|
isect->type = PRIMITIVE_LAMP;
|
||||||
isect->prim = lamp;
|
isect->prim = lamp;
|
||||||
isect->object = OBJECT_NONE;
|
isect->object = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_hits;
|
return num_hits;
|
||||||
@@ -465,26 +462,24 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
|
|||||||
const uint32_t path_flag,
|
const uint32_t path_flag,
|
||||||
ccl_private LightSample *ccl_restrict ls)
|
ccl_private LightSample *ccl_restrict ls)
|
||||||
{
|
{
|
||||||
const int lamp = isect->prim;
|
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, isect->prim);
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
|
|
||||||
const LightType type = (LightType)klight->type;
|
const LightType type = (LightType)klight->type;
|
||||||
ls->type = type;
|
ls->type = type;
|
||||||
ls->shader = klight->shader_id;
|
ls->shader = klight->shader_id;
|
||||||
ls->object = isect->object;
|
ls->object = isect->object;
|
||||||
ls->prim = isect->prim;
|
ls->prim = isect->prim;
|
||||||
ls->lamp = lamp;
|
|
||||||
ls->t = isect->t;
|
ls->t = isect->t;
|
||||||
ls->P = ray_P + ray_D * ls->t;
|
ls->P = ray_P + ray_D * ls->t;
|
||||||
ls->D = ray_D;
|
ls->D = ray_D;
|
||||||
ls->group = lamp_lightgroup(kg, lamp);
|
ls->group = object_lightgroup(kg, ls->object);
|
||||||
|
|
||||||
if (type == LIGHT_SPOT) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == LIGHT_POINT) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "kernel/globals.h"
|
||||||
|
|
||||||
#include "kernel/light/common.h"
|
#include "kernel/light/common.h"
|
||||||
|
|
||||||
#include "util/math_intersect.h"
|
#include "util/math_intersect.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
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 float2 rand,
|
||||||
const float3 P,
|
const float3 P,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -72,7 +75,7 @@ ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Texture coordinates. */
|
/* 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));
|
const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
|
||||||
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
||||||
ls->u = uv.y;
|
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);
|
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,
|
ccl_private LightSample *ls,
|
||||||
const float3 P,
|
const float3 P,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -122,7 +126,7 @@ ccl_device_forceinline void point_light_mnee_sample_update(const ccl_global Kern
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Texture coordinates. */
|
/* 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));
|
const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
|
||||||
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
||||||
ls->u = uv.y;
|
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);
|
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_P,
|
||||||
const float3 ray_D,
|
const float3 ray_D,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -179,7 +184,7 @@ ccl_device_inline bool point_light_sample_from_intersection(const ccl_global Ker
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Texture coordinates. */
|
/* 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));
|
const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
|
||||||
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
||||||
ls->u = uv.y;
|
ls->u = uv.y;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "kernel/light/distribution.h"
|
#include "kernel/light/distribution.h"
|
||||||
#include "kernel/light/light.h"
|
#include "kernel/light/light.h"
|
||||||
|
#include "kernel/types.h"
|
||||||
|
|
||||||
#ifdef __LIGHT_TREE__
|
#ifdef __LIGHT_TREE__
|
||||||
# include "kernel/light/tree.h"
|
# include "kernel/light/tree.h"
|
||||||
@@ -56,7 +57,7 @@ light_sample_shader_eval(KernelGlobals kg,
|
|||||||
ls->t,
|
ls->t,
|
||||||
time,
|
time,
|
||||||
false,
|
false,
|
||||||
ls->lamp);
|
ls->type != LIGHT_TRIANGLE);
|
||||||
|
|
||||||
ls->Ng = emission_sd->Ng;
|
ls->Ng = emission_sd->Ng;
|
||||||
}
|
}
|
||||||
@@ -80,8 +81,8 @@ light_sample_shader_eval(KernelGlobals kg,
|
|||||||
|
|
||||||
eval *= ls->eval_fac;
|
eval *= ls->eval_fac;
|
||||||
|
|
||||||
if (ls->lamp != LAMP_NONE) {
|
if (ls->type != LIGHT_TRIANGLE) {
|
||||||
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
|
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->prim);
|
||||||
eval *= rgb_to_spectrum(
|
eval *= rgb_to_spectrum(
|
||||||
make_float3(klight->strength[0], klight->strength[1], klight->strength[2]));
|
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.prim = (skip_self) ? sd->prim : PRIM_NONE;
|
||||||
ray->self.light_object = ls->object;
|
ray->self.light_object = ls->object;
|
||||||
ray->self.light_prim = ls->prim;
|
ray->self.light_prim = ls->prim;
|
||||||
ray->self.light = ls->lamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create shadow ray towards light sample. */
|
/* Create shadow ray towards light sample. */
|
||||||
@@ -392,13 +392,13 @@ ccl_device_forceinline void light_sample_update(KernelGlobals kg,
|
|||||||
const float3 N,
|
const float3 N,
|
||||||
const uint32_t path_flag)
|
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) {
|
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) {
|
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) {
|
else if (ls->type == LIGHT_AREA) {
|
||||||
area_light_mnee_sample_update(klight, ls, P);
|
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,
|
dt,
|
||||||
path_flag,
|
path_flag,
|
||||||
0,
|
0,
|
||||||
kernel_data_fetch(light_to_tree, ls->lamp),
|
kernel_data_fetch(light_to_tree, ls->prim),
|
||||||
light_link_receiver_forward(kg, state));
|
light_link_receiver_forward(kg, state));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/* Transform vector to spot light's local coordinate system. */
|
/* 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));
|
float3 transformed_ray = safe_normalize(transform_direction(&itfm, ray));
|
||||||
transformed_ray.z = -transformed_ray.z;
|
transformed_ray.z = -transformed_ray.z;
|
||||||
|
|
||||||
@@ -42,7 +44,8 @@ ccl_device void spot_light_uv(const float3 ray,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<bool in_volume_segment>
|
template<bool in_volume_segment>
|
||||||
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 float2 rand,
|
||||||
const float3 P,
|
const float3 P,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -98,7 +101,7 @@ ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attenuation. */
|
/* 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) {
|
if (d_sq > r_sq) {
|
||||||
ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
|
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;
|
ls->Ng = -ls->D;
|
||||||
|
|
||||||
/* Attenuation. */
|
/* 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);
|
ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
|
||||||
if (!in_volume_segment && ls->eval_fac == 0.0f) {
|
if (!in_volume_segment && ls->eval_fac == 0.0f) {
|
||||||
return false;
|
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);
|
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,
|
ccl_private LightSample *ls,
|
||||||
const float3 P,
|
const float3 P,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -203,7 +207,7 @@ ccl_device_forceinline void spot_light_mnee_sample_update(const ccl_global Kerne
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attenuation. */
|
/* 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) {
|
if (use_attenuation) {
|
||||||
ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
|
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);
|
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_P,
|
||||||
const float3 ray_D,
|
const float3 ray_D,
|
||||||
const float3 N,
|
const float3 N,
|
||||||
@@ -254,7 +259,7 @@ ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global Kern
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Attenuation. */
|
/* 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) {
|
if (!klight->spot.is_sphere || d_sq > r_sq) {
|
||||||
ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
|
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. */
|
/* 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 P,
|
||||||
const float3 D,
|
const float3 D,
|
||||||
ccl_private Interval<float> *t_range)
|
ccl_private Interval<float> *t_range)
|
||||||
{
|
{
|
||||||
/* Convert to local space of the spot light. */
|
/* 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;
|
float3 local_P = P + klight->spot.dir * klight->spot.ray_segment_dp;
|
||||||
local_P = transform_point(&itfm, local_P);
|
local_P = transform_point(&itfm, local_P);
|
||||||
const float3 local_D = transform_direction(&itfm, D);
|
const float3 local_D = transform_direction(&itfm, D);
|
||||||
|
|||||||
@@ -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)
|
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)
|
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)
|
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 {
|
else {
|
||||||
kernel_assert(is_triangle(kemitter));
|
kernel_assert(is_triangle(kemitter));
|
||||||
const int object = kemitter->mesh_light.object_id;
|
const int object = kemitter->object_id;
|
||||||
float3 vertices[3];
|
float3 vertices[3];
|
||||||
triangle_vertices(kg, kemitter->triangle.id, vertices);
|
triangle_vertices(kg, kemitter->triangle.id, vertices);
|
||||||
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
|
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
|
|||||||
ls->eval_fac = 1.0f;
|
ls->eval_fac = 1.0f;
|
||||||
ls->object = object;
|
ls->object = object;
|
||||||
ls->prim = prim;
|
ls->prim = prim;
|
||||||
ls->lamp = LAMP_NONE;
|
|
||||||
ls->shader |= SHADER_USE_MIS;
|
ls->shader |= SHADER_USE_MIS;
|
||||||
ls->type = LIGHT_TRIANGLE;
|
ls->type = LIGHT_TRIANGLE;
|
||||||
ls->group = object_lightgroup(kg, object);
|
ls->group = object_lightgroup(kg, object);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ void osl_eval_nodes<SHADER_TYPE_SURFACE>(const ThreadKernelGlobalsCPU *kg,
|
|||||||
OSL::ShadingContext *octx = kg->osl.context;
|
OSL::ShadingContext *octx = kg->osl.context;
|
||||||
const int shader = sd->shader & SHADER_MASK;
|
const int shader = sd->shader & SHADER_MASK;
|
||||||
|
|
||||||
if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) {
|
if (sd->object == OBJECT_NONE) {
|
||||||
/* background */
|
/* background */
|
||||||
if (kg->osl.globals->background_state) {
|
if (kg->osl.globals->background_state) {
|
||||||
ss->execute(*octx,
|
ss->execute(*octx,
|
||||||
|
|||||||
@@ -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_geom_dupli_uv("geom:dupli_uv");
|
||||||
ustring OSLRenderServices::u_material_index("material:index");
|
ustring OSLRenderServices::u_material_index("material:index");
|
||||||
ustring OSLRenderServices::u_object_random("object:random");
|
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_index("particle:index");
|
||||||
ustring OSLRenderServices::u_particle_random("particle:random");
|
ustring OSLRenderServices::u_particle_random("particle:random");
|
||||||
ustring OSLRenderServices::u_particle_age("particle:age");
|
ustring OSLRenderServices::u_particle_age("particle:age");
|
||||||
@@ -177,12 +176,6 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
|
|||||||
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -221,12 +214,6 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
|
|||||||
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -317,12 +304,6 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg,
|
|||||||
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -349,12 +330,6 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg,
|
|||||||
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -754,10 +729,6 @@ bool OSLRenderServices::get_object_standard_attribute(
|
|||||||
const float f = object_random_number(kg, sd->object);
|
const float f = object_random_number(kg, sd->object);
|
||||||
return set_attribute(f, type, derivatives, val);
|
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 */
|
/* Particle Attributes */
|
||||||
if (name == u_particle_index) {
|
if (name == u_particle_index) {
|
||||||
@@ -1571,7 +1542,6 @@ bool OSLRenderServices::trace(TraceOpt &options,
|
|||||||
ray.self.prim = PRIM_NONE;
|
ray.self.prim = PRIM_NONE;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
if (options.mindist == 0.0f) {
|
if (options.mindist == 0.0f) {
|
||||||
/* avoid self-intersections */
|
/* avoid self-intersections */
|
||||||
|
|||||||
@@ -275,7 +275,6 @@ class OSLRenderServices : public OSL::RendererServices {
|
|||||||
static ustring u_geom_dupli_uv;
|
static ustring u_geom_dupli_uv;
|
||||||
static ustring u_material_index;
|
static ustring u_material_index;
|
||||||
static ustring u_object_random;
|
static ustring u_object_random;
|
||||||
static ustring u_light_random;
|
|
||||||
static ustring u_particle_index;
|
static ustring u_particle_index;
|
||||||
static ustring u_particle_random;
|
static ustring u_particle_random;
|
||||||
static ustring u_particle_age;
|
static ustring u_particle_age;
|
||||||
|
|||||||
@@ -80,8 +80,6 @@ ccl_device_constant DeviceString u_geom_dupli_uv = 1294253317490155849ull;
|
|||||||
ccl_device_constant DeviceString u_material_index = 741770758159634623ull;
|
ccl_device_constant DeviceString u_material_index = 741770758159634623ull;
|
||||||
/* "object:random" */
|
/* "object:random" */
|
||||||
ccl_device_constant DeviceString u_object_random = 15789063994977955884ull;
|
ccl_device_constant DeviceString u_object_random = 15789063994977955884ull;
|
||||||
/* "light:random" */
|
|
||||||
ccl_device_constant DeviceString u_light_random = 1743557801140685447ull;
|
|
||||||
/* "particle:index" */
|
/* "particle:index" */
|
||||||
ccl_device_constant DeviceString u_particle_index = 9489711748229903784ull;
|
ccl_device_constant DeviceString u_particle_index = 9489711748229903784ull;
|
||||||
/* "particle:random" */
|
/* "particle:random" */
|
||||||
@@ -628,11 +626,6 @@ ccl_device_extern bool osl_get_matrix(ccl_private ShaderGlobals *sg,
|
|||||||
copy_matrix(res, tfm);
|
copy_matrix(res, tfm);
|
||||||
return true;
|
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) {
|
else if (from == DeviceStrings::u_ndc) {
|
||||||
copy_matrix(res, kernel_data.cam.ndctoworld);
|
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);
|
copy_matrix(res, itfm);
|
||||||
return true;
|
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) {
|
else if (to == DeviceStrings::u_ndc) {
|
||||||
copy_matrix(res, kernel_data.cam.worldtondc);
|
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);
|
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 */
|
/* Particle attributes */
|
||||||
else if (name == DeviceStrings::u_particle_index) {
|
else if (name == DeviceStrings::u_particle_index) {
|
||||||
|
|||||||
@@ -16,13 +16,5 @@ shader node_object_info(output point Location = point(0.0, 0.0, 0.0),
|
|||||||
getattribute("object:alpha", Alpha);
|
getattribute("object:alpha", Alpha);
|
||||||
getattribute("object:index", ObjectIndex);
|
getattribute("object:index", ObjectIndex);
|
||||||
getattribute("material:index", MaterialIndex);
|
getattribute("material:index", MaterialIndex);
|
||||||
|
getattribute("object:random", Random);
|
||||||
float is_light;
|
|
||||||
getattribute("object:is_light", is_light);
|
|
||||||
if (is_light) {
|
|
||||||
getattribute("light:random", Random);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
getattribute("object:random", Random);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ ccl_device float svm_ao(
|
|||||||
ray.self.prim = sd->prim;
|
ray.self.prim = sd->prim;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
ray.dP = differential_zero_compact();
|
ray.dP = differential_zero_compact();
|
||||||
ray.dD = differential_zero_compact();
|
ray.dD = differential_zero_compact();
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,6 @@ ccl_device float3 svm_bevel(
|
|||||||
ray.self.prim = PRIM_NONE;
|
ray.self.prim = PRIM_NONE;
|
||||||
ray.self.light_object = OBJECT_NONE;
|
ray.self.light_object = OBJECT_NONE;
|
||||||
ray.self.light_prim = PRIM_NONE;
|
ray.self.light_prim = PRIM_NONE;
|
||||||
ray.self.light = LAMP_NONE;
|
|
||||||
|
|
||||||
/* Intersect with the same object. if multiple intersections are found it
|
/* 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. */
|
* will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
|
||||||
|
|||||||
@@ -141,12 +141,7 @@ ccl_device_noinline void svm_node_object_info(KernelGlobals kg,
|
|||||||
data = shader_pass_id(kg, sd);
|
data = shader_pass_id(kg, sd);
|
||||||
break;
|
break;
|
||||||
case NODE_INFO_OB_RANDOM: {
|
case NODE_INFO_OB_RANDOM: {
|
||||||
if (sd->lamp != LAMP_NONE) {
|
data = object_random_number(kg, sd->object);
|
||||||
data = lamp_random_number(kg, sd->lamp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data = object_random_number(kg, sd->object);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg,
|
|||||||
const NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito;
|
const NodeVectorTransformConvertSpace to = (NodeVectorTransformConvertSpace)ito;
|
||||||
|
|
||||||
Transform tfm;
|
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_normal = (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
|
||||||
const bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
|
const bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
|
||||||
|
|
||||||
|
|||||||
@@ -724,7 +724,6 @@ struct RaySelfPrimitives {
|
|||||||
int object; /* Instance prim is a part of */
|
int object; /* Instance prim is a part of */
|
||||||
int light_prim; /* Light primitive */
|
int light_prim; /* Light primitive */
|
||||||
int light_object; /* Light object */
|
int light_object; /* Light object */
|
||||||
int light; /* Light ID (the light the shadow ray is traced towards to) */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ray {
|
struct Ray {
|
||||||
@@ -1151,8 +1150,6 @@ struct ccl_align(16) ShaderData
|
|||||||
float v;
|
float v;
|
||||||
/* object id if there is one, ~0 otherwise */
|
/* object id if there is one, ~0 otherwise */
|
||||||
int object;
|
int object;
|
||||||
/* lamp id if there is one, ~0 otherwise */
|
|
||||||
int lamp;
|
|
||||||
|
|
||||||
/* motion blur sample time */
|
/* motion blur sample time */
|
||||||
float time;
|
float time;
|
||||||
@@ -1606,32 +1603,24 @@ struct KernelLight {
|
|||||||
int type;
|
int type;
|
||||||
packed_float3 co;
|
packed_float3 co;
|
||||||
int shader_id;
|
int shader_id;
|
||||||
|
int object_id;
|
||||||
float max_bounces;
|
float max_bounces;
|
||||||
float random;
|
|
||||||
float strength[3];
|
float strength[3];
|
||||||
int use_caustics;
|
int use_caustics;
|
||||||
int lightgroup;
|
int pad;
|
||||||
Transform tfm;
|
|
||||||
Transform itfm;
|
|
||||||
union {
|
union {
|
||||||
KernelSpotLight spot;
|
KernelSpotLight spot;
|
||||||
KernelAreaLight area;
|
KernelAreaLight area;
|
||||||
KernelDistantLight distant;
|
KernelDistantLight distant;
|
||||||
};
|
};
|
||||||
uint64_t light_set_membership;
|
|
||||||
uint64_t shadow_set_membership;
|
|
||||||
};
|
};
|
||||||
static_assert_align(KernelLight, 16);
|
static_assert_align(KernelLight, 16);
|
||||||
|
|
||||||
struct MeshLight {
|
|
||||||
int shader_flag;
|
|
||||||
int object_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KernelLightDistribution {
|
struct KernelLightDistribution {
|
||||||
float totarea;
|
float totarea;
|
||||||
int prim;
|
int prim;
|
||||||
MeshLight mesh_light;
|
int shader_flag;
|
||||||
|
int object_id;
|
||||||
};
|
};
|
||||||
static_assert_align(KernelLightDistribution, 16);
|
static_assert_align(KernelLightDistribution, 16);
|
||||||
|
|
||||||
@@ -1718,7 +1707,9 @@ struct KernelLightTreeEmitter {
|
|||||||
} mesh;
|
} mesh;
|
||||||
};
|
};
|
||||||
|
|
||||||
MeshLight mesh_light;
|
/* Object and shader. */
|
||||||
|
int object_id;
|
||||||
|
int shader_flag;
|
||||||
|
|
||||||
/* Bit trail from root node to leaf node containing emitter. */
|
/* Bit trail from root node to leaf node containing emitter. */
|
||||||
int bit_trail;
|
int bit_trail;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class Geometry : public Node {
|
|||||||
HAIR,
|
HAIR,
|
||||||
VOLUME,
|
VOLUME,
|
||||||
POINTCLOUD,
|
POINTCLOUD,
|
||||||
|
LIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type geometry_type;
|
Type geometry_type;
|
||||||
@@ -185,6 +186,11 @@ class Geometry : public Node {
|
|||||||
return geometry_type == VOLUME;
|
return geometry_type == VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_light() const
|
||||||
|
{
|
||||||
|
return geometry_type == LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates */
|
/* Updates */
|
||||||
void tag_update(Scene *scene, bool rebuild);
|
void tag_update(Scene *scene, bool rebuild);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ static void shade_background_pixels(Device *device,
|
|||||||
|
|
||||||
NODE_DEFINE(Light)
|
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;
|
static NodeEnum type_enum;
|
||||||
type_enum.insert("point", LIGHT_POINT);
|
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_angle, "Spot Angle", M_PI_4_F);
|
||||||
SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
|
SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
|
||||||
|
|
||||||
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
|
|
||||||
|
|
||||||
SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
|
SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
|
||||||
SOCKET_BOOLEAN(use_mis, "Use Mis", false);
|
SOCKET_BOOLEAN(use_mis, "Use Mis", false);
|
||||||
SOCKET_BOOLEAN(use_camera, "Use Camera", true);
|
SOCKET_BOOLEAN(use_camera, "Use Camera", true);
|
||||||
@@ -124,24 +122,17 @@ NODE_DEFINE(Light)
|
|||||||
SOCKET_BOOLEAN(use_caustics, "Shadow Caustics", false);
|
SOCKET_BOOLEAN(use_caustics, "Shadow Caustics", false);
|
||||||
|
|
||||||
SOCKET_INT(max_bounces, "Max Bounces", 1024);
|
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_shadow_catcher, "Shadow Catcher", true);
|
||||||
SOCKET_BOOLEAN(is_portal, "Is Portal", false);
|
SOCKET_BOOLEAN(is_portal, "Is Portal", false);
|
||||||
SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
|
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);
|
SOCKET_BOOLEAN(normalize, "Normalize", true);
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Light::Light() : Node(get_node_type())
|
Light::Light() : Geometry(get_node_type(), Geometry::LIGHT)
|
||||||
{
|
{
|
||||||
dereference_all_used_nodes();
|
dereference_all_used_nodes();
|
||||||
}
|
}
|
||||||
@@ -165,46 +156,33 @@ bool Light::has_contribution(Scene *scene)
|
|||||||
return true;
|
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);
|
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 (used_shaders.empty()) ? nullptr : static_cast<Shader *>(used_shaders[0]);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Light::has_shadow_linking() const
|
void Light::compute_bounds()
|
||||||
{
|
{
|
||||||
if (get_shadow_set_membership() != LIGHT_LINK_MASK_ALL) {
|
/* To be implemented when this becomes actual geometry. */
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<int> & /*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);
|
return PRIMITIVE_LAMP;
|
||||||
}
|
|
||||||
|
|
||||||
float3 Light::get_axisv() const
|
|
||||||
{
|
|
||||||
return transform_get_column(&tfm, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Light Manager */
|
/* Light Manager */
|
||||||
@@ -219,7 +197,12 @@ LightManager::LightManager()
|
|||||||
|
|
||||||
bool LightManager::has_background_light(Scene *scene)
|
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<Light *>(object->get_geometry());
|
||||||
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
||||||
return true;
|
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
|
* needed for finer-tuning of settings (for example, check whether we've
|
||||||
* got portals or not).
|
* got portals or not).
|
||||||
*/
|
*/
|
||||||
|
vector<Light *> background_lights;
|
||||||
|
size_t num_lights = 0;
|
||||||
bool has_portal = false;
|
bool has_portal = false;
|
||||||
bool has_background = false;
|
for (Object *object : scene->objects) {
|
||||||
for (Light *light : scene->lights) {
|
if (!object->get_geometry()->is_light()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Light *light = static_cast<Light *>(object->get_geometry());
|
||||||
light->is_enabled = light->has_contribution(scene);
|
light->is_enabled = light->has_contribution(scene);
|
||||||
has_portal |= light->is_portal;
|
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;
|
bool background_enabled = false;
|
||||||
int background_resolution = 0;
|
int background_resolution = 0;
|
||||||
|
|
||||||
if (has_background) {
|
if (!background_lights.empty()) {
|
||||||
/* Ignore background light if:
|
/* Ignore background light if:
|
||||||
* - If unsupported on a device
|
* - If unsupported on a device
|
||||||
* - If we don't need it (no HDRs etc.)
|
* - If we don't need it (no HDRs etc.)
|
||||||
@@ -254,12 +250,10 @@ void LightManager::test_enabled_lights(Scene *scene)
|
|||||||
if (disable_mis) {
|
if (disable_mis) {
|
||||||
VLOG_INFO << "Background MIS has been disabled.\n";
|
VLOG_INFO << "Background MIS has been disabled.\n";
|
||||||
}
|
}
|
||||||
for (Light *light : scene->lights) {
|
for (Light *light : background_lights) {
|
||||||
if (light->light_type == LIGHT_BACKGROUND) {
|
light->is_enabled = !disable_mis;
|
||||||
light->is_enabled = !disable_mis;
|
background_enabled = !disable_mis;
|
||||||
background_enabled = !disable_mis;
|
background_resolution = light->map_resolution;
|
||||||
background_resolution = light->map_resolution;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +329,6 @@ void LightManager::device_update_distribution(Device * /*unused*/,
|
|||||||
|
|
||||||
/* Triangles. */
|
/* Triangles. */
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
for (Object *object : scene->objects) {
|
for (Object *object : scene->objects) {
|
||||||
if (progress.get_cancel()) {
|
if (progress.get_cancel()) {
|
||||||
@@ -343,14 +336,12 @@ void LightManager::device_update_distribution(Device * /*unused*/,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!object->usable_as_light()) {
|
if (!object->usable_as_light()) {
|
||||||
j++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Sum area. */
|
/* Sum area. */
|
||||||
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
||||||
const bool transform_applied = mesh->transform_applied;
|
const bool transform_applied = mesh->transform_applied;
|
||||||
const Transform tfm = object->get_tfm();
|
const Transform tfm = object->get_tfm();
|
||||||
const int object_id = j;
|
|
||||||
int shader_flag = 0;
|
int shader_flag = 0;
|
||||||
|
|
||||||
if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
|
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) {
|
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
|
||||||
distribution[offset].totarea = totarea;
|
distribution[offset].totarea = totarea;
|
||||||
distribution[offset].prim = i + mesh->prim_offset;
|
distribution[offset].prim = i + mesh->prim_offset;
|
||||||
distribution[offset].mesh_light.shader_flag = shader_flag;
|
distribution[offset].shader_flag = shader_flag;
|
||||||
distribution[offset].mesh_light.object_id = object_id;
|
distribution[offset].object_id = object->index;
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
const Mesh::Triangle t = mesh->get_triangle(i);
|
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);
|
totarea += triangle_area(p1, p2, p3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float trianglearea = totarea;
|
const float trianglearea = totarea;
|
||||||
@@ -414,15 +403,20 @@ void LightManager::device_update_distribution(Device * /*unused*/,
|
|||||||
|
|
||||||
if (num_lights > 0) {
|
if (num_lights > 0) {
|
||||||
const float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
|
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<Light *>(object->get_geometry());
|
||||||
if (!light->is_enabled) {
|
if (!light->is_enabled) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
distribution[offset].totarea = totarea;
|
distribution[offset].totarea = totarea;
|
||||||
distribution[offset].prim = ~light_index;
|
distribution[offset].prim = ~light_index;
|
||||||
distribution[offset].mesh_light.object_id = OBJECT_NONE;
|
distribution[offset].object_id = object->index;
|
||||||
distribution[offset].mesh_light.shader_flag = 0;
|
distribution[offset].shader_flag = 0;
|
||||||
totarea += lightarea;
|
totarea += lightarea;
|
||||||
|
|
||||||
light_index++;
|
light_index++;
|
||||||
@@ -433,8 +427,8 @@ void LightManager::device_update_distribution(Device * /*unused*/,
|
|||||||
/* normalize cumulative distribution functions */
|
/* normalize cumulative distribution functions */
|
||||||
distribution[num_distribution].totarea = totarea;
|
distribution[num_distribution].totarea = totarea;
|
||||||
distribution[num_distribution].prim = 0;
|
distribution[num_distribution].prim = 0;
|
||||||
distribution[num_distribution].mesh_light.object_id = OBJECT_NONE;
|
distribution[num_distribution].object_id = OBJECT_NONE;
|
||||||
distribution[num_distribution].mesh_light.shader_flag = 0;
|
distribution[num_distribution].shader_flag = 0;
|
||||||
|
|
||||||
if (totarea > 0.0f) {
|
if (totarea > 0.0f) {
|
||||||
for (size_t i = 0; i < num_distribution; i++) {
|
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.triangle.id = emitter.prim_id + mesh->prim_offset;
|
||||||
kemitter.mesh_light.shader_flag = shader_flag;
|
kemitter.shader_flag = shader_flag;
|
||||||
kemitter.mesh_light.object_id = emitter.object_id;
|
kemitter.object_id = emitter.object_id;
|
||||||
kemitter.triangle.emission_sampling = shader->emission_sampling;
|
kemitter.triangle.emission_sampling = shader->emission_sampling;
|
||||||
flatten.triangle_array[emitter.prim_id + flatten.object_lookup_offset[emitter.object_id]] =
|
flatten.triangle_array[emitter.prim_id + flatten.object_lookup_offset[emitter.object_id]] =
|
||||||
emitter_index;
|
emitter_index;
|
||||||
@@ -575,16 +569,16 @@ static void light_tree_leaf_emitters_copy_and_flatten(LightTreeFlatten &flatten,
|
|||||||
else if (emitter.is_light()) {
|
else if (emitter.is_light()) {
|
||||||
/* Light object. */
|
/* Light object. */
|
||||||
kemitter.light.id = emitter.light_id;
|
kemitter.light.id = emitter.light_id;
|
||||||
kemitter.mesh_light.shader_flag = 0;
|
kemitter.shader_flag = 0;
|
||||||
kemitter.mesh_light.object_id = OBJECT_NONE;
|
kemitter.object_id = emitter.object_id;
|
||||||
flatten.light_array[~emitter.light_id] = emitter_index;
|
flatten.light_array[~emitter.light_id] = emitter_index;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Mesh instance. */
|
/* Mesh instance. */
|
||||||
assert(emitter.is_mesh());
|
assert(emitter.is_mesh());
|
||||||
kemitter.mesh.object_id = emitter.object_id;
|
kemitter.mesh.object_id = emitter.object_id;
|
||||||
kemitter.mesh_light.shader_flag = 0;
|
kemitter.shader_flag = 0;
|
||||||
kemitter.mesh_light.object_id = OBJECT_NONE;
|
kemitter.object_id = OBJECT_NONE;
|
||||||
flatten.mesh_array[emitter.object_id] = emitter_index;
|
flatten.mesh_array[emitter.object_id] = emitter_index;
|
||||||
|
|
||||||
/* Create instance node. One instance node will be the same as the
|
/* 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);
|
auto map_it = flatten.instances.find(reference_node);
|
||||||
if (map_it == flatten.instances.end()) {
|
if (map_it == flatten.instances.end()) {
|
||||||
if (instance_node != reference_node) {
|
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->type, reference_node->type);
|
||||||
std::swap(instance_node->variant_type, reference_node->variant_type);
|
std::swap(instance_node->variant_type, reference_node->variant_type);
|
||||||
}
|
}
|
||||||
@@ -727,8 +722,8 @@ static std::pair<int, LightTreeMeasure> light_tree_specialize_nodes_flatten(
|
|||||||
|
|
||||||
assert(first_emitter != -1);
|
assert(first_emitter != -1);
|
||||||
|
|
||||||
/* Preserve the type of the node, so that the kernel can do proper decision when sampling node
|
/* Preserve the type of the node, so that the kernel can do proper decision when sampling
|
||||||
* with multiple distant lights in it. */
|
* node with multiple distant lights in it. */
|
||||||
if (node->is_leaf()) {
|
if (node->is_leaf()) {
|
||||||
new_node.make_leaf(first_emitter, num_emitters);
|
new_node.make_leaf(first_emitter, num_emitters);
|
||||||
}
|
}
|
||||||
@@ -951,7 +946,12 @@ void LightManager::device_update_background(Device *device,
|
|||||||
bool background_mis = false;
|
bool background_mis = false;
|
||||||
|
|
||||||
/* find background light */
|
/* find background light */
|
||||||
for (Light *light : scene->lights) {
|
for (Object *object : scene->objects) {
|
||||||
|
if (!object->get_geometry()->is_light()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Light *light = static_cast<Light *>(object->get_geometry());
|
||||||
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
||||||
background_light = light;
|
background_light = light;
|
||||||
background_mis |= light->use_mis;
|
background_mis |= light->use_mis;
|
||||||
@@ -1125,7 +1125,12 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene)
|
|||||||
size_t num_distant_lights = 0;
|
size_t num_distant_lights = 0;
|
||||||
bool use_light_mis = false;
|
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<Light *>(object->get_geometry());
|
||||||
if (light->is_enabled) {
|
if (light->is_enabled) {
|
||||||
num_lights++;
|
num_lights++;
|
||||||
|
|
||||||
@@ -1165,14 +1170,24 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene)
|
|||||||
int light_index = 0;
|
int light_index = 0;
|
||||||
int portal_index = num_lights;
|
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<Light *>(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
|
/* Consider moving portals update to their own function
|
||||||
* keeping this one more manageable. */
|
* keeping this one more manageable. */
|
||||||
if (light->is_portal) {
|
if (light->is_portal) {
|
||||||
assert(light->light_type == LIGHT_AREA);
|
assert(light->light_type == LIGHT_AREA);
|
||||||
|
|
||||||
const float3 extentu = light->get_axisu() * (light->sizeu * light->size);
|
const float3 extentu = axisu * (light->sizeu * light->size);
|
||||||
const float3 extentv = light->get_axisv() * (light->sizev * light->size);
|
const float3 extentv = axisv * (light->sizev * light->size);
|
||||||
|
|
||||||
float len_u;
|
float len_u;
|
||||||
float len_v;
|
float len_v;
|
||||||
@@ -1188,17 +1203,14 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene)
|
|||||||
invarea = -invarea;
|
invarea = -invarea;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float3 dir = safe_normalize(light->get_dir());
|
klights[portal_index].co = co;
|
||||||
|
|
||||||
klights[portal_index].co = light->get_co();
|
|
||||||
klights[portal_index].area.axis_u = axis_u;
|
klights[portal_index].area.axis_u = axis_u;
|
||||||
klights[portal_index].area.len_u = len_u;
|
klights[portal_index].area.len_u = len_u;
|
||||||
klights[portal_index].area.axis_v = axis_v;
|
klights[portal_index].area.axis_v = axis_v;
|
||||||
klights[portal_index].area.len_v = len_v;
|
klights[portal_index].area.len_v = len_v;
|
||||||
klights[portal_index].area.invarea = invarea;
|
klights[portal_index].area.invarea = invarea;
|
||||||
klights[portal_index].area.dir = dir;
|
klights[portal_index].area.dir = safe_normalize(dir);
|
||||||
klights[portal_index].tfm = light->tfm;
|
klights[portal_index].object_id = object->index;
|
||||||
klights[portal_index].itfm = transform_inverse(light->tfm);
|
|
||||||
|
|
||||||
portal_index++;
|
portal_index++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1208,9 +1220,8 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene)
|
|||||||
continue;
|
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);
|
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) {
|
if (!light->cast_shadow) {
|
||||||
shader_id &= ~SHADER_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;
|
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.radius = radius;
|
||||||
klights[light_index].spot.eval_fac = eval_fac;
|
klights[light_index].spot.eval_fac = eval_fac;
|
||||||
klights[light_index].spot.is_sphere = light->get_is_sphere() && radius != 0.0f;
|
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) {
|
else if (light->light_type == LIGHT_DISTANT) {
|
||||||
shader_id &= ~SHADER_AREA_LIGHT;
|
shader_id &= ~SHADER_AREA_LIGHT;
|
||||||
|
|
||||||
const float3 dir = safe_normalize(light->get_dir());
|
|
||||||
const float angle = light->angle / 2.0f;
|
const float angle = light->angle / 2.0f;
|
||||||
|
|
||||||
if (light->use_mis && angle > 0.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 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;
|
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.angle = angle;
|
||||||
klights[light_index].distant.one_minus_cosangle = one_minus_cosangle;
|
klights[light_index].distant.one_minus_cosangle = one_minus_cosangle;
|
||||||
klights[light_index].distant.pdf = pdf;
|
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) {
|
else if (light->light_type == LIGHT_AREA) {
|
||||||
const float light_size = light->size;
|
const float light_size = light->size;
|
||||||
const float3 extentu = light->get_axisu() * (light->sizeu * light_size);
|
const float3 extentu = axisu * (light->sizeu * light_size);
|
||||||
const float3 extentv = light->get_axisv() * (light->sizev * light_size);
|
const float3 extentv = axisv * (light->sizev * light_size);
|
||||||
|
|
||||||
float len_u;
|
float len_u;
|
||||||
float len_v;
|
float len_v;
|
||||||
@@ -1336,19 +1346,17 @@ void LightManager::device_update_lights(DeviceScene *dscene, Scene *scene)
|
|||||||
3.0f / powf(half_spread, 3.0f)) :
|
3.0f / powf(half_spread, 3.0f)) :
|
||||||
FLT_MAX;
|
FLT_MAX;
|
||||||
|
|
||||||
const float3 dir = safe_normalize(light->get_dir());
|
|
||||||
|
|
||||||
if (light->use_mis && area != 0.0f && light->spread > 0.0f) {
|
if (light->use_mis && area != 0.0f && light->spread > 0.0f) {
|
||||||
shader_id |= SHADER_USE_MIS;
|
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.axis_u = axis_u;
|
||||||
klights[light_index].area.len_u = len_u;
|
klights[light_index].area.len_u = len_u;
|
||||||
klights[light_index].area.axis_v = axis_v;
|
klights[light_index].area.axis_v = axis_v;
|
||||||
klights[light_index].area.len_v = len_v;
|
klights[light_index].area.len_v = len_v;
|
||||||
klights[light_index].area.invarea = invarea;
|
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.tan_half_spread = tan_half_spread;
|
||||||
klights[light_index].area.normalize_spread = normalize_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 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 tan_half_spot_angle = tanf(light->spot_angle * 0.5f);
|
||||||
|
|
||||||
const float len_w_sq = len_squared(light->get_dir());
|
const float len_w_sq = len_squared(dir);
|
||||||
const float len_u_sq = len_squared(light->get_axisu());
|
const float len_u_sq = len_squared(axisu);
|
||||||
const float len_v_sq = len_squared(light->get_axisv());
|
const float len_v_sq = len_squared(axisv);
|
||||||
const float tan_sq = sqr(tan_half_spot_angle);
|
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.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.half_cot_half_spot_angle = 0.5f / tan_half_spot_angle;
|
||||||
klights[light_index].spot.spot_smooth = spot_smooth;
|
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].shader_id = shader_id;
|
||||||
|
klights[light_index].object_id = object->index;
|
||||||
|
|
||||||
klights[light_index].max_bounces = light->max_bounces;
|
klights[light_index].max_bounces = light->max_bounces;
|
||||||
klights[light_index].random = random;
|
|
||||||
klights[light_index].use_caustics = light->use_caustics;
|
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++;
|
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. */
|
/* Detect which lights are enabled, also determines if we need to update the background. */
|
||||||
test_enabled_lights(scene);
|
test_enabled_lights(scene);
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,7 @@
|
|||||||
|
|
||||||
#include "graph/node.h"
|
#include "graph/node.h"
|
||||||
|
|
||||||
/* included as Light::set_shader defined through NODE_SOCKET_API does not select
|
#include "scene/geometry.h"
|
||||||
* the right Node::set overload as it does not know that Shader is a Node */
|
|
||||||
#include "scene/shader.h"
|
|
||||||
|
|
||||||
#include "util/ies.h"
|
#include "util/ies.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
@@ -26,7 +24,7 @@ class Progress;
|
|||||||
class Scene;
|
class Scene;
|
||||||
class Shader;
|
class Shader;
|
||||||
|
|
||||||
class Light : public Node {
|
class Light : public Geometry {
|
||||||
public:
|
public:
|
||||||
NODE_DECLARE;
|
NODE_DECLARE;
|
||||||
|
|
||||||
@@ -43,8 +41,6 @@ class Light : public Node {
|
|||||||
NODE_SOCKET_API(bool, ellipse)
|
NODE_SOCKET_API(bool, ellipse)
|
||||||
NODE_SOCKET_API(float, spread)
|
NODE_SOCKET_API(float, spread)
|
||||||
|
|
||||||
NODE_SOCKET_API(Transform, tfm)
|
|
||||||
|
|
||||||
NODE_SOCKET_API(int, map_resolution)
|
NODE_SOCKET_API(int, map_resolution)
|
||||||
NODE_SOCKET_API(float, average_radiance)
|
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_portal)
|
||||||
NODE_SOCKET_API(bool, is_enabled)
|
NODE_SOCKET_API(bool, is_enabled)
|
||||||
|
|
||||||
NODE_SOCKET_API(Shader *, shader)
|
|
||||||
NODE_SOCKET_API(int, max_bounces)
|
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. */
|
/* Normalize power by the surface area of the light. */
|
||||||
NODE_SOCKET_API(bool, normalize)
|
NODE_SOCKET_API(bool, normalize)
|
||||||
@@ -82,15 +72,14 @@ class Light : public Node {
|
|||||||
/* Check whether the light has contribution the scene. */
|
/* Check whether the light has contribution the scene. */
|
||||||
bool has_contribution(Scene *scene);
|
bool has_contribution(Scene *scene);
|
||||||
|
|
||||||
/* Check whether this light participates in light or shadow linking. */
|
/* Shader */
|
||||||
bool has_light_linking() const;
|
Shader *get_shader() const;
|
||||||
bool has_shadow_linking() const;
|
|
||||||
|
|
||||||
/* Convenience access to transform. */
|
/* Geometry */
|
||||||
float3 get_co() const;
|
void compute_bounds() override;
|
||||||
float3 get_dir() const;
|
void apply_transform(const Transform &tfm, const bool apply_to_motion) override;
|
||||||
float3 get_axisu() const;
|
void get_uv_tiles(ustring map, unordered_set<int> &tiles) override;
|
||||||
float3 get_axisv() const;
|
PrimitiveType primitive_type() const override;
|
||||||
|
|
||||||
friend class LightManager;
|
friend class LightManager;
|
||||||
friend class LightTree;
|
friend class LightTree;
|
||||||
|
|||||||
@@ -88,9 +88,10 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
|
|||||||
bool need_transformation)
|
bool need_transformation)
|
||||||
: prim_id(prim_id), object_id(object_id)
|
: prim_id(prim_id), object_id(object_id)
|
||||||
{
|
{
|
||||||
|
Object *object = scene->objects[object_id];
|
||||||
|
|
||||||
if (is_triangle()) {
|
if (is_triangle()) {
|
||||||
float3 vertices[3];
|
float3 vertices[3];
|
||||||
Object *object = scene->objects[object_id];
|
|
||||||
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
||||||
const Mesh::Triangle triangle = mesh->get_triangle(prim_id);
|
const Mesh::Triangle triangle = mesh->get_triangle(prim_id);
|
||||||
Shader *shader = static_cast<Shader *>(mesh->get_used_shaders()[mesh->get_shader()[prim_id]]);
|
Shader *shader = static_cast<Shader *>(mesh->get_used_shaders()[mesh->get_shader()[prim_id]]);
|
||||||
@@ -148,13 +149,13 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(is_light());
|
assert(is_light());
|
||||||
Light *lamp = scene->lights[object_id];
|
Light *lamp = static_cast<Light *>(object->get_geometry());
|
||||||
const LightType type = lamp->get_light_type();
|
const LightType type = lamp->get_light_type();
|
||||||
const float size = lamp->get_size();
|
const float size = lamp->get_size();
|
||||||
float3 strength = lamp->get_strength();
|
float3 strength = lamp->get_strength();
|
||||||
|
|
||||||
centroid = lamp->get_co();
|
centroid = transform_get_column(&object->get_tfm(), 3);
|
||||||
measure.bcone.axis = safe_normalize(lamp->get_dir());
|
measure.bcone.axis = -safe_normalize(transform_get_column(&object->get_tfm(), 2));
|
||||||
|
|
||||||
if (type == LIGHT_AREA) {
|
if (type == LIGHT_AREA) {
|
||||||
measure.bcone.theta_o = 0;
|
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,
|
/* 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.
|
* while axisu and axisv determine the orientation of the 2 dimensions.
|
||||||
* We want to add all 4 corners to our bounding box. */
|
* 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 axisu = transform_get_column(&object->get_tfm(), 0);
|
||||||
const float3 half_extentv = 0.5f * lamp->get_sizev() * lamp->get_axisv() * size;
|
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);
|
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;
|
measure.bcone.theta_o = 0;
|
||||||
|
|
||||||
float theta_e = min(lamp->get_spot_angle() * 0.5f, M_PI_2_F);
|
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_u = len(transform_get_column(&object->get_tfm(), 0));
|
||||||
const float len_v = len(lamp->get_axisv());
|
const float len_v = len(transform_get_column(&object->get_tfm(), 1));
|
||||||
const float len_w = len(lamp->get_dir());
|
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
|
/* 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
|
* 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. */
|
* light tree. */
|
||||||
measure.energy = average(fabs(strength));
|
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.
|
* 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. */
|
* However, we also need the light's index in the scene when we're constructing the tree. */
|
||||||
int device_light_index = 0;
|
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) {
|
for (Object *object : scene->objects) {
|
||||||
if (progress_.get_cancel()) {
|
if (progress_.get_cancel()) {
|
||||||
return;
|
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<Light *>(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()) {
|
device_light_index++;
|
||||||
object_id++;
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* Emissive triangles. */
|
||||||
|
light_link_receiver_used |= (uint64_t(1) << object->get_receiver_light_set());
|
||||||
|
|
||||||
mesh_lights_.emplace_back(object, object_id);
|
if (!object->usable_as_light()) {
|
||||||
object_id++;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Only count unique meshes. */
|
mesh_lights_.emplace_back(object, object->index);
|
||||||
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
|
||||||
auto map_it = offset_map_.find(mesh);
|
/* Only count unique meshes. */
|
||||||
if (map_it == offset_map_.end()) {
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
||||||
offset_map_[mesh] = num_triangles;
|
auto map_it = offset_map_.find(mesh);
|
||||||
num_triangles += mesh->num_triangles();
|
if (map_it == offset_map_.end()) {
|
||||||
|
offset_map_[mesh] = num_triangles;
|
||||||
|
num_triangles += mesh->num_triangles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ static void recursive_print_node(FILE *file, const LightTreeNode &node)
|
|||||||
fprintf(file, "];\n");
|
fprintf(file, "];\n");
|
||||||
|
|
||||||
if (node.is_inner()) {
|
if (node.is_inner()) {
|
||||||
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left].get();
|
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left];
|
||||||
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right].get();
|
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right];
|
||||||
|
|
||||||
recursive_print_node(file, left_node);
|
recursive_print_node(file, left_node);
|
||||||
recursive_print_node(file, right_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("<f%d> emitter %s", field++, std::to_string(i).c_str());
|
string label = string_printf("<f%d> emitter %s", field++, std::to_string(i).c_str());
|
||||||
|
|
||||||
/* Emitter details (type, object or light name). */
|
/* Emitter details (type, object or light name). */
|
||||||
|
const Object &object = *scene.objects[emitter.object_id];
|
||||||
if (emitter.is_light()) {
|
if (emitter.is_light()) {
|
||||||
const Light &lamp = *scene.lights[emitter.object_id];
|
|
||||||
label += string_printf("|<f%d> light", field++);
|
label += string_printf("|<f%d> light", field++);
|
||||||
label += string_printf("|<f%d> %s", field++, lamp.name.c_str());
|
|
||||||
}
|
}
|
||||||
else if (emitter.is_triangle()) {
|
else if (emitter.is_triangle()) {
|
||||||
const Object &object = *scene.objects[emitter.object_id];
|
|
||||||
label += string_printf("|<f%d> triangle", field++);
|
label += string_printf("|<f%d> triangle", field++);
|
||||||
label += string_printf("|<f%d> %s", field++, object.name.c_str());
|
|
||||||
}
|
}
|
||||||
else if (emitter.is_mesh()) {
|
else if (emitter.is_mesh()) {
|
||||||
const Object &object = *scene.objects[emitter.object_id];
|
|
||||||
label += string_printf("|<f%d> mesh", field++);
|
label += string_printf("|<f%d> mesh", field++);
|
||||||
label += string_printf("|<f%d> %s", field++, object.name.c_str());
|
|
||||||
}
|
}
|
||||||
|
label += string_printf("|<f%d> %s", field++, object.name.c_str());
|
||||||
|
|
||||||
/* Light linking. */
|
/* Light linking. */
|
||||||
if (emitter.light_set_membership == ~uint64_t(0)) {
|
if (emitter.light_set_membership == ~uint64_t(0)) {
|
||||||
@@ -176,8 +172,8 @@ static void recursive_print_node_relations(FILE *file,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left].get();
|
const LightTreeNode &left_node = *node.get_inner().children[LightTree::left];
|
||||||
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right].get();
|
const LightTreeNode &right_node = *node.get_inner().children[LightTree::right];
|
||||||
|
|
||||||
const string left_node_id = get_node_id(left_node);
|
const string left_node_id = get_node_id(left_node);
|
||||||
const string right_node_id = get_node_id(right_node);
|
const string right_node_id = get_node_id(right_node);
|
||||||
|
|||||||
@@ -272,6 +272,10 @@ int Object::motion_step(const float time) const
|
|||||||
|
|
||||||
bool Object::is_traceable() 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. */
|
/* Mesh itself can be empty,can skip all such objects. */
|
||||||
if (!bounds.valid() || bounds.size() == zero_float3()) {
|
if (!bounds.valid() || bounds.size() == zero_float3()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ class Object : public Node {
|
|||||||
/* Set during device update. */
|
/* Set during device update. */
|
||||||
bool intersects_volume;
|
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();
|
||||||
~Object() override;
|
~Object() override;
|
||||||
|
|
||||||
@@ -120,10 +124,6 @@ class Object : public Node {
|
|||||||
bool has_shadow_linking() const;
|
bool has_shadow_linking() const;
|
||||||
|
|
||||||
protected:
|
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,
|
/* Reference to the attribute map with object attributes,
|
||||||
* or 0 if none. Set in update_svm_attributes. */
|
* or 0 if none. Set in update_svm_attributes. */
|
||||||
size_t attr_map_offset;
|
size_t attr_map_offset;
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ void Scene::free_memory(bool final)
|
|||||||
procedurals.clear();
|
procedurals.clear();
|
||||||
objects.clear();
|
objects.clear();
|
||||||
geometry.clear();
|
geometry.clear();
|
||||||
lights.clear();
|
|
||||||
particle_systems.clear();
|
particle_systems.clear();
|
||||||
passes.clear();
|
passes.clear();
|
||||||
|
|
||||||
@@ -511,6 +510,12 @@ void Scene::update_kernel_features()
|
|||||||
else if (geom->is_pointcloud()) {
|
else if (geom->is_pointcloud()) {
|
||||||
kernel_features |= KERNEL_FEATURE_POINTCLOUD;
|
kernel_features |= KERNEL_FEATURE_POINTCLOUD;
|
||||||
}
|
}
|
||||||
|
else if (geom->is_light()) {
|
||||||
|
const Light *light = static_cast<const Light *>(object->get_geometry());
|
||||||
|
if (light->get_use_caustics()) {
|
||||||
|
has_caustics_light = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (object->has_light_linking()) {
|
if (object->has_light_linking()) {
|
||||||
kernel_features |= KERNEL_FEATURE_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;
|
dscene.data.integrator.use_caustics = false;
|
||||||
if (device->info.has_mnee && has_caustics_caster && has_caustics_receiver && has_caustics_light)
|
if (device->info.has_mnee && has_caustics_caster && has_caustics_receiver && has_caustics_light)
|
||||||
{
|
{
|
||||||
@@ -741,7 +733,7 @@ template<> Light *Scene::create_node<Light>()
|
|||||||
unique_ptr<Light> node = make_unique<Light>();
|
unique_ptr<Light> node = make_unique<Light>();
|
||||||
Light *node_ptr = node.get();
|
Light *node_ptr = node.get();
|
||||||
node->set_owner(this);
|
node->set_owner(this);
|
||||||
lights.push_back(std::move(node));
|
geometry.push_back(std::move(node));
|
||||||
light_manager->tag_update(this, LightManager::LIGHT_ADDED);
|
light_manager->tag_update(this, LightManager::LIGHT_ADDED);
|
||||||
return node_ptr;
|
return node_ptr;
|
||||||
}
|
}
|
||||||
@@ -879,7 +871,7 @@ template<> Film *Scene::create_node<Film>()
|
|||||||
template<> void Scene::delete_node(Light *node)
|
template<> void Scene::delete_node(Light *node)
|
||||||
{
|
{
|
||||||
assert(node->get_owner() == this);
|
assert(node->get_owner() == this);
|
||||||
lights.erase_by_swap(node);
|
geometry.erase_by_swap(node);
|
||||||
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,18 +975,12 @@ template<typename T> static void assert_same_owner(const set<T *> &nodes, const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void Scene::delete_nodes(const set<Light *> &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<Geometry *> &nodes, const NodeOwner *owner)
|
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
|
||||||
{
|
{
|
||||||
assert_same_owner(nodes, owner);
|
assert_same_owner(nodes, owner);
|
||||||
geometry.erase_in_set(nodes);
|
geometry.erase_in_set(nodes);
|
||||||
geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
|
geometry_manager->tag_update(this, GeometryManager::GEOMETRY_REMOVED);
|
||||||
|
light_manager->tag_update(this, LightManager::LIGHT_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
|
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ class Scene : public NodeOwner {
|
|||||||
unique_ptr_vector<Shader> shaders;
|
unique_ptr_vector<Shader> shaders;
|
||||||
unique_ptr_vector<Pass> passes;
|
unique_ptr_vector<Pass> passes;
|
||||||
unique_ptr_vector<ParticleSystem> particle_systems;
|
unique_ptr_vector<ParticleSystem> particle_systems;
|
||||||
unique_ptr_vector<Light> lights;
|
|
||||||
unique_ptr_vector<Geometry> geometry;
|
unique_ptr_vector<Geometry> geometry;
|
||||||
unique_ptr_vector<Object> objects;
|
unique_ptr_vector<Object> objects;
|
||||||
unique_ptr_vector<Procedural> procedurals;
|
unique_ptr_vector<Procedural> procedurals;
|
||||||
@@ -281,7 +280,6 @@ template<> void Scene::delete_node(Procedural *node);
|
|||||||
template<> void Scene::delete_node(AlembicProcedural *node);
|
template<> void Scene::delete_node(AlembicProcedural *node);
|
||||||
template<> void Scene::delete_node(Pass *node);
|
template<> void Scene::delete_node(Pass *node);
|
||||||
|
|
||||||
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner);
|
|
||||||
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
|
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner);
|
||||||
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner);
|
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner);
|
||||||
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner);
|
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner);
|
||||||
|
|||||||
Reference in New Issue
Block a user