diff options
Diffstat (limited to 'intern/cycles/blender/blender_object.cpp')
-rw-r--r-- | intern/cycles/blender/blender_object.cpp | 282 |
1 files changed, 215 insertions, 67 deletions
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 212b9cbe103..4a70cbbf41f 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -32,6 +32,7 @@ #include "util/util_foreach.h" #include "util/util_hash.h" #include "util/util_logging.h" +#include "util/util_task.h" CCL_NAMESPACE_BEGIN @@ -103,7 +104,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, bool use_particle_hair, bool show_lights, BlenderObjectCulling &culling, - bool *use_portal) + bool *use_portal, + TaskPool *geom_task_pool) { const bool is_instance = b_instance.is_instance(); BL::Object b_ob = b_instance.object(); @@ -181,6 +183,10 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, return NULL; } + /* Use task pool only for non-instances, since sync_dupli_particle accesses + * geometry. This restriction should be removed for better performance. */ + TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool; + /* key to lookup object */ ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair); Object *object; @@ -193,12 +199,19 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* Set transform at matching motion time step. */ int time_index = object->motion_step(motion_time); if (time_index >= 0) { - object->motion[time_index] = tfm; + array<Transform> motion = object->get_motion(); + motion[time_index] = tfm; + object->set_motion(motion); } /* mesh deformation */ - if (object->geometry) - sync_geometry_motion(b_depsgraph, b_ob, object, motion_time, use_particle_hair); + if (object->get_geometry()) + sync_geometry_motion(b_depsgraph, + b_ob_instance, + object, + motion_time, + use_particle_hair, + object_geom_task_pool); } return object; @@ -207,38 +220,40 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* test if we need to sync */ bool object_updated = false; - if (object_map.add_or_update(scene, &object, b_ob, b_parent, key)) + if (object_map.add_or_update(&object, b_ob, b_parent, key)) object_updated = true; /* mesh sync */ - object->geometry = sync_geometry( - b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair); + /* b_ob is owned by the iterator and will go out of scope at the end of the block. + * b_ob_instance is the original object and will remain valid for deferred geometry + * sync. */ + Geometry *geometry = sync_geometry(b_depsgraph, + b_ob_instance, + b_ob_instance, + object_updated, + use_particle_hair, + object_geom_task_pool); + object->set_geometry(geometry); /* special case not tracked by object update flags */ - /* holdout */ - if (use_holdout != object->use_holdout) { - object->use_holdout = use_holdout; - scene->object_manager->tag_update(scene); + if (sync_object_attributes(b_instance, object)) { object_updated = true; } - if (visibility != object->visibility) { - object->visibility = visibility; - object_updated = true; + /* holdout */ + object->set_use_holdout(use_holdout); + if (object->use_holdout_is_modified()) { + scene->object_manager->tag_update(scene); } + object->set_visibility(visibility); + bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher"); - if (is_shadow_catcher != object->is_shadow_catcher) { - object->is_shadow_catcher = is_shadow_catcher; - object_updated = true; - } + object->set_is_shadow_catcher(is_shadow_catcher); float shadow_terminator_offset = get_float(cobject, "shadow_terminator_offset"); - if (shadow_terminator_offset != object->shadow_terminator_offset) { - object->shadow_terminator_offset = shadow_terminator_offset; - object_updated = true; - } + object->set_shadow_terminator_offset(shadow_terminator_offset); /* sync the asset name for Cryptomatte */ BL::Object parent = b_ob.parent(); @@ -252,48 +267,49 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, else { parent_name = b_ob.name(); } - if (object->asset_name != parent_name) { - object->asset_name = parent_name; - object_updated = true; - } + object->set_asset_name(parent_name); /* object sync * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ - if (object_updated || (object->geometry && object->geometry->need_update) || - tfm != object->tfm) { + if (object->is_modified() || object_updated || + (object->get_geometry() && object->get_geometry()->is_modified()) || + tfm != object->get_tfm()) { object->name = b_ob.name().c_str(); - object->pass_id = b_ob.pass_index(); - object->color = get_float3(b_ob.color()); - object->tfm = tfm; - object->motion.clear(); + object->set_pass_id(b_ob.pass_index()); + object->set_color(get_float3(b_ob.color())); + object->set_tfm(tfm); + array<Transform> motion; + object->set_motion(motion); /* motion blur */ Scene::MotionType need_motion = scene->need_motion(); - if (need_motion != Scene::MOTION_NONE && object->geometry) { - Geometry *geom = object->geometry; - geom->use_motion_blur = false; - geom->motion_steps = 0; + if (need_motion != Scene::MOTION_NONE && object->get_geometry()) { + Geometry *geom = object->get_geometry(); + geom->set_use_motion_blur(false); + geom->set_motion_steps(0); uint motion_steps; if (need_motion == Scene::MOTION_BLUR) { motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS); - geom->motion_steps = motion_steps; + geom->set_motion_steps(motion_steps); if (motion_steps && object_use_deform_motion(b_parent, b_ob)) { - geom->use_motion_blur = true; + geom->set_use_motion_blur(true); } } else { motion_steps = 3; - geom->motion_steps = motion_steps; + geom->set_motion_steps(motion_steps); } - object->motion.clear(); - object->motion.resize(motion_steps, transform_empty()); + motion.resize(motion_steps, transform_empty()); if (motion_steps) { - object->motion[motion_steps / 2] = tfm; + motion[motion_steps / 2] = tfm; + + /* update motion socket before trying to access object->motion_time */ + object->set_motion(motion); for (size_t step = 0; step < motion_steps; step++) { motion_times.insert(object->motion_time(step)); @@ -303,15 +319,15 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* dupli texture coordinates and random_id */ if (is_instance) { - object->dupli_generated = 0.5f * get_float3(b_instance.orco()) - - make_float3(0.5f, 0.5f, 0.5f); - object->dupli_uv = get_float2(b_instance.uv()); - object->random_id = b_instance.random_id(); + object->set_dupli_generated(0.5f * get_float3(b_instance.orco()) - + make_float3(0.5f, 0.5f, 0.5f)); + object->set_dupli_uv(get_float2(b_instance.uv())); + object->set_random_id(b_instance.random_id()); } else { - object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); - object->dupli_uv = make_float2(0.0f, 0.0f); - object->random_id = hash_uint2(hash_string(object->name.c_str()), 0); + object->set_dupli_generated(make_float3(0.0f, 0.0f, 0.0f)); + object->set_dupli_uv(make_float2(0.0f, 0.0f)); + object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0)); } object->tag_update(scene); @@ -325,12 +341,141 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, return object; } +/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */ +static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value) +{ + PointerRNA ptr; + PropertyRNA *prop; + + if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) { + return false; + } + + PropertyType type = RNA_property_type(prop); + int arraylen = RNA_property_array_length(&ptr, prop); + + if (arraylen == 0) { + float value; + + if (type == PROP_FLOAT) + value = RNA_property_float_get(&ptr, prop); + else if (type == PROP_INT) + value = RNA_property_int_get(&ptr, prop); + else + return false; + + *r_value = make_float4(value, value, value, 1.0f); + return true; + } + else if (type == PROP_FLOAT && arraylen <= 4) { + *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + RNA_property_float_get_array(&ptr, prop, &r_value->x); + return true; + } + + return false; +} + +/* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */ +static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance, + const string &name, + bool use_instancer) +{ + string idprop_name = string_printf("[\"%s\"]", name.c_str()); + float4 value; + + /* If requesting instance data, check the parent particle system and object. */ + if (use_instancer && b_instance.is_instance()) { + BL::ParticleSystem b_psys = b_instance.particle_system(); + + if (b_psys) { + if (lookup_property(b_psys.settings(), idprop_name, &value) || + lookup_property(b_psys.settings(), name, &value)) { + return value; + } + } + if (lookup_property(b_instance.parent(), idprop_name, &value) || + lookup_property(b_instance.parent(), name, &value)) { + return value; + } + } + + /* Check the object and mesh. */ + BL::Object b_ob = b_instance.object(); + BL::ID b_data = b_ob.data(); + + if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) || + lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) { + return value; + } + + return make_float4(0.0f); +} + +bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object) +{ + /* Find which attributes are needed. */ + AttributeRequestSet requests = object->get_geometry()->needed_attributes(); + + /* Delete attributes that became unnecessary. */ + vector<ParamValue> &attributes = object->attributes; + bool changed = false; + + for (int i = attributes.size() - 1; i >= 0; i--) { + if (!requests.find(attributes[i].name())) { + attributes.erase(attributes.begin() + i); + changed = true; + } + } + + /* Update attribute values. */ + foreach (AttributeRequest &req, requests.requests) { + ustring name = req.name; + + std::string real_name; + BlenderAttributeType type = blender_attribute_name_split_type(name, &real_name); + + if (type != BL::ShaderNodeAttribute::attribute_type_GEOMETRY) { + bool use_instancer = (type == BL::ShaderNodeAttribute::attribute_type_INSTANCER); + float4 value = lookup_instance_property(b_instance, real_name, use_instancer); + + /* Try finding the existing attribute value. */ + ParamValue *param = NULL; + + for (size_t i = 0; i < attributes.size(); i++) { + if (attributes[i].name() == name) { + param = &attributes[i]; + break; + } + } + + /* Replace or add the value. */ + ParamValue new_param(name, TypeDesc::TypeFloat4, 1, &value); + assert(new_param.datasize() == sizeof(value)); + + if (!param) { + changed = true; + attributes.push_back(new_param); + } + else if (memcmp(param->data(), &value, sizeof(value)) != 0) { + changed = true; + *param = new_param; + } + } + } + + return changed; +} + /* Object Loop */ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, float motion_time) { + /* Task pool for multithreaded geometry sync. */ + TaskPool geom_task_pool; + /* layer data */ bool motion = motion_time != 0.0f; @@ -355,8 +500,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights; BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - BL::Depsgraph::object_instances_iterator b_instance_iter; + for (b_depsgraph.object_instances.begin(b_instance_iter); b_instance_iter != b_depsgraph.object_instances.end() && !cancel; ++b_instance_iter) { @@ -372,6 +517,11 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, /* Load per-object culling data. */ culling.init_object(scene, b_ob); + /* Ensure the object geom supporting the hair is processed before adding + * the hair processing task to the task pool, calling .to_mesh() on the + * same object in parallel does not work. */ + const bool sync_hair = b_instance.show_particles() && object_has_particle_hair(b_ob); + /* Object itself. */ if (b_instance.show_self()) { sync_object(b_depsgraph, @@ -381,11 +531,12 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, false, show_lights, culling, - &use_portal); + &use_portal, + sync_hair ? NULL : &geom_task_pool); } /* Particle hair as separate object. */ - if (b_instance.show_particles() && object_has_particle_hair(b_ob)) { + if (sync_hair) { sync_object(b_depsgraph, b_view_layer, b_instance, @@ -393,22 +544,25 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, true, show_lights, culling, - &use_portal); + &use_portal, + &geom_task_pool); } cancel = progress.get_cancel(); } + geom_task_pool.wait_work(); + progress.set_sync_status(""); if (!cancel && !motion) { sync_background_light(b_v3d, use_portal); /* handle removed data and modified pointers */ - light_map.post_sync(scene); - geometry_map.post_sync(scene); - object_map.post_sync(scene); - particle_system_map.post_sync(scene); + light_map.post_sync(); + geometry_map.post_sync(); + object_map.post_sync(); + particle_system_map.post_sync(); } if (motion) @@ -431,20 +585,18 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, if (b_override) b_cam = b_override; - Camera prevcam = *(scene->camera); - int frame_center = b_scene.frame_current(); float subframe_center = b_scene.frame_subframe(); float frame_center_delta = 0.0f; if (scene->need_motion() != Scene::MOTION_PASS && - scene->camera->motion_position != Camera::MOTION_POSITION_CENTER) { - float shuttertime = scene->camera->shuttertime; - if (scene->camera->motion_position == Camera::MOTION_POSITION_END) { + scene->camera->get_motion_position() != Camera::MOTION_POSITION_CENTER) { + float shuttertime = scene->camera->get_shuttertime(); + if (scene->camera->get_motion_position() == Camera::MOTION_POSITION_END) { frame_center_delta = -shuttertime * 0.5f; } else { - assert(scene->camera->motion_position == Camera::MOTION_POSITION_START); + assert(scene->camera->get_motion_position() == Camera::MOTION_POSITION_START); frame_center_delta = shuttertime * 0.5f; } @@ -505,10 +657,6 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, python_thread_state_restore(python_thread_state); b_engine.frame_set(frame_center, subframe_center); python_thread_state_save(python_thread_state); - - /* tag camera for motion update */ - if (scene->camera->motion_modified(prevcam)) - scene->camera->tag_update(); } CCL_NAMESPACE_END |