2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
2014-12-25 02:50:24 +01:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "device/device.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "render/background.h"
|
|
|
|
|
#include "render/bake.h"
|
|
|
|
|
#include "render/camera.h"
|
|
|
|
|
#include "render/curves.h"
|
|
|
|
|
#include "render/film.h"
|
|
|
|
|
#include "render/integrator.h"
|
|
|
|
|
#include "render/light.h"
|
|
|
|
|
#include "render/mesh.h"
|
|
|
|
|
#include "render/object.h"
|
|
|
|
|
#include "render/osl.h"
|
|
|
|
|
#include "render/particles.h"
|
|
|
|
|
#include "render/scene.h"
|
2020-08-18 10:46:12 +02:00
|
|
|
#include "render/session.h"
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "render/shader.h"
|
|
|
|
|
#include "render/svm.h"
|
|
|
|
|
#include "render/tables.h"
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
#include "render/volume.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "util/util_foreach.h"
|
|
|
|
|
#include "util/util_guarded_allocator.h"
|
|
|
|
|
#include "util/util_logging.h"
|
|
|
|
|
#include "util/util_progress.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2017-10-20 23:31:13 +02:00
|
|
|
DeviceScene::DeviceScene(Device *device)
|
2020-03-12 15:22:18 +01:00
|
|
|
: bvh_nodes(device, "__bvh_nodes", MEM_GLOBAL),
|
|
|
|
|
bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_GLOBAL),
|
|
|
|
|
object_node(device, "__object_node", MEM_GLOBAL),
|
|
|
|
|
prim_tri_index(device, "__prim_tri_index", MEM_GLOBAL),
|
|
|
|
|
prim_tri_verts(device, "__prim_tri_verts", MEM_GLOBAL),
|
|
|
|
|
prim_type(device, "__prim_type", MEM_GLOBAL),
|
|
|
|
|
prim_visibility(device, "__prim_visibility", MEM_GLOBAL),
|
|
|
|
|
prim_index(device, "__prim_index", MEM_GLOBAL),
|
|
|
|
|
prim_object(device, "__prim_object", MEM_GLOBAL),
|
|
|
|
|
prim_time(device, "__prim_time", MEM_GLOBAL),
|
|
|
|
|
tri_shader(device, "__tri_shader", MEM_GLOBAL),
|
|
|
|
|
tri_vnormal(device, "__tri_vnormal", MEM_GLOBAL),
|
|
|
|
|
tri_vindex(device, "__tri_vindex", MEM_GLOBAL),
|
|
|
|
|
tri_patch(device, "__tri_patch", MEM_GLOBAL),
|
|
|
|
|
tri_patch_uv(device, "__tri_patch_uv", MEM_GLOBAL),
|
|
|
|
|
curves(device, "__curves", MEM_GLOBAL),
|
|
|
|
|
curve_keys(device, "__curve_keys", MEM_GLOBAL),
|
|
|
|
|
patches(device, "__patches", MEM_GLOBAL),
|
|
|
|
|
objects(device, "__objects", MEM_GLOBAL),
|
|
|
|
|
object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
|
|
|
|
|
object_motion(device, "__object_motion", MEM_GLOBAL),
|
|
|
|
|
object_flag(device, "__object_flag", MEM_GLOBAL),
|
2020-03-07 14:38:52 +01:00
|
|
|
object_volume_step(device, "__object_volume_step", MEM_GLOBAL),
|
2020-03-12 15:22:18 +01:00
|
|
|
camera_motion(device, "__camera_motion", MEM_GLOBAL),
|
|
|
|
|
attributes_map(device, "__attributes_map", MEM_GLOBAL),
|
|
|
|
|
attributes_float(device, "__attributes_float", MEM_GLOBAL),
|
|
|
|
|
attributes_float2(device, "__attributes_float2", MEM_GLOBAL),
|
|
|
|
|
attributes_float3(device, "__attributes_float3", MEM_GLOBAL),
|
|
|
|
|
attributes_uchar4(device, "__attributes_uchar4", MEM_GLOBAL),
|
|
|
|
|
light_distribution(device, "__light_distribution", MEM_GLOBAL),
|
|
|
|
|
lights(device, "__lights", MEM_GLOBAL),
|
|
|
|
|
light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_GLOBAL),
|
|
|
|
|
light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_GLOBAL),
|
|
|
|
|
particles(device, "__particles", MEM_GLOBAL),
|
|
|
|
|
svm_nodes(device, "__svm_nodes", MEM_GLOBAL),
|
|
|
|
|
shaders(device, "__shaders", MEM_GLOBAL),
|
|
|
|
|
lookup_table(device, "__lookup_table", MEM_GLOBAL),
|
|
|
|
|
sample_pattern_lut(device, "__sample_pattern_lut", MEM_GLOBAL),
|
|
|
|
|
ies_lights(device, "__ies", MEM_GLOBAL)
|
2017-10-20 23:31:13 +02:00
|
|
|
{
|
2018-06-11 12:54:17 +02:00
|
|
|
memset((void *)&data, 0, sizeof(data));
|
2017-10-20 23:31:13 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-20 05:08:26 +02:00
|
|
|
Scene::Scene(const SceneParams ¶ms_, Device *device)
|
2020-03-18 17:54:24 +01:00
|
|
|
: name("Scene"),
|
|
|
|
|
default_surface(NULL),
|
|
|
|
|
default_volume(NULL),
|
|
|
|
|
default_light(NULL),
|
|
|
|
|
default_background(NULL),
|
|
|
|
|
default_empty(NULL),
|
|
|
|
|
device(device),
|
|
|
|
|
dscene(device),
|
2020-10-01 23:16:01 +02:00
|
|
|
params(params_),
|
|
|
|
|
update_stats(NULL)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2018-06-11 12:54:17 +02:00
|
|
|
memset((void *)&dscene.data, 0, sizeof(dscene.data));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
camera = create_node<Camera>();
|
|
|
|
|
dicing_camera = create_node<Camera>();
|
2013-04-01 20:26:43 +00:00
|
|
|
lookup_tables = new LookupTables();
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
film = create_node<Film>();
|
|
|
|
|
background = create_node<Background>();
|
2011-04-27 11:58:34 +00:00
|
|
|
light_manager = new LightManager();
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager = new GeometryManager();
|
2011-04-27 11:58:34 +00:00
|
|
|
object_manager = new ObjectManager();
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
integrator = create_node<Integrator>();
|
2017-10-20 05:08:26 +02:00
|
|
|
image_manager = new ImageManager(device->info);
|
2012-08-31 17:27:08 +00:00
|
|
|
particle_system_manager = new ParticleSystemManager();
|
2014-01-02 19:05:07 -02:00
|
|
|
bake_manager = new BakeManager();
|
2020-08-18 10:46:12 +02:00
|
|
|
kernels_loaded = false;
|
|
|
|
|
|
|
|
|
|
/* TODO(sergey): Check if it's indeed optimal value for the split kernel. */
|
|
|
|
|
max_closure_global = 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-18 12:15:46 +02:00
|
|
|
film->add_default(this);
|
|
|
|
|
|
2012-12-04 07:48:09 +00:00
|
|
|
/* OSL only works on the CPU */
|
2017-10-20 05:08:26 +02:00
|
|
|
if (device->info.has_osl)
|
2020-03-11 17:49:00 +01:00
|
|
|
shader_manager = ShaderManager::create(params.shadingsystem);
|
2012-12-04 07:48:09 +00:00
|
|
|
else
|
2020-03-11 17:49:00 +01:00
|
|
|
shader_manager = ShaderManager::create(SHADINGSYSTEM_SVM);
|
|
|
|
|
|
|
|
|
|
shader_manager->add_default(this);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Scene::~Scene()
|
|
|
|
|
{
|
2012-11-09 08:46:53 +00:00
|
|
|
free_memory(true);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
void Scene::free_memory(bool final)
|
|
|
|
|
{
|
2011-04-27 11:58:34 +00:00
|
|
|
foreach (Shader *s, shaders)
|
|
|
|
|
delete s;
|
2020-02-02 12:04:19 +01:00
|
|
|
foreach (Geometry *g, geometry)
|
|
|
|
|
delete g;
|
2011-04-27 11:58:34 +00:00
|
|
|
foreach (Object *o, objects)
|
|
|
|
|
delete o;
|
|
|
|
|
foreach (Light *l, lights)
|
|
|
|
|
delete l;
|
2012-08-31 17:27:08 +00:00
|
|
|
foreach (ParticleSystem *p, particle_systems)
|
|
|
|
|
delete p;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-02-14 16:11:47 +00:00
|
|
|
shaders.clear();
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry.clear();
|
2013-02-14 16:11:47 +00:00
|
|
|
objects.clear();
|
|
|
|
|
lights.clear();
|
|
|
|
|
particle_systems.clear();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
if (device) {
|
2015-10-27 13:16:04 +05:00
|
|
|
camera->device_free(device, &dscene, this);
|
2013-04-01 20:26:43 +00:00
|
|
|
film->device_free(device, &dscene, this);
|
2012-11-09 08:46:53 +00:00
|
|
|
background->device_free(device, &dscene);
|
|
|
|
|
integrator->device_free(device, &dscene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
object_manager->device_free(device, &dscene);
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager->device_free(device, &dscene);
|
2013-04-01 20:26:52 +00:00
|
|
|
shader_manager->device_free(device, &dscene, this);
|
2012-11-09 08:46:53 +00:00
|
|
|
light_manager->device_free(device, &dscene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
particle_system_manager->device_free(device, &dscene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-02 19:05:07 -02:00
|
|
|
bake_manager->device_free(device, &dscene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-02-14 16:48:43 +00:00
|
|
|
if (!params.persistent_data || final)
|
2017-10-20 04:20:37 +02:00
|
|
|
image_manager->device_free(device);
|
2014-05-19 14:45:52 +02:00
|
|
|
else
|
2017-10-20 04:20:37 +02:00
|
|
|
image_manager->device_free_builtin(device);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-01 20:26:43 +00:00
|
|
|
lookup_tables->device_free(device, &dscene);
|
2012-11-09 08:46:53 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
if (final) {
|
2013-04-01 20:26:43 +00:00
|
|
|
delete lookup_tables;
|
2012-11-09 08:46:53 +00:00
|
|
|
delete camera;
|
2018-01-12 00:50:34 +01:00
|
|
|
delete dicing_camera;
|
2012-11-09 08:46:53 +00:00
|
|
|
delete film;
|
|
|
|
|
delete background;
|
|
|
|
|
delete integrator;
|
|
|
|
|
delete object_manager;
|
2020-02-02 12:04:19 +01:00
|
|
|
delete geometry_manager;
|
2012-11-09 08:46:53 +00:00
|
|
|
delete shader_manager;
|
|
|
|
|
delete light_manager;
|
|
|
|
|
delete particle_system_manager;
|
|
|
|
|
delete image_manager;
|
2014-01-02 19:05:07 -02:00
|
|
|
delete bake_manager;
|
2020-10-01 23:16:01 +02:00
|
|
|
delete update_stats;
|
2012-11-09 08:46:53 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Scene::device_update(Device *device_, Progress &progress)
|
|
|
|
|
{
|
|
|
|
|
if (!device)
|
|
|
|
|
device = device_;
|
2016-04-22 10:55:26 +02:00
|
|
|
|
|
|
|
|
bool print_stats = need_data_update();
|
|
|
|
|
|
2020-10-01 23:16:01 +02:00
|
|
|
if (update_stats) {
|
|
|
|
|
update_stats->clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scoped_callback_timer timer([this, print_stats](double time) {
|
|
|
|
|
if (update_stats) {
|
|
|
|
|
update_stats->scene.times.add_entry({"device_update", time});
|
|
|
|
|
|
|
|
|
|
if (print_stats) {
|
|
|
|
|
printf("Update statistics:\n%s\n", update_stats->full_report().c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* The order of updates is important, because there's dependencies between
|
|
|
|
|
* the different managers, using data computed by previous managers.
|
|
|
|
|
*
|
|
|
|
|
* - Image manager uploads images used by shaders.
|
2014-08-02 16:53:52 +10:00
|
|
|
* - Camera may be used for adaptive subdivision.
|
2011-04-27 11:58:34 +00:00
|
|
|
* - Displacement shader must have all shader data available.
|
2014-02-06 21:09:46 +01:00
|
|
|
* - Light manager needs lookup tables and final mesh data to compute emission CDF.
|
2014-03-12 18:20:42 +01:00
|
|
|
* - Film needs light manager to run for use_light_visibility
|
|
|
|
|
* - Lookup tables are done a second time to handle film tables
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
progress.set_status("Updating Shaders");
|
|
|
|
|
shader_manager->device_update(device, &dscene, this, progress);
|
|
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-12-28 16:56:19 +01:00
|
|
|
progress.set_status("Updating Background");
|
|
|
|
|
background->device_update(device, &dscene, this);
|
|
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2013-12-28 16:56:19 +01:00
|
|
|
|
2015-02-02 22:06:31 +05:00
|
|
|
progress.set_status("Updating Camera");
|
|
|
|
|
camera->device_update(device, &dscene, this);
|
|
|
|
|
|
|
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
|
|
|
|
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager->device_update_preprocess(device, this, progress);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-03-31 17:54:03 +02:00
|
|
|
progress.set_status("Updating Objects");
|
|
|
|
|
object_manager->device_update(device, &dscene, this, progress);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2018-01-18 22:40:48 -05:00
|
|
|
progress.set_status("Updating Particle Systems");
|
|
|
|
|
particle_system_manager->device_update(device, &dscene, this, progress);
|
|
|
|
|
|
|
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-04-30 01:07:38 +05:00
|
|
|
progress.set_status("Updating Meshes");
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager->device_update(device, &dscene, this, progress);
|
2014-10-03 12:11:19 +02:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2014-10-03 12:11:19 +02:00
|
|
|
|
2015-04-30 01:07:38 +05:00
|
|
|
progress.set_status("Updating Objects Flags");
|
|
|
|
|
object_manager->device_update_flags(device, &dscene, this, progress);
|
2015-01-19 19:08:58 +05:00
|
|
|
|
|
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-04-02 20:37:57 +05:00
|
|
|
progress.set_status("Updating Images");
|
2017-10-20 04:20:37 +02:00
|
|
|
image_manager->device_update(device, this, progress);
|
2015-04-02 20:37:57 +05:00
|
|
|
|
|
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-02 22:06:31 +05:00
|
|
|
progress.set_status("Updating Camera Volume");
|
|
|
|
|
camera->device_update_volume(device, &dscene, this);
|
|
|
|
|
|
|
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2018-11-25 08:01:14 +11:00
|
|
|
|
2014-02-06 21:09:46 +01:00
|
|
|
progress.set_status("Updating Lookup Tables");
|
2020-10-01 23:16:01 +02:00
|
|
|
lookup_tables->device_update(device, &dscene, this);
|
2014-02-06 21:09:46 +01:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2014-02-06 21:09:46 +01:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
progress.set_status("Updating Lights");
|
|
|
|
|
light_manager->device_update(device, &dscene, this, progress);
|
|
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-04-13 10:39:21 +02:00
|
|
|
progress.set_status("Updating Integrator");
|
|
|
|
|
integrator->device_update(device, &dscene, this);
|
2014-03-12 18:20:42 +01:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2014-03-12 18:20:42 +01:00
|
|
|
|
2016-04-13 10:39:21 +02:00
|
|
|
progress.set_status("Updating Film");
|
|
|
|
|
film->device_update(device, &dscene, this);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2014-03-12 18:20:42 +01:00
|
|
|
progress.set_status("Updating Lookup Tables");
|
2020-10-01 23:16:01 +02:00
|
|
|
lookup_tables->device_update(device, &dscene, this);
|
2014-03-12 18:20:42 +01:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2014-03-12 18:20:42 +01:00
|
|
|
|
2014-01-02 19:05:07 -02:00
|
|
|
progress.set_status("Updating Baking");
|
|
|
|
|
bake_manager->device_update(device, &dscene, this, progress);
|
|
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (progress.get_cancel() || device->have_error())
|
|
|
|
|
return;
|
2014-01-02 19:05:07 -02:00
|
|
|
|
2014-12-05 21:00:05 +05:00
|
|
|
if (device->have_error() == false) {
|
|
|
|
|
progress.set_status("Updating Device", "Writing constant memory");
|
|
|
|
|
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
|
|
|
|
|
}
|
2015-02-14 19:39:14 +05:00
|
|
|
|
2016-04-22 10:55:26 +02:00
|
|
|
if (print_stats) {
|
2016-05-29 18:02:05 -04:00
|
|
|
size_t mem_used = util_guarded_get_mem_used();
|
|
|
|
|
size_t mem_peak = util_guarded_get_mem_peak();
|
|
|
|
|
|
2016-04-22 10:55:26 +02:00
|
|
|
VLOG(1) << "System memory statistics after full device sync:\n"
|
2016-05-29 18:02:05 -04:00
|
|
|
<< " Usage: " << string_human_readable_number(mem_used) << " ("
|
|
|
|
|
<< string_human_readable_size(mem_used) << ")\n"
|
|
|
|
|
<< " Peak: " << string_human_readable_number(mem_peak) << " ("
|
|
|
|
|
<< string_human_readable_size(mem_peak) << ")";
|
2016-04-22 10:55:26 +02:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-12 19:56:52 +01:00
|
|
|
Scene::MotionType Scene::need_motion()
|
2012-04-30 12:49:26 +00:00
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
if (integrator->get_motion_blur())
|
2018-01-12 19:56:52 +01:00
|
|
|
return MOTION_BLUR;
|
2020-08-18 12:15:46 +02:00
|
|
|
else if (Pass::contains(passes, PASS_MOTION))
|
2012-04-30 12:49:26 +00:00
|
|
|
return MOTION_PASS;
|
|
|
|
|
else
|
|
|
|
|
return MOTION_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 18:56:59 +02:00
|
|
|
float Scene::motion_shutter_time()
|
|
|
|
|
{
|
|
|
|
|
if (need_motion() == Scene::MOTION_PASS)
|
|
|
|
|
return 2.0f;
|
|
|
|
|
else
|
2020-11-04 11:17:38 +01:00
|
|
|
return camera->get_shuttertime();
|
2016-07-16 18:56:59 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
bool Scene::need_global_attribute(AttributeStandard std)
|
|
|
|
|
{
|
|
|
|
|
if (std == ATTR_STD_UV)
|
2020-08-18 12:15:46 +02:00
|
|
|
return Pass::contains(passes, PASS_UV);
|
2014-05-12 10:20:20 +02:00
|
|
|
else if (std == ATTR_STD_MOTION_VERTEX_POSITION)
|
2014-03-29 13:03:46 +01:00
|
|
|
return need_motion() != MOTION_NONE;
|
2014-05-12 10:20:20 +02:00
|
|
|
else if (std == ATTR_STD_MOTION_VERTEX_NORMAL)
|
2014-03-29 13:03:46 +01:00
|
|
|
return need_motion() == MOTION_BLUR;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-30 12:49:26 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Scene::need_global_attributes(AttributeRequestSet &attributes)
|
|
|
|
|
{
|
|
|
|
|
for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
|
|
|
|
|
if (need_global_attribute((AttributeStandard)std))
|
|
|
|
|
attributes.add((AttributeStandard)std);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
bool Scene::need_update()
|
|
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
return (need_reset() || film->is_modified());
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-22 10:55:26 +02:00
|
|
|
bool Scene::need_data_update()
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
return (background->is_modified() || image_manager->need_update || object_manager->need_update ||
|
2020-02-07 15:26:35 +01:00
|
|
|
geometry_manager->need_update || light_manager->need_update ||
|
2020-11-04 11:17:38 +01:00
|
|
|
lookup_tables->need_update || integrator->is_modified() || shader_manager->need_update ||
|
|
|
|
|
particle_system_manager->need_update || bake_manager->need_update ||
|
|
|
|
|
film->is_modified());
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-22 10:55:26 +02:00
|
|
|
bool Scene::need_reset()
|
|
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
return need_data_update() || camera->is_modified();
|
2016-04-22 10:55:26 +02:00
|
|
|
}
|
|
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
void Scene::reset()
|
|
|
|
|
{
|
2013-02-14 16:11:47 +00:00
|
|
|
shader_manager->reset(this);
|
2012-11-09 08:46:53 +00:00
|
|
|
shader_manager->add_default(this);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-09 08:46:53 +00:00
|
|
|
/* ensure all objects are updated */
|
2020-11-04 11:17:38 +01:00
|
|
|
camera->tag_modified();
|
|
|
|
|
dicing_camera->tag_modified();
|
|
|
|
|
film->tag_modified();
|
2012-11-09 08:46:53 +00:00
|
|
|
background->tag_update(this);
|
|
|
|
|
integrator->tag_update(this);
|
2014-06-05 17:39:16 +02:00
|
|
|
object_manager->tag_update(this);
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager->tag_update(this);
|
2014-06-05 17:39:16 +02:00
|
|
|
light_manager->tag_update(this);
|
|
|
|
|
particle_system_manager->tag_update(this);
|
2012-11-09 08:46:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Scene::device_free()
|
|
|
|
|
{
|
|
|
|
|
free_memory(false);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 15:46:13 +02:00
|
|
|
void Scene::collect_statistics(RenderStats *stats)
|
|
|
|
|
{
|
2020-02-02 12:04:19 +01:00
|
|
|
geometry_manager->collect_statistics(this, stats);
|
2018-07-27 15:46:13 +02:00
|
|
|
image_manager->collect_statistics(stats);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 23:16:01 +02:00
|
|
|
void Scene::enable_update_stats()
|
|
|
|
|
{
|
|
|
|
|
if (!update_stats) {
|
|
|
|
|
update_stats = new SceneUpdateStats();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 10:46:12 +02:00
|
|
|
DeviceRequestedFeatures Scene::get_requested_device_features()
|
|
|
|
|
{
|
|
|
|
|
DeviceRequestedFeatures requested_features;
|
|
|
|
|
|
|
|
|
|
shader_manager->get_requested_features(this, &requested_features);
|
|
|
|
|
|
|
|
|
|
/* This features are not being tweaked as often as shaders,
|
|
|
|
|
* so could be done selective magic for the viewport as well.
|
|
|
|
|
*/
|
|
|
|
|
bool use_motion = need_motion() == Scene::MotionType::MOTION_BLUR;
|
|
|
|
|
requested_features.use_hair = false;
|
|
|
|
|
requested_features.use_hair_thick = (params.hair_shape == CURVE_THICK);
|
|
|
|
|
requested_features.use_object_motion = false;
|
|
|
|
|
requested_features.use_camera_motion = use_motion && camera->use_motion();
|
|
|
|
|
foreach (Object *object, objects) {
|
2020-11-04 11:17:38 +01:00
|
|
|
Geometry *geom = object->get_geometry();
|
2020-08-18 10:46:12 +02:00
|
|
|
if (use_motion) {
|
2020-11-04 11:17:38 +01:00
|
|
|
requested_features.use_object_motion |= object->use_motion() | geom->get_use_motion_blur();
|
|
|
|
|
requested_features.use_camera_motion |= geom->get_use_motion_blur();
|
2020-08-18 10:46:12 +02:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
if (object->get_is_shadow_catcher()) {
|
2020-08-18 10:46:12 +02:00
|
|
|
requested_features.use_shadow_tricks = true;
|
|
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
if (geom->is_mesh()) {
|
2020-08-18 10:46:12 +02:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(geom);
|
|
|
|
|
#ifdef WITH_OPENSUBDIV
|
2020-11-04 11:17:38 +01:00
|
|
|
if (mesh->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
|
2020-08-18 10:46:12 +02:00
|
|
|
requested_features.use_patch_evaluation = true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
requested_features.use_true_displacement |= mesh->has_true_displacement();
|
|
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (geom->is_hair()) {
|
2020-08-18 10:46:12 +02:00
|
|
|
requested_features.use_hair = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requested_features.use_background_light = light_manager->has_background_light(this);
|
|
|
|
|
|
|
|
|
|
requested_features.use_baking = bake_manager->get_baking();
|
2020-11-04 11:17:38 +01:00
|
|
|
requested_features.use_integrator_branched = (integrator->get_method() ==
|
|
|
|
|
Integrator::BRANCHED_PATH);
|
|
|
|
|
if (film->get_denoising_data_pass()) {
|
2020-08-18 10:46:12 +02:00
|
|
|
requested_features.use_denoising = true;
|
|
|
|
|
requested_features.use_shadow_tricks = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return requested_features;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Scene::update(Progress &progress, bool &kernel_switch_needed)
|
|
|
|
|
{
|
|
|
|
|
/* update scene */
|
|
|
|
|
if (need_update()) {
|
|
|
|
|
/* Updated used shader tag so we know which features are need for the kernel. */
|
|
|
|
|
shader_manager->update_shaders_used(this);
|
|
|
|
|
|
|
|
|
|
/* Update max_closures. */
|
|
|
|
|
KernelIntegrator *kintegrator = &dscene.data.integrator;
|
|
|
|
|
if (params.background) {
|
|
|
|
|
kintegrator->max_closures = get_max_closure_count();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Currently viewport render is faster with higher max_closures, needs investigating. */
|
|
|
|
|
kintegrator->max_closures = MAX_CLOSURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Load render kernels, before device update where we upload data to the GPU. */
|
|
|
|
|
bool new_kernels_needed = load_kernels(progress, false);
|
|
|
|
|
|
|
|
|
|
progress.set_status("Updating Scene");
|
|
|
|
|
MEM_GUARDED_CALL(&progress, device_update, device, progress);
|
|
|
|
|
|
|
|
|
|
DeviceKernelStatus kernel_switch_status = device->get_active_kernel_switch_state();
|
|
|
|
|
kernel_switch_needed = kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE ||
|
|
|
|
|
kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_INVALID;
|
|
|
|
|
if (kernel_switch_status == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) {
|
|
|
|
|
progress.set_kernel_status("Compiling render kernels");
|
|
|
|
|
}
|
|
|
|
|
if (new_kernels_needed || kernel_switch_needed) {
|
|
|
|
|
progress.set_kernel_status("Compiling render kernels");
|
|
|
|
|
device->wait_for_availability(loaded_kernel_features);
|
|
|
|
|
progress.set_kernel_status("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Scene::load_kernels(Progress &progress, bool lock_scene)
|
|
|
|
|
{
|
|
|
|
|
thread_scoped_lock scene_lock;
|
|
|
|
|
if (lock_scene) {
|
|
|
|
|
scene_lock = thread_scoped_lock(mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeviceRequestedFeatures requested_features = get_requested_device_features();
|
|
|
|
|
|
|
|
|
|
if (!kernels_loaded || loaded_kernel_features.modified(requested_features)) {
|
|
|
|
|
progress.set_status("Loading render kernels (may take a few minutes the first time)");
|
|
|
|
|
|
|
|
|
|
scoped_timer timer;
|
|
|
|
|
|
|
|
|
|
VLOG(2) << "Requested features:\n" << requested_features;
|
|
|
|
|
if (!device->load_kernels(requested_features)) {
|
|
|
|
|
string message = device->error_message();
|
|
|
|
|
if (message.empty())
|
|
|
|
|
message = "Failed loading render kernel, see console for errors";
|
|
|
|
|
|
|
|
|
|
progress.set_error(message);
|
|
|
|
|
progress.set_status(message);
|
|
|
|
|
progress.set_update();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progress.add_skip_time(timer, false);
|
|
|
|
|
VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start();
|
|
|
|
|
|
|
|
|
|
kernels_loaded = true;
|
|
|
|
|
loaded_kernel_features = requested_features;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Scene::get_max_closure_count()
|
|
|
|
|
{
|
|
|
|
|
if (shader_manager->use_osl()) {
|
|
|
|
|
/* OSL always needs the maximum as we can't predict the
|
|
|
|
|
* number of closures a shader might generate. */
|
|
|
|
|
return MAX_CLOSURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int max_closures = 0;
|
|
|
|
|
for (int i = 0; i < shaders.size(); i++) {
|
|
|
|
|
Shader *shader = shaders[i];
|
|
|
|
|
if (shader->used) {
|
|
|
|
|
int num_closures = shader->graph->get_num_closures();
|
|
|
|
|
max_closures = max(max_closures, num_closures);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
max_closure_global = max(max_closure_global, max_closures);
|
|
|
|
|
|
|
|
|
|
if (max_closure_global > MAX_CLOSURE) {
|
|
|
|
|
/* This is usually harmless as more complex shader tend to get many
|
|
|
|
|
* closures discarded due to mixing or low weights. We need to limit
|
|
|
|
|
* to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it
|
|
|
|
|
* avoids excessive memory usage for split kernels. */
|
|
|
|
|
VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > "
|
|
|
|
|
<< MAX_CLOSURE;
|
|
|
|
|
|
|
|
|
|
max_closure_global = MAX_CLOSURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return max_closure_global;
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
template<> Light *Scene::create_node<Light>()
|
|
|
|
|
{
|
|
|
|
|
Light *node = new Light();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
lights.push_back(node);
|
|
|
|
|
light_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> Mesh *Scene::create_node<Mesh>()
|
|
|
|
|
{
|
|
|
|
|
Mesh *node = new Mesh();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
geometry.push_back(node);
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> Hair *Scene::create_node<Hair>()
|
|
|
|
|
{
|
|
|
|
|
Hair *node = new Hair();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
geometry.push_back(node);
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> Volume *Scene::create_node<Volume>()
|
|
|
|
|
{
|
|
|
|
|
Volume *node = new Volume();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
geometry.push_back(node);
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> Object *Scene::create_node<Object>()
|
|
|
|
|
{
|
|
|
|
|
Object *node = new Object();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
objects.push_back(node);
|
|
|
|
|
object_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> ParticleSystem *Scene::create_node<ParticleSystem>()
|
|
|
|
|
{
|
|
|
|
|
ParticleSystem *node = new ParticleSystem();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
particle_systems.push_back(node);
|
|
|
|
|
particle_system_manager->tag_update(this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> Shader *Scene::create_node<Shader>()
|
|
|
|
|
{
|
|
|
|
|
Shader *node = new Shader();
|
|
|
|
|
node->set_owner(this);
|
|
|
|
|
shaders.push_back(node);
|
|
|
|
|
shader_manager->need_update = true;
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T> void delete_node_from_array(vector<T> &nodes, T node)
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < nodes.size(); ++i) {
|
|
|
|
|
if (nodes[i] == node) {
|
|
|
|
|
std::swap(nodes[i], nodes[nodes.size() - 1]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodes.resize(nodes.size() - 1);
|
|
|
|
|
delete node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Light *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(lights, node);
|
|
|
|
|
light_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Mesh *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Hair *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Volume *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(geometry, static_cast<Geometry *>(node));
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Geometry *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(geometry, node);
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Object *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(objects, node);
|
|
|
|
|
object_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(ParticleSystem *node)
|
|
|
|
|
{
|
|
|
|
|
delete_node_from_array(particle_systems, node);
|
|
|
|
|
particle_system_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_node_impl(Shader * /*node*/)
|
|
|
|
|
{
|
|
|
|
|
/* don't delete unused shaders, not supported */
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 14:40:29 +01:00
|
|
|
template<typename T>
|
|
|
|
|
static void remove_nodes_in_set(const set<T *> &nodes_set,
|
|
|
|
|
vector<T *> &nodes_array,
|
|
|
|
|
const NodeOwner *owner)
|
|
|
|
|
{
|
|
|
|
|
size_t new_size = nodes_array.size();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < new_size; ++i) {
|
|
|
|
|
T *node = nodes_array[i];
|
|
|
|
|
|
|
|
|
|
if (nodes_set.find(node) != nodes_set.end()) {
|
|
|
|
|
std::swap(nodes_array[i], nodes_array[new_size - 1]);
|
|
|
|
|
|
|
|
|
|
assert(node->get_owner() == owner);
|
|
|
|
|
delete node;
|
|
|
|
|
|
|
|
|
|
i -= 1;
|
|
|
|
|
new_size -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodes_array.resize(new_size);
|
|
|
|
|
(void)owner;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_nodes(const set<Light *> &nodes, const NodeOwner *owner)
|
|
|
|
|
{
|
|
|
|
|
remove_nodes_in_set(nodes, lights, owner);
|
|
|
|
|
light_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_nodes(const set<Geometry *> &nodes, const NodeOwner *owner)
|
|
|
|
|
{
|
|
|
|
|
remove_nodes_in_set(nodes, geometry, owner);
|
|
|
|
|
geometry_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_nodes(const set<Object *> &nodes, const NodeOwner *owner)
|
|
|
|
|
{
|
|
|
|
|
remove_nodes_in_set(nodes, objects, owner);
|
|
|
|
|
object_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_nodes(const set<ParticleSystem *> &nodes, const NodeOwner *owner)
|
|
|
|
|
{
|
|
|
|
|
remove_nodes_in_set(nodes, particle_systems, owner);
|
|
|
|
|
particle_system_manager->tag_update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<> void Scene::delete_nodes(const set<Shader *> & /*nodes*/, const NodeOwner * /*owner*/)
|
|
|
|
|
{
|
|
|
|
|
/* don't delete unused shaders, not supported */
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|