diff options
Diffstat (limited to 'intern/cycles/render/object.cpp')
-rw-r--r-- | intern/cycles/render/object.cpp | 997 |
1 files changed, 0 insertions, 997 deletions
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp deleted file mode 100644 index 6d5c537e33d..00000000000 --- a/intern/cycles/render/object.cpp +++ /dev/null @@ -1,997 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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 - * limitations under the License. - */ - -#include "render/object.h" -#include "device/device.h" -#include "render/camera.h" -#include "render/curves.h" -#include "render/hair.h" -#include "render/integrator.h" -#include "render/light.h" -#include "render/mesh.h" -#include "render/particles.h" -#include "render/scene.h" -#include "render/stats.h" -#include "render/volume.h" - -#include "util/util_foreach.h" -#include "util/util_logging.h" -#include "util/util_map.h" -#include "util/util_murmurhash.h" -#include "util/util_progress.h" -#include "util/util_set.h" -#include "util/util_task.h" -#include "util/util_vector.h" - -#include "subd/subd_patch_table.h" - -CCL_NAMESPACE_BEGIN - -/* Global state of object transform update. */ - -struct UpdateObjectTransformState { - /* Global state used by device_update_object_transform(). - * Common for both threaded and non-threaded update. - */ - - /* Type of the motion required by the scene settings. */ - Scene::MotionType need_motion; - - /* Mapping from particle system to a index in packed particle array. - * Only used for read. - */ - map<ParticleSystem *, int> particle_offset; - - /* Motion offsets for each object. */ - array<uint> motion_offset; - - /* Packed object arrays. Those will be filled in. */ - uint *object_flag; - uint *object_visibility; - KernelObject *objects; - Transform *object_motion_pass; - DecomposedTransform *object_motion; - float *object_volume_step; - - /* Flags which will be synchronized to Integrator. */ - bool have_motion; - bool have_curves; - - /* ** Scheduling queue. ** */ - Scene *scene; - - /* First unused object index in the queue. */ - int queue_start_object; -}; - -/* Object */ - -NODE_DEFINE(Object) -{ - NodeType *type = NodeType::add("object", create); - - SOCKET_NODE(geometry, "Geometry", Geometry::get_node_base_type()); - SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_UINT(visibility, "Visibility", ~0); - SOCKET_COLOR(color, "Color", zero_float3()); - SOCKET_UINT(random_id, "Random ID", 0); - SOCKET_INT(pass_id, "Pass ID", 0); - SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); - SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false); - SOCKET_POINT(dupli_generated, "Dupli Generated", zero_float3()); - SOCKET_POINT2(dupli_uv, "Dupli UV", zero_float2()); - SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>()); - SOCKET_FLOAT(shadow_terminator_shading_offset, "Shadow Terminator Shading Offset", 0.0f); - SOCKET_FLOAT(shadow_terminator_geometry_offset, "Shadow Terminator Geometry Offset", 0.1f); - SOCKET_STRING(asset_name, "Asset Name", ustring()); - - SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); - - SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type()); - SOCKET_INT(particle_index, "Particle Index", 0); - - SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f); - - return type; -} - -Object::Object() : Node(get_node_type()) -{ - particle_system = NULL; - particle_index = 0; - attr_map_offset = 0; - bounds = BoundBox::empty; -} - -Object::~Object() -{ -} - -void Object::update_motion() -{ - if (!use_motion()) { - return; - } - - bool have_motion = false; - - for (size_t i = 0; i < motion.size(); i++) { - if (motion[i] == transform_empty()) { - if (hide_on_missing_motion) { - /* Hide objects that have no valid previous or next - * transform, for example particle that stop existing. It - * would be better to handle this in the kernel and make - * objects invisible outside certain motion steps. */ - tfm = transform_empty(); - motion.clear(); - return; - } - else { - /* Otherwise just copy center motion. */ - motion[i] = tfm; - } - } - - /* Test if any of the transforms are actually different. */ - have_motion = have_motion || motion[i] != tfm; - } - - /* Clear motion array if there is no actual motion. */ - if (!have_motion) { - motion.clear(); - } -} - -void Object::compute_bounds(bool motion_blur) -{ - BoundBox mbounds = geometry->bounds; - - if (motion_blur && use_motion()) { - array<DecomposedTransform> decomp(motion.size()); - transform_motion_decompose(decomp.data(), motion.data(), motion.size()); - - bounds = BoundBox::empty; - - /* TODO: this is really terrible. according to PBRT there is a better - * way to find this iteratively, but did not find implementation yet - * or try to implement myself */ - for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) { - Transform ttfm; - - transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t); - bounds.grow(mbounds.transformed(&ttfm)); - } - } - else { - /* No motion blur case. */ - if (geometry->transform_applied) { - bounds = mbounds; - } - else { - bounds = mbounds.transformed(&tfm); - } - } -} - -void Object::apply_transform(bool apply_to_motion) -{ - if (!geometry || tfm == transform_identity()) - return; - - geometry->apply_transform(tfm, apply_to_motion); - - /* we keep normals pointing in same direction on negative scale, notify - * geometry about this in it (re)calculates normals */ - if (transform_negative_scale(tfm)) - geometry->transform_negative_scaled = true; - - if (bounds.valid()) { - geometry->compute_bounds(); - compute_bounds(false); - } - - /* tfm is not reset to identity, all code that uses it needs to check the - * transform_applied boolean */ -} - -void Object::tag_update(Scene *scene) -{ - uint32_t flag = ObjectManager::UPDATE_NONE; - - if (is_modified()) { - flag |= ObjectManager::OBJECT_MODIFIED; - - if (use_holdout_is_modified()) { - flag |= ObjectManager::HOLDOUT_MODIFIED; - } - - if (is_shadow_catcher_is_modified()) { - scene->tag_shadow_catcher_modified(); - } - } - - if (geometry) { - if (tfm_is_modified()) { - flag |= ObjectManager::TRANSFORM_MODIFIED; - } - - if (visibility_is_modified()) { - flag |= ObjectManager::VISIBILITY_MODIFIED; - } - - foreach (Node *node, geometry->get_used_shaders()) { - Shader *shader = static_cast<Shader *>(node); - if (shader->get_use_mis() && shader->has_surface_emission) - scene->light_manager->tag_update(scene, LightManager::EMISSIVE_MESH_MODIFIED); - } - } - - scene->camera->need_flags_update = true; - scene->object_manager->tag_update(scene, flag); -} - -bool Object::use_motion() const -{ - return (motion.size() > 1); -} - -float Object::motion_time(int step) const -{ - return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; -} - -int Object::motion_step(float time) const -{ - if (use_motion()) { - for (size_t step = 0; step < motion.size(); step++) { - if (time == motion_time(step)) { - return step; - } - } - } - - return -1; -} - -bool Object::is_traceable() const -{ - /* Mesh itself can be empty,can skip all such objects. */ - if (!bounds.valid() || bounds.size() == zero_float3()) { - return false; - } - /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ - return true; -} - -uint Object::visibility_for_tracing() const -{ - return SHADOW_CATCHER_OBJECT_VISIBILITY(is_shadow_catcher, visibility & PATH_RAY_ALL_VISIBILITY); -} - -float Object::compute_volume_step_size() const -{ - if (geometry->geometry_type != Geometry::MESH && geometry->geometry_type != Geometry::VOLUME) { - return FLT_MAX; - } - - Mesh *mesh = static_cast<Mesh *>(geometry); - - if (!mesh->has_volume) { - return FLT_MAX; - } - - /* Compute step rate from shaders. */ - float step_rate = FLT_MAX; - - foreach (Node *node, mesh->get_used_shaders()) { - Shader *shader = static_cast<Shader *>(node); - if (shader->has_volume) { - if ((shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) || - (shader->has_volume_attribute_dependency)) { - step_rate = fminf(shader->get_volume_step_rate(), step_rate); - } - } - } - - if (step_rate == FLT_MAX) { - return FLT_MAX; - } - - /* Compute step size from voxel grids. */ - float step_size = FLT_MAX; - - if (geometry->geometry_type == Geometry::VOLUME) { - Volume *volume = static_cast<Volume *>(geometry); - - foreach (Attribute &attr, volume->attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - ImageHandle &handle = attr.data_voxel(); - const ImageMetaData &metadata = handle.metadata(); - if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) { - continue; - } - - /* User specified step size. */ - float voxel_step_size = volume->get_step_size(); - - if (voxel_step_size == 0.0f) { - /* Auto detect step size. */ - float3 size = one_float3(); -#ifdef WITH_NANOVDB - /* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */ - if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT && - metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) -#endif - size /= make_float3(metadata.width, metadata.height, metadata.depth); - - /* Step size is transformed from voxel to world space. */ - Transform voxel_tfm = tfm; - if (metadata.use_transform_3d) { - voxel_tfm = tfm * transform_inverse(metadata.transform_3d); - } - voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size))); - } - else if (volume->get_object_space()) { - /* User specified step size in object space. */ - float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size); - voxel_step_size = min3(fabs(transform_direction(&tfm, size))); - } - - if (voxel_step_size > 0.0f) { - step_size = fminf(voxel_step_size, step_size); - } - } - } - } - - if (step_size == FLT_MAX) { - /* Fall back to 1/10th of bounds for procedural volumes. */ - step_size = 0.1f * average(bounds.size()); - } - - step_size *= step_rate; - - return step_size; -} - -bool Object::check_is_volume() const -{ - if (geometry->geometry_type == Geometry::VOLUME) { - return true; - } - - for (Node *node : get_geometry()->get_used_shaders()) { - const Shader *shader = static_cast<const Shader *>(node); - if (shader->has_volume) { - return true; - } - } - - return false; -} - -int Object::get_device_index() const -{ - return index; -} - -/* Object Manager */ - -ObjectManager::ObjectManager() -{ - update_flags = UPDATE_ALL; - need_flags_update = true; -} - -ObjectManager::~ObjectManager() -{ -} - -static float object_volume_density(const Transform &tfm, Geometry *geom) -{ - if (geom->geometry_type == Geometry::VOLUME) { - /* Volume density automatically adjust to object scale. */ - if (static_cast<Volume *>(geom)->get_object_space()) { - const float3 unit = normalize(one_float3()); - return 1.0f / len(transform_direction(&tfm, unit)); - } - } - - return 1.0f; -} - -void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, - Object *ob, - bool update_all) -{ - KernelObject &kobject = state->objects[ob->index]; - Transform *object_motion_pass = state->object_motion_pass; - - Geometry *geom = ob->geometry; - uint flag = 0; - - /* Compute transformations. */ - Transform tfm = ob->tfm; - Transform itfm = transform_inverse(tfm); - - float3 color = ob->color; - float pass_id = ob->pass_id; - float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF); - int particle_index = (ob->particle_system) ? - ob->particle_index + state->particle_offset[ob->particle_system] : - 0; - - kobject.tfm = tfm; - kobject.itfm = itfm; - kobject.volume_density = object_volume_density(tfm, geom); - kobject.color[0] = color.x; - kobject.color[1] = color.y; - kobject.color[2] = color.z; - kobject.pass_id = pass_id; - kobject.random_number = random_number; - kobject.particle_index = particle_index; - kobject.motion_offset = 0; - kobject.ao_distance = ob->ao_distance; - - if (geom->get_use_motion_blur()) { - state->have_motion = true; - } - - if (geom->geometry_type == Geometry::MESH) { - /* TODO: why only mesh? */ - Mesh *mesh = static_cast<Mesh *>(geom); - if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { - flag |= SD_OBJECT_HAS_VERTEX_MOTION; - } - } - - if (state->need_motion == Scene::MOTION_PASS) { - /* Clear motion array if there is no actual motion. */ - ob->update_motion(); - - /* Compute motion transforms. */ - Transform tfm_pre, tfm_post; - if (ob->use_motion()) { - tfm_pre = ob->motion[0]; - tfm_post = ob->motion[ob->motion.size() - 1]; - } - else { - tfm_pre = tfm; - tfm_post = tfm; - } - - /* Motion transformations, is world/object space depending if mesh - * comes with deformed position in object space, or if we transform - * the shading point in world space. */ - if (!(flag & SD_OBJECT_HAS_VERTEX_MOTION)) { - tfm_pre = tfm_pre * itfm; - tfm_post = tfm_post * itfm; - } - - int motion_pass_offset = ob->index * OBJECT_MOTION_PASS_SIZE; - object_motion_pass[motion_pass_offset + 0] = tfm_pre; - object_motion_pass[motion_pass_offset + 1] = tfm_post; - } - else if (state->need_motion == Scene::MOTION_BLUR) { - if (ob->use_motion()) { - kobject.motion_offset = state->motion_offset[ob->index]; - - /* Decompose transforms for interpolation. */ - if (ob->tfm_is_modified() || update_all) { - DecomposedTransform *decomp = state->object_motion + kobject.motion_offset; - transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size()); - } - - flag |= SD_OBJECT_MOTION; - state->have_motion = true; - } - } - - /* Dupli object coords and motion info. */ - kobject.dupli_generated[0] = ob->dupli_generated[0]; - kobject.dupli_generated[1] = ob->dupli_generated[1]; - kobject.dupli_generated[2] = ob->dupli_generated[2]; - kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ? - static_cast<Hair *>(geom)->get_curve_keys().size() : - 0; - kobject.dupli_uv[0] = ob->dupli_uv[0]; - kobject.dupli_uv[1] = ob->dupli_uv[1]; - int totalsteps = geom->get_motion_steps(); - kobject.numsteps = (totalsteps - 1) / 2; - kobject.numverts = (geom->geometry_type == Geometry::MESH || - geom->geometry_type == Geometry::VOLUME) ? - static_cast<Mesh *>(geom)->get_verts().size() : - 0; - kobject.patch_map_offset = 0; - kobject.attribute_map_offset = 0; - - if (ob->asset_name_is_modified() || update_all) { - uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); - uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); - kobject.cryptomatte_object = util_hash_to_float(hash_name); - kobject.cryptomatte_asset = util_hash_to_float(hash_asset); - } - - kobject.shadow_terminator_shading_offset = 1.0f / - (1.0f - 0.5f * ob->shadow_terminator_shading_offset); - kobject.shadow_terminator_geometry_offset = ob->shadow_terminator_geometry_offset; - - kobject.visibility = ob->visibility_for_tracing(); - kobject.primitive_type = geom->primitive_type(); - - /* Object flag. */ - if (ob->use_holdout) { - flag |= SD_OBJECT_HOLDOUT_MASK; - } - state->object_flag[ob->index] = flag; - state->object_volume_step[ob->index] = FLT_MAX; - - /* Have curves. */ - if (geom->geometry_type == Geometry::HAIR) { - state->have_curves = true; - } -} - -void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) -{ - UpdateObjectTransformState state; - state.need_motion = scene->need_motion(); - state.have_motion = false; - state.have_curves = false; - state.scene = scene; - state.queue_start_object = 0; - - state.objects = dscene->objects.alloc(scene->objects.size()); - state.object_flag = dscene->object_flag.alloc(scene->objects.size()); - state.object_volume_step = dscene->object_volume_step.alloc(scene->objects.size()); - state.object_motion = NULL; - state.object_motion_pass = NULL; - - if (state.need_motion == Scene::MOTION_PASS) { - state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE * - scene->objects.size()); - } - else if (state.need_motion == Scene::MOTION_BLUR) { - /* Set object offsets into global object motion array. */ - uint *motion_offsets = state.motion_offset.resize(scene->objects.size()); - uint motion_offset = 0; - - foreach (Object *ob, scene->objects) { - *motion_offsets = motion_offset; - motion_offsets++; - - /* Clear motion array if there is no actual motion. */ - ob->update_motion(); - motion_offset += ob->motion.size(); - } - - state.object_motion = dscene->object_motion.alloc(motion_offset); - } - - /* Particle system device offsets - * 0 is dummy particle, index starts at 1. - */ - int numparticles = 1; - foreach (ParticleSystem *psys, scene->particle_systems) { - state.particle_offset[psys] = numparticles; - numparticles += psys->particles.size(); - } - - /* as all the arrays are the same size, checking only dscene.objects is sufficient */ - const bool update_all = dscene->objects.need_realloc(); - - /* Parallel object update, with grain size to avoid too much threading overhead - * for individual objects. */ - static const int OBJECTS_PER_TASK = 32; - parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK), - [&](const blocked_range<size_t> &r) { - for (size_t i = r.begin(); i != r.end(); i++) { - Object *ob = state.scene->objects[i]; - device_update_object_transform(&state, ob, update_all); - } - }); - - if (progress.get_cancel()) { - return; - } - - dscene->objects.copy_to_device_if_modified(); - if (state.need_motion == Scene::MOTION_PASS) { - dscene->object_motion_pass.copy_to_device(); - } - else if (state.need_motion == Scene::MOTION_BLUR) { - dscene->object_motion.copy_to_device(); - } - - dscene->data.bvh.have_motion = state.have_motion; - dscene->data.bvh.have_curves = state.have_curves; - - dscene->objects.clear_modified(); - dscene->object_motion_pass.clear_modified(); - dscene->object_motion.clear_modified(); -} - -void ObjectManager::device_update(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - if (!need_update()) - return; - - if (update_flags & (OBJECT_ADDED | OBJECT_REMOVED)) { - dscene->objects.tag_realloc(); - dscene->object_motion_pass.tag_realloc(); - dscene->object_motion.tag_realloc(); - dscene->object_flag.tag_realloc(); - dscene->object_volume_step.tag_realloc(); - } - - if (update_flags & HOLDOUT_MODIFIED) { - dscene->object_flag.tag_modified(); - } - - if (update_flags & PARTICLE_MODIFIED) { - dscene->objects.tag_modified(); - } - - VLOG(1) << "Total " << scene->objects.size() << " objects."; - - device_free(device, dscene, false); - - if (scene->objects.size() == 0) - return; - - { - /* Assign object IDs. */ - scoped_callback_timer timer([scene](double time) { - if (scene->update_stats) { - scene->update_stats->object.times.add_entry({"device_update (assign index)", time}); - } - }); - - int index = 0; - foreach (Object *object, scene->objects) { - object->index = index++; - - /* this is a bit too broad, however a bigger refactor might be needed to properly separate - * update each type of data (transform, flags, etc.) */ - if (object->is_modified()) { - dscene->objects.tag_modified(); - dscene->object_motion_pass.tag_modified(); - dscene->object_motion.tag_modified(); - dscene->object_flag.tag_modified(); - dscene->object_volume_step.tag_modified(); - } - } - } - - { - /* set object transform matrices, before applying static transforms */ - scoped_callback_timer timer([scene](double time) { - if (scene->update_stats) { - scene->update_stats->object.times.add_entry( - {"device_update (copy objects to device)", time}); - } - }); - - progress.set_status("Updating Objects", "Copying Transformations to device"); - device_update_transforms(dscene, scene, progress); - } - - if (progress.get_cancel()) - return; - - /* prepare for static BVH building */ - /* todo: do before to support getting object level coords? */ - if (scene->params.bvh_type == BVH_TYPE_STATIC) { - scoped_callback_timer timer([scene](double time) { - if (scene->update_stats) { - scene->update_stats->object.times.add_entry( - {"device_update (apply static transforms)", time}); - } - }); - - progress.set_status("Updating Objects", "Applying Static Transformations"); - apply_static_transforms(dscene, scene, progress); - } - - foreach (Object *object, scene->objects) { - object->clear_modified(); - } -} - -void ObjectManager::device_update_flags( - Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid) -{ - if (!need_update() && !need_flags_update) - return; - - scoped_callback_timer timer([scene](double time) { - if (scene->update_stats) { - scene->update_stats->object.times.add_entry({"device_update_flags", time}); - } - }); - - update_flags = UPDATE_NONE; - need_flags_update = false; - - if (scene->objects.size() == 0) - return; - - /* Object info flag. */ - uint *object_flag = dscene->object_flag.data(); - float *object_volume_step = dscene->object_volume_step.data(); - - /* Object volume intersection. */ - vector<Object *> volume_objects; - bool has_volume_objects = false; - foreach (Object *object, scene->objects) { - if (object->geometry->has_volume) { - if (bounds_valid) { - volume_objects.push_back(object); - } - has_volume_objects = true; - object_volume_step[object->index] = object->compute_volume_step_size(); - } - else { - object_volume_step[object->index] = FLT_MAX; - } - } - - foreach (Object *object, scene->objects) { - if (object->geometry->has_volume) { - object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; - object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; - - foreach (Attribute &attr, object->geometry->attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; - } - } - } - else { - object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES); - } - - if (object->is_shadow_catcher) { - object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER; - } - else { - object_flag[object->index] &= ~SD_OBJECT_SHADOW_CATCHER; - } - - if (bounds_valid) { - foreach (Object *volume_object, volume_objects) { - if (object == volume_object) { - continue; - } - if (object->bounds.intersects(volume_object->bounds)) { - object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; - break; - } - } - } - else if (has_volume_objects) { - /* Not really valid, but can't make more reliable in the case - * of bounds not being up to date. - */ - object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; - } - } - - /* Copy object flag. */ - dscene->object_flag.copy_to_device(); - dscene->object_volume_step.copy_to_device(); - - dscene->object_flag.clear_modified(); - dscene->object_volume_step.clear_modified(); -} - -void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) -{ - if (dscene->objects.size() == 0) { - return; - } - - KernelObject *kobjects = dscene->objects.data(); - - bool update = false; - - foreach (Object *object, scene->objects) { - Geometry *geom = object->geometry; - - if (geom->geometry_type == Geometry::MESH) { - Mesh *mesh = static_cast<Mesh *>(geom); - if (mesh->patch_table) { - uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - - mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - - mesh->patch_offset; - - if (kobjects[object->index].patch_map_offset != patch_map_offset) { - kobjects[object->index].patch_map_offset = patch_map_offset; - update = true; - } - } - } - - size_t attr_map_offset = object->attr_map_offset; - - /* An object attribute map cannot have a zero offset because mesh maps come first. */ - if (attr_map_offset == 0) { - attr_map_offset = geom->attr_map_offset; - } - - if (kobjects[object->index].attribute_map_offset != attr_map_offset) { - kobjects[object->index].attribute_map_offset = attr_map_offset; - update = true; - } - } - - if (update) { - dscene->objects.copy_to_device(); - } -} - -void ObjectManager::device_free(Device *, DeviceScene *dscene, bool force_free) -{ - dscene->objects.free_if_need_realloc(force_free); - dscene->object_motion_pass.free_if_need_realloc(force_free); - dscene->object_motion.free_if_need_realloc(force_free); - dscene->object_flag.free_if_need_realloc(force_free); - dscene->object_volume_step.free_if_need_realloc(force_free); -} - -void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) -{ - /* todo: normals and displacement should be done before applying transform! */ - /* todo: create objects/geometry in right order! */ - - /* counter geometry users */ - map<Geometry *, int> geometry_users; - Scene::MotionType need_motion = scene->need_motion(); - bool motion_blur = need_motion == Scene::MOTION_BLUR; - bool apply_to_motion = need_motion != Scene::MOTION_PASS; - int i = 0; - - foreach (Object *object, scene->objects) { - map<Geometry *, int>::iterator it = geometry_users.find(object->geometry); - - if (it == geometry_users.end()) - geometry_users[object->geometry] = 1; - else - it->second++; - } - - if (progress.get_cancel()) - return; - - uint *object_flag = dscene->object_flag.data(); - - /* apply transforms for objects with single user geometry */ - foreach (Object *object, scene->objects) { - /* Annoying feedback loop here: we can't use is_instanced() because - * it'll use uninitialized transform_applied flag. - * - * Could be solved by moving reference counter to Geometry. - */ - Geometry *geom = object->geometry; - bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf && - !geom->has_true_displacement(); - - if (geom->geometry_type == Geometry::MESH) { - Mesh *mesh = static_cast<Mesh *>(geom); - apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE; - } - else if (geom->geometry_type == Geometry::HAIR) { - /* Can't apply non-uniform scale to curves, this can't be represented by - * control points and radius alone. */ - float scale; - apply = apply && transform_uniform_scale(object->tfm, scale); - } - - if (apply) { - if (!(motion_blur && object->use_motion())) { - if (!geom->transform_applied) { - object->apply_transform(apply_to_motion); - geom->transform_applied = true; - - if (progress.get_cancel()) - return; - } - - object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; - if (geom->transform_negative_scaled) - object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; - } - } - - i++; - } -} - -void ObjectManager::tag_update(Scene *scene, uint32_t flag) -{ - update_flags |= flag; - - /* avoid infinite loops if the geometry manager tagged us for an update */ - if ((flag & GEOMETRY_MANAGER) == 0) { - uint32_t geometry_flag = GeometryManager::OBJECT_MANAGER; - - /* Also notify in case added or removed objects were instances, as no Geometry might have been - * added or removed, but the BVH still needs to updated. */ - if ((flag & (OBJECT_ADDED | OBJECT_REMOVED)) != 0) { - geometry_flag |= (GeometryManager::GEOMETRY_ADDED | GeometryManager::GEOMETRY_REMOVED); - } - - if ((flag & TRANSFORM_MODIFIED) != 0) { - geometry_flag |= GeometryManager::TRANSFORM_MODIFIED; - } - - if ((flag & VISIBILITY_MODIFIED) != 0) { - geometry_flag |= GeometryManager::VISIBILITY_MODIFIED; - } - - scene->geometry_manager->tag_update(scene, geometry_flag); - } - - scene->light_manager->tag_update(scene, LightManager::OBJECT_MANAGER); - - /* Integrator's shadow catcher settings depends on object visibility settings. */ - if (flag & (OBJECT_ADDED | OBJECT_REMOVED | OBJECT_MODIFIED)) { - scene->integrator->tag_update(scene, Integrator::OBJECT_MANAGER); - } -} - -bool ObjectManager::need_update() const -{ - return update_flags != UPDATE_NONE; -} - -string ObjectManager::get_cryptomatte_objects(Scene *scene) -{ - string manifest = "{"; - - unordered_set<ustring, ustringHash> objects; - foreach (Object *object, scene->objects) { - if (objects.count(object->name)) { - continue; - } - objects.insert(object->name); - uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0); - manifest += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name); - } - manifest[manifest.size() - 1] = '}'; - return manifest; -} - -string ObjectManager::get_cryptomatte_assets(Scene *scene) -{ - string manifest = "{"; - unordered_set<ustring, ustringHash> assets; - foreach (Object *ob, scene->objects) { - if (assets.count(ob->asset_name)) { - continue; - } - assets.insert(ob->asset_name); - uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); - manifest += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset); - } - manifest[manifest.size() - 1] = '}'; - return manifest; -} - -CCL_NAMESPACE_END |