Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/object.cpp
| Show First 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | void Object::update_motion() | ||||
| /* Clear motion array if there is no actual motion. */ | /* Clear motion array if there is no actual motion. */ | ||||
| if (!have_motion) { | if (!have_motion) { | ||||
| motion.clear(); | motion.clear(); | ||||
| } | } | ||||
| } | } | ||||
| void Object::compute_bounds(bool motion_blur) | void Object::compute_bounds(bool motion_blur) | ||||
| { | { | ||||
| BoundBox mbounds = geometry->bounds; | BoundBox mbounds = geometry->get_bounds(); | ||||
| if (motion_blur && use_motion()) { | if (motion_blur && use_motion()) { | ||||
| array<DecomposedTransform> decomp(motion.size()); | array<DecomposedTransform> decomp(motion.size()); | ||||
| transform_motion_decompose(decomp.data(), motion.data(), motion.size()); | transform_motion_decompose(decomp.data(), motion.data(), motion.size()); | ||||
| bounds = BoundBox::empty; | bounds = BoundBox::empty; | ||||
| /* TODO: this is really terrible. according to PBRT there is a better | /* TODO: this is really terrible. according to PBRT there is a better | ||||
| * way to find this iteratively, but did not find implementation yet | * way to find this iteratively, but did not find implementation yet | ||||
| * or try to implement myself */ | * or try to implement myself */ | ||||
| for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) { | for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) { | ||||
| Transform ttfm; | Transform ttfm; | ||||
| transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t); | transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t); | ||||
| bounds.grow(mbounds.transformed(&ttfm)); | bounds.grow(mbounds.transformed(&ttfm)); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* No motion blur case. */ | /* No motion blur case. */ | ||||
| if (geometry->transform_applied) { | if (geometry->get_transform_applied()) { | ||||
| bounds = mbounds; | bounds = mbounds; | ||||
| } | } | ||||
| else { | else { | ||||
| bounds = mbounds.transformed(&tfm); | bounds = mbounds.transformed(&tfm); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void Object::apply_transform(bool apply_to_motion) | void Object::apply_transform(bool apply_to_motion) | ||||
| { | { | ||||
| if (!geometry || tfm == transform_identity()) | if (!geometry || tfm == transform_identity()) | ||||
| return; | return; | ||||
| geometry->apply_transform(tfm, apply_to_motion); | geometry->apply_transform(tfm, apply_to_motion); | ||||
| /* we keep normals pointing in same direction on negative scale, notify | /* we keep normals pointing in same direction on negative scale, notify | ||||
| * geometry about this in it (re)calculates normals */ | * geometry about this in it (re)calculates normals */ | ||||
| if (transform_negative_scale(tfm)) | if (transform_negative_scale(tfm)) | ||||
| geometry->transform_negative_scaled = true; | geometry->set_transform_negative_scaled(true); | ||||
| if (bounds.valid()) { | if (bounds.valid()) { | ||||
| geometry->compute_bounds(); | geometry->compute_bounds(); | ||||
| compute_bounds(false); | compute_bounds(false); | ||||
| } | } | ||||
| /* tfm is not reset to identity, all code that uses it needs to check the | /* tfm is not reset to identity, all code that uses it needs to check the | ||||
| * transform_applied boolean */ | * transform_applied boolean */ | ||||
| } | } | ||||
| void Object::tag_update(Scene *scene) | void Object::tag_update(Scene *scene) | ||||
| { | { | ||||
| if (geometry) { | if (geometry) { | ||||
| if (geometry->transform_applied) | if (geometry->get_transform_applied()) | ||||
| geometry->tag_modified(); | geometry->tag_modified(); | ||||
| foreach (Node *node, geometry->get_used_shaders()) { | foreach (Node *node, geometry->get_used_shaders()) { | ||||
| Shader *shader = static_cast<Shader *>(node); | Shader *shader = static_cast<Shader *>(node); | ||||
| if (shader->get_use_mis() && shader->has_surface_emission) | if (shader->get_use_mis() && shader->get_has_surface_emission()) | ||||
| scene->light_manager->need_update = true; | scene->get_light_manager()->need_update = true; | ||||
| } | } | ||||
| } | } | ||||
| scene->camera->need_flags_update = true; | scene->get_camera()->need_flags_update = true; | ||||
| scene->geometry_manager->need_update = true; | scene->get_geometry_manager()->need_update = true; | ||||
| scene->object_manager->need_update = true; | scene->get_object_manager()->need_update = true; | ||||
| } | } | ||||
| bool Object::use_motion() const | bool Object::use_motion() const | ||||
| { | { | ||||
| return (motion.size() > 1); | return (motion.size() > 1); | ||||
| } | } | ||||
| float Object::motion_time(int step) const | float Object::motion_time(int step) const | ||||
| Show All 33 Lines | uint Object::visibility_for_tracing() const | ||||
| else { | else { | ||||
| trace_visibility &= ~PATH_RAY_SHADOW_CATCHER; | trace_visibility &= ~PATH_RAY_SHADOW_CATCHER; | ||||
| } | } | ||||
| return trace_visibility; | return trace_visibility; | ||||
| } | } | ||||
| float Object::compute_volume_step_size() const | float Object::compute_volume_step_size() const | ||||
| { | { | ||||
| if (geometry->geometry_type != Geometry::MESH && geometry->geometry_type != Geometry::VOLUME) { | if (!geometry->is_mesh() && !geometry->is_volume()) { | ||||
| return FLT_MAX; | return FLT_MAX; | ||||
| } | } | ||||
| Mesh *mesh = static_cast<Mesh *>(geometry); | Mesh *mesh = static_cast<Mesh *>(geometry); | ||||
| if (!mesh->has_volume) { | if (!mesh->get_has_volume()) { | ||||
| return FLT_MAX; | return FLT_MAX; | ||||
| } | } | ||||
| /* Compute step rate from shaders. */ | /* Compute step rate from shaders. */ | ||||
| float step_rate = FLT_MAX; | float step_rate = FLT_MAX; | ||||
| foreach (Node *node, mesh->get_used_shaders()) { | foreach (Node *node, mesh->get_used_shaders()) { | ||||
| Shader *shader = static_cast<Shader *>(node); | Shader *shader = static_cast<Shader *>(node); | ||||
| if (shader->has_volume) { | if (shader->get_has_volume()) { | ||||
| if ((shader->get_heterogeneous_volume() && shader->has_volume_spatial_varying) || | if ((shader->get_heterogeneous_volume() && shader->get_has_volume_spatial_varying()) || | ||||
| (shader->has_volume_attribute_dependency)) { | (shader->get_has_volume_attribute_dependency())) { | ||||
| step_rate = fminf(shader->get_volume_step_rate(), step_rate); | step_rate = fminf(shader->get_volume_step_rate(), step_rate); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (step_rate == FLT_MAX) { | if (step_rate == FLT_MAX) { | ||||
| return FLT_MAX; | return FLT_MAX; | ||||
| } | } | ||||
| /* Compute step size from voxel grids. */ | /* Compute step size from voxel grids. */ | ||||
| float step_size = FLT_MAX; | float step_size = FLT_MAX; | ||||
| if (geometry->geometry_type == Geometry::VOLUME) { | if (geometry->is_volume()) { | ||||
| Volume *volume = static_cast<Volume *>(geometry); | Volume *volume = static_cast<Volume *>(geometry); | ||||
| foreach (Attribute &attr, volume->attributes.attributes) { | foreach (Attribute &attr, volume->get_attributes().get_attributes()) { | ||||
| if (attr.element == ATTR_ELEMENT_VOXEL) { | if (attr.get_element() == ATTR_ELEMENT_VOXEL) { | ||||
| ImageHandle &handle = attr.data_voxel(); | ImageHandle &handle = attr.data_voxel(); | ||||
| const ImageMetaData &metadata = handle.metadata(); | const ImageMetaData &metadata = handle.metadata(); | ||||
| if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) { | if (metadata.width == 0 || metadata.height == 0 || metadata.depth == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* User specified step size. */ | /* User specified step size. */ | ||||
| float voxel_step_size = volume->get_step_size(); | float voxel_step_size = volume->get_step_size(); | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| ObjectManager::~ObjectManager() | ObjectManager::~ObjectManager() | ||||
| { | { | ||||
| } | } | ||||
| static float object_volume_density(const Transform &tfm, Geometry *geom) | static float object_volume_density(const Transform &tfm, Geometry *geom) | ||||
| { | { | ||||
| if (geom->geometry_type == Geometry::VOLUME) { | if (geom->is_volume()) { | ||||
| /* Volume density automatically adjust to object scale. */ | /* Volume density automatically adjust to object scale. */ | ||||
| if (static_cast<Volume *>(geom)->get_object_space()) { | if (static_cast<Volume *>(geom)->get_object_space()) { | ||||
| const float3 unit = normalize(make_float3(1.0f, 1.0f, 1.0f)); | const float3 unit = normalize(make_float3(1.0f, 1.0f, 1.0f)); | ||||
| return 1.0f / len(transform_direction(&tfm, unit)); | return 1.0f / len(transform_direction(&tfm, unit)); | ||||
| } | } | ||||
| } | } | ||||
| return 1.0f; | return 1.0f; | ||||
| Show All 28 Lines | void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob) | ||||
| kobject.random_number = random_number; | kobject.random_number = random_number; | ||||
| kobject.particle_index = particle_index; | kobject.particle_index = particle_index; | ||||
| kobject.motion_offset = 0; | kobject.motion_offset = 0; | ||||
| if (geom->get_use_motion_blur()) { | if (geom->get_use_motion_blur()) { | ||||
| state->have_motion = true; | state->have_motion = true; | ||||
| } | } | ||||
| if (geom->geometry_type == Geometry::MESH) { | if (geom->is_mesh()) { | ||||
| /* TODO: why only mesh? */ | /* TODO: why only mesh? */ | ||||
| Mesh *mesh = static_cast<Mesh *>(geom); | Mesh *mesh = static_cast<Mesh *>(geom); | ||||
| if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { | if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { | ||||
| flag |= SD_OBJECT_HAS_VERTEX_MOTION; | flag |= SD_OBJECT_HAS_VERTEX_MOTION; | ||||
| } | } | ||||
| } | } | ||||
| if (state->need_motion == Scene::MOTION_PASS) { | if (state->need_motion == Scene::MOTION_PASS) { | ||||
| Show All 34 Lines | if (ob->use_motion()) { | ||||
| state->have_motion = true; | state->have_motion = true; | ||||
| } | } | ||||
| } | } | ||||
| /* Dupli object coords and motion info. */ | /* Dupli object coords and motion info. */ | ||||
| kobject.dupli_generated[0] = ob->dupli_generated[0]; | kobject.dupli_generated[0] = ob->dupli_generated[0]; | ||||
| kobject.dupli_generated[1] = ob->dupli_generated[1]; | kobject.dupli_generated[1] = ob->dupli_generated[1]; | ||||
| kobject.dupli_generated[2] = ob->dupli_generated[2]; | kobject.dupli_generated[2] = ob->dupli_generated[2]; | ||||
| kobject.numkeys = (geom->geometry_type == Geometry::HAIR) ? | kobject.numkeys = (geom->is_hair()) ? static_cast<Hair *>(geom)->get_curve_keys().size() : 0; | ||||
| static_cast<Hair *>(geom)->get_curve_keys().size() : | |||||
| 0; | |||||
| kobject.dupli_uv[0] = ob->dupli_uv[0]; | kobject.dupli_uv[0] = ob->dupli_uv[0]; | ||||
| kobject.dupli_uv[1] = ob->dupli_uv[1]; | kobject.dupli_uv[1] = ob->dupli_uv[1]; | ||||
| int totalsteps = geom->get_motion_steps(); | int totalsteps = geom->get_motion_steps(); | ||||
| kobject.numsteps = (totalsteps - 1) / 2; | kobject.numsteps = (totalsteps - 1) / 2; | ||||
| kobject.numverts = (geom->geometry_type == Geometry::MESH || | kobject.numverts = (geom->is_mesh() || geom->is_volume()) ? | ||||
| geom->geometry_type == Geometry::VOLUME) ? | |||||
| static_cast<Mesh *>(geom)->get_verts().size() : | static_cast<Mesh *>(geom)->get_verts().size() : | ||||
| 0; | 0; | ||||
| kobject.patch_map_offset = 0; | kobject.patch_map_offset = 0; | ||||
| kobject.attribute_map_offset = 0; | kobject.attribute_map_offset = 0; | ||||
| uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); | 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); | 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_object = util_hash_to_float(hash_name); | ||||
| kobject.cryptomatte_asset = util_hash_to_float(hash_asset); | kobject.cryptomatte_asset = util_hash_to_float(hash_asset); | ||||
| kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset); | kobject.shadow_terminator_offset = 1.0f / (1.0f - 0.5f * ob->shadow_terminator_offset); | ||||
| /* Object flag. */ | /* Object flag. */ | ||||
| if (ob->use_holdout) { | if (ob->use_holdout) { | ||||
| flag |= SD_OBJECT_HOLDOUT_MASK; | flag |= SD_OBJECT_HOLDOUT_MASK; | ||||
| } | } | ||||
| state->object_flag[ob->index] = flag; | state->object_flag[ob->index] = flag; | ||||
| state->object_volume_step[ob->index] = FLT_MAX; | state->object_volume_step[ob->index] = FLT_MAX; | ||||
| /* Have curves. */ | /* Have curves. */ | ||||
| if (geom->geometry_type == Geometry::HAIR) { | if (geom->is_hair()) { | ||||
| state->have_curves = true; | state->have_curves = true; | ||||
| } | } | ||||
| } | } | ||||
| void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) | void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) | ||||
| { | { | ||||
| UpdateObjectTransformState state; | UpdateObjectTransformState state; | ||||
| state.need_motion = scene->need_motion(); | state.need_motion = scene->need_motion(); | ||||
| state.have_motion = false; | state.have_motion = false; | ||||
| state.have_curves = false; | state.have_curves = false; | ||||
| state.scene = scene; | state.scene = scene; | ||||
| state.queue_start_object = 0; | state.queue_start_object = 0; | ||||
| state.objects = dscene->objects.alloc(scene->objects.size()); | state.objects = dscene->objects.alloc(scene->get_objects().size()); | ||||
| state.object_flag = dscene->object_flag.alloc(scene->objects.size()); | state.object_flag = dscene->object_flag.alloc(scene->get_objects().size()); | ||||
| state.object_volume_step = dscene->object_volume_step.alloc(scene->objects.size()); | state.object_volume_step = dscene->object_volume_step.alloc(scene->get_objects().size()); | ||||
| state.object_motion = NULL; | state.object_motion = NULL; | ||||
| state.object_motion_pass = NULL; | state.object_motion_pass = NULL; | ||||
| if (state.need_motion == Scene::MOTION_PASS) { | if (state.need_motion == Scene::MOTION_PASS) { | ||||
| state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE * | state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE * | ||||
| scene->objects.size()); | scene->get_objects().size()); | ||||
| } | } | ||||
| else if (state.need_motion == Scene::MOTION_BLUR) { | else if (state.need_motion == Scene::MOTION_BLUR) { | ||||
| /* Set object offsets into global object motion array. */ | /* Set object offsets into global object motion array. */ | ||||
| uint *motion_offsets = state.motion_offset.resize(scene->objects.size()); | uint *motion_offsets = state.motion_offset.resize(scene->get_objects().size()); | ||||
| uint motion_offset = 0; | uint motion_offset = 0; | ||||
| foreach (Object *ob, scene->objects) { | foreach (Object *ob, scene->get_objects()) { | ||||
| *motion_offsets = motion_offset; | *motion_offsets = motion_offset; | ||||
| motion_offsets++; | motion_offsets++; | ||||
| /* Clear motion array if there is no actual motion. */ | /* Clear motion array if there is no actual motion. */ | ||||
| ob->update_motion(); | ob->update_motion(); | ||||
| motion_offset += ob->motion.size(); | motion_offset += ob->motion.size(); | ||||
| } | } | ||||
| state.object_motion = dscene->object_motion.alloc(motion_offset); | state.object_motion = dscene->object_motion.alloc(motion_offset); | ||||
| } | } | ||||
| /* Particle system device offsets | /* Particle system device offsets | ||||
| * 0 is dummy particle, index starts at 1. | * 0 is dummy particle, index starts at 1. | ||||
| */ | */ | ||||
| int numparticles = 1; | int numparticles = 1; | ||||
| foreach (ParticleSystem *psys, scene->particle_systems) { | foreach (ParticleSystem *psys, scene->get_particle_systems()) { | ||||
| state.particle_offset[psys] = numparticles; | state.particle_offset[psys] = numparticles; | ||||
| numparticles += psys->particles.size(); | numparticles += psys->get_particles().size(); | ||||
| } | } | ||||
| /* Parallel object update, with grain size to avoid too much threading overhead | /* Parallel object update, with grain size to avoid too much threading overhead | ||||
| * for individual objects. */ | * for individual objects. */ | ||||
| static const int OBJECTS_PER_TASK = 32; | static const int OBJECTS_PER_TASK = 32; | ||||
| parallel_for(blocked_range<size_t>(0, scene->objects.size(), OBJECTS_PER_TASK), | parallel_for(blocked_range<size_t>(0, scene->get_objects().size(), OBJECTS_PER_TASK), | ||||
| [&](const blocked_range<size_t> &r) { | [&](const blocked_range<size_t> &r) { | ||||
| for (size_t i = r.begin(); i != r.end(); i++) { | for (size_t i = r.begin(); i != r.end(); i++) { | ||||
| Object *ob = state.scene->objects[i]; | Object *ob = state.scene->get_objects()[i]; | ||||
| device_update_object_transform(&state, ob); | device_update_object_transform(&state, ob); | ||||
| } | } | ||||
| }); | }); | ||||
| if (progress.get_cancel()) { | if (progress.get_cancel()) { | ||||
| return; | return; | ||||
| } | } | ||||
| Show All 12 Lines | |||||
| void ObjectManager::device_update(Device *device, | void ObjectManager::device_update(Device *device, | ||||
| DeviceScene *dscene, | DeviceScene *dscene, | ||||
| Scene *scene, | Scene *scene, | ||||
| Progress &progress) | Progress &progress) | ||||
| { | { | ||||
| if (!need_update) | if (!need_update) | ||||
| return; | return; | ||||
| VLOG(1) << "Total " << scene->objects.size() << " objects."; | VLOG(1) << "Total " << scene->get_objects().size() << " objects."; | ||||
| device_free(device, dscene); | device_free(device, dscene); | ||||
| if (scene->objects.size() == 0) | if (scene->get_objects().size() == 0) | ||||
| return; | return; | ||||
| { | { | ||||
| /* Assign object IDs. */ | /* Assign object IDs. */ | ||||
| scoped_callback_timer timer([scene](double time) { | scoped_callback_timer timer([scene](double time) { | ||||
| if (scene->update_stats) { | if (scene->get_update_stats()) { | ||||
| scene->update_stats->object.times.add_entry({"device_update (assign index)", time}); | scene->get_update_stats()->object.times.add_entry({"device_update (assign index)", time}); | ||||
| } | } | ||||
| }); | }); | ||||
| int index = 0; | int index = 0; | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| object->index = index++; | object->index = index++; | ||||
| } | } | ||||
| } | } | ||||
| { | { | ||||
| /* set object transform matrices, before applying static transforms */ | /* set object transform matrices, before applying static transforms */ | ||||
| scoped_callback_timer timer([scene](double time) { | scoped_callback_timer timer([scene](double time) { | ||||
| if (scene->update_stats) { | if (scene->get_update_stats()) { | ||||
| scene->update_stats->object.times.add_entry( | scene->get_update_stats()->object.times.add_entry( | ||||
| {"device_update (copy objects to device)", time}); | {"device_update (copy objects to device)", time}); | ||||
| } | } | ||||
| }); | }); | ||||
| progress.set_status("Updating Objects", "Copying Transformations to device"); | progress.set_status("Updating Objects", "Copying Transformations to device"); | ||||
| device_update_transforms(dscene, scene, progress); | device_update_transforms(dscene, scene, progress); | ||||
| } | } | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| /* prepare for static BVH building */ | /* prepare for static BVH building */ | ||||
| /* todo: do before to support getting object level coords? */ | /* todo: do before to support getting object level coords? */ | ||||
| if (scene->params.bvh_type == SceneParams::BVH_STATIC) { | if (scene->get_params().bvh_type == SceneParams::BVH_STATIC) { | ||||
| scoped_callback_timer timer([scene](double time) { | scoped_callback_timer timer([scene](double time) { | ||||
| if (scene->update_stats) { | if (scene->get_update_stats()) { | ||||
| scene->update_stats->object.times.add_entry( | scene->get_update_stats()->object.times.add_entry( | ||||
| {"device_update (apply static transforms)", time}); | {"device_update (apply static transforms)", time}); | ||||
| } | } | ||||
| }); | }); | ||||
| progress.set_status("Updating Objects", "Applying Static Transformations"); | progress.set_status("Updating Objects", "Applying Static Transformations"); | ||||
| apply_static_transforms(dscene, scene, progress); | apply_static_transforms(dscene, scene, progress); | ||||
| } | } | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| object->clear_modified(); | object->clear_modified(); | ||||
| } | } | ||||
| } | } | ||||
| void ObjectManager::device_update_flags( | void ObjectManager::device_update_flags( | ||||
| Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid) | Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid) | ||||
| { | { | ||||
| if (!need_update && !need_flags_update) | if (!need_update && !need_flags_update) | ||||
| return; | return; | ||||
| scoped_callback_timer timer([scene](double time) { | scoped_callback_timer timer([scene](double time) { | ||||
| if (scene->update_stats) { | if (scene->get_update_stats()) { | ||||
| scene->update_stats->object.times.add_entry({"device_update_flags", time}); | scene->get_update_stats()->object.times.add_entry({"device_update_flags", time}); | ||||
| } | } | ||||
| }); | }); | ||||
| need_update = false; | need_update = false; | ||||
| need_flags_update = false; | need_flags_update = false; | ||||
| if (scene->objects.size() == 0) | if (scene->get_objects().size() == 0) | ||||
| return; | return; | ||||
| /* Object info flag. */ | /* Object info flag. */ | ||||
| uint *object_flag = dscene->object_flag.data(); | uint *object_flag = dscene->object_flag.data(); | ||||
| float *object_volume_step = dscene->object_volume_step.data(); | float *object_volume_step = dscene->object_volume_step.data(); | ||||
| /* Object volume intersection. */ | /* Object volume intersection. */ | ||||
| vector<Object *> volume_objects; | vector<Object *> volume_objects; | ||||
| bool has_volume_objects = false; | bool has_volume_objects = false; | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| if (object->geometry->has_volume) { | if (object->geometry->get_has_volume()) { | ||||
| if (bounds_valid) { | if (bounds_valid) { | ||||
| volume_objects.push_back(object); | volume_objects.push_back(object); | ||||
| } | } | ||||
| has_volume_objects = true; | has_volume_objects = true; | ||||
| object_volume_step[object->index] = object->compute_volume_step_size(); | object_volume_step[object->index] = object->compute_volume_step_size(); | ||||
| } | } | ||||
| else { | else { | ||||
| object_volume_step[object->index] = FLT_MAX; | object_volume_step[object->index] = FLT_MAX; | ||||
| } | } | ||||
| } | } | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| if (object->geometry->has_volume) { | if (object->geometry->get_has_volume()) { | ||||
| object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; | object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; | ||||
| object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; | object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; | ||||
| foreach (Attribute &attr, object->geometry->attributes.attributes) { | foreach (Attribute &attr, object->geometry->get_attributes().get_attributes()) { | ||||
| if (attr.element == ATTR_ELEMENT_VOXEL) { | if (attr.get_element() == ATTR_ELEMENT_VOXEL) { | ||||
| object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; | object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES); | object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES); | ||||
| } | } | ||||
| Show All 33 Lines | void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) | ||||
| if (dscene->objects.size() == 0) { | if (dscene->objects.size() == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| KernelObject *kobjects = dscene->objects.data(); | KernelObject *kobjects = dscene->objects.data(); | ||||
| bool update = false; | bool update = false; | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| Geometry *geom = object->geometry; | Geometry *geom = object->geometry; | ||||
| if (geom->geometry_type == Geometry::MESH) { | if (geom->is_mesh()) { | ||||
| Mesh *mesh = static_cast<Mesh *>(geom); | Mesh *mesh = static_cast<Mesh *>(geom); | ||||
| if (mesh->patch_table) { | if (mesh->patch_table) { | ||||
| uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - | uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - | ||||
| mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - | mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - | ||||
| mesh->patch_offset; | mesh->patch_offset; | ||||
| if (kobjects[object->index].patch_map_offset != patch_map_offset) { | if (kobjects[object->index].patch_map_offset != patch_map_offset) { | ||||
| kobjects[object->index].patch_map_offset = patch_map_offset; | kobjects[object->index].patch_map_offset = patch_map_offset; | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| size_t attr_map_offset = object->attr_map_offset; | size_t attr_map_offset = object->attr_map_offset; | ||||
| /* An object attribute map cannot have a zero offset because mesh maps come first. */ | /* An object attribute map cannot have a zero offset because mesh maps come first. */ | ||||
| if (attr_map_offset == 0) { | if (attr_map_offset == 0) { | ||||
| attr_map_offset = geom->attr_map_offset; | attr_map_offset = geom->get_attr_map_offset(); | ||||
| } | } | ||||
| if (kobjects[object->index].attribute_map_offset != attr_map_offset) { | if (kobjects[object->index].attribute_map_offset != attr_map_offset) { | ||||
| kobjects[object->index].attribute_map_offset = attr_map_offset; | kobjects[object->index].attribute_map_offset = attr_map_offset; | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| } | } | ||||
| Show All 18 Lines | void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) | ||||
| /* counter geometry users */ | /* counter geometry users */ | ||||
| map<Geometry *, int> geometry_users; | map<Geometry *, int> geometry_users; | ||||
| Scene::MotionType need_motion = scene->need_motion(); | Scene::MotionType need_motion = scene->need_motion(); | ||||
| bool motion_blur = need_motion == Scene::MOTION_BLUR; | bool motion_blur = need_motion == Scene::MOTION_BLUR; | ||||
| bool apply_to_motion = need_motion != Scene::MOTION_PASS; | bool apply_to_motion = need_motion != Scene::MOTION_PASS; | ||||
| int i = 0; | int i = 0; | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| map<Geometry *, int>::iterator it = geometry_users.find(object->geometry); | map<Geometry *, int>::iterator it = geometry_users.find(object->geometry); | ||||
| if (it == geometry_users.end()) | if (it == geometry_users.end()) | ||||
| geometry_users[object->geometry] = 1; | geometry_users[object->geometry] = 1; | ||||
| else | else | ||||
| it->second++; | it->second++; | ||||
| } | } | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| uint *object_flag = dscene->object_flag.data(); | uint *object_flag = dscene->object_flag.data(); | ||||
| /* apply transforms for objects with single user geometry */ | /* apply transforms for objects with single user geometry */ | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| /* Annoying feedback loop here: we can't use is_instanced() because | /* Annoying feedback loop here: we can't use is_instanced() because | ||||
| * it'll use uninitialized transform_applied flag. | * it'll use uninitialized transform_applied flag. | ||||
| * | * | ||||
| * Could be solved by moving reference counter to Geometry. | * Could be solved by moving reference counter to Geometry. | ||||
| */ | */ | ||||
| Geometry *geom = object->geometry; | Geometry *geom = object->geometry; | ||||
| bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf && | bool apply = (geometry_users[geom] == 1) && !geom->get_has_surface_bssrdf() && | ||||
| !geom->has_true_displacement(); | !geom->has_true_displacement(); | ||||
| if (geom->geometry_type == Geometry::MESH) { | if (geom->is_mesh()) { | ||||
| Mesh *mesh = static_cast<Mesh *>(geom); | Mesh *mesh = static_cast<Mesh *>(geom); | ||||
| apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE; | apply = apply && mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE; | ||||
| } | } | ||||
| else if (geom->geometry_type == Geometry::HAIR) { | else if (geom->is_hair()) { | ||||
| /* Can't apply non-uniform scale to curves, this can't be represented by | /* Can't apply non-uniform scale to curves, this can't be represented by | ||||
| * control points and radius alone. */ | * control points and radius alone. */ | ||||
| float scale; | float scale; | ||||
| apply = apply && transform_uniform_scale(object->tfm, scale); | apply = apply && transform_uniform_scale(object->tfm, scale); | ||||
| } | } | ||||
| if (apply) { | if (apply) { | ||||
| if (!(motion_blur && object->use_motion())) { | if (!(motion_blur && object->use_motion())) { | ||||
| if (!geom->transform_applied) { | if (!geom->get_transform_applied()) { | ||||
| object->apply_transform(apply_to_motion); | object->apply_transform(apply_to_motion); | ||||
| geom->transform_applied = true; | geom->set_transform_applied(true); | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| } | } | ||||
| object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; | object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; | ||||
| if (geom->transform_negative_scaled) | if (geom->get_transform_negative_scaled()) | ||||
| object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; | object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; | ||||
| } | } | ||||
| } | } | ||||
| i++; | i++; | ||||
| } | } | ||||
| } | } | ||||
| void ObjectManager::tag_update(Scene *scene) | void ObjectManager::tag_update(Scene *scene) | ||||
| { | { | ||||
| need_update = true; | need_update = true; | ||||
| scene->geometry_manager->need_update = true; | scene->get_geometry_manager()->need_update = true; | ||||
| scene->light_manager->need_update = true; | scene->get_light_manager()->need_update = true; | ||||
| } | } | ||||
| string ObjectManager::get_cryptomatte_objects(Scene *scene) | string ObjectManager::get_cryptomatte_objects(Scene *scene) | ||||
| { | { | ||||
| string manifest = "{"; | string manifest = "{"; | ||||
| unordered_set<ustring, ustringHash> objects; | unordered_set<ustring, ustringHash> objects; | ||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->get_objects()) { | ||||
| if (objects.count(object->name)) { | if (objects.count(object->name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| objects.insert(object->name); | objects.insert(object->name); | ||||
| uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0); | 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 += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name); | ||||
| } | } | ||||
| manifest[manifest.size() - 1] = '}'; | manifest[manifest.size() - 1] = '}'; | ||||
| return manifest; | return manifest; | ||||
| } | } | ||||
| string ObjectManager::get_cryptomatte_assets(Scene *scene) | string ObjectManager::get_cryptomatte_assets(Scene *scene) | ||||
| { | { | ||||
| string manifest = "{"; | string manifest = "{"; | ||||
| unordered_set<ustring, ustringHash> assets; | unordered_set<ustring, ustringHash> assets; | ||||
| foreach (Object *ob, scene->objects) { | foreach (Object *ob, scene->get_objects()) { | ||||
| if (assets.count(ob->asset_name)) { | if (assets.count(ob->asset_name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| assets.insert(ob->asset_name); | assets.insert(ob->asset_name); | ||||
| uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); | 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 += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset); | ||||
| } | } | ||||
| manifest[manifest.size() - 1] = '}'; | manifest[manifest.size() - 1] = '}'; | ||||
| return manifest; | return manifest; | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||