From f8637cd8af451661a306edd5682cc17029e7e7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 20 Aug 2021 02:30:50 +0200 Subject: Alembic Procedural: only subdivide if subsurf modifier is present As subdivision objects are first class citizens in Alembic, to differentiate them with non-subdivided polygon meshes, the Alembic Procedural automatically sets up subdivision properties on the generated Cycles Mesh. However, for real-time playback subdivision is far too slow, so this modifies the detection of a MeshSeqCache modifier used to activate the procedural to allow for a Subsurf modifier right after the cache one. If present, the procedural will tag the object for subdivision, if absent, the object will be treated as a regular mesh. This is a temporary measure for until subdivision surface settings are part of the Mesh datablock (see T68891). Reviewed By: brecht Differential Revision: https://developer.blender.org/D11162 --- intern/cycles/blender/blender_mesh.cpp | 4 +-- intern/cycles/blender/blender_object.cpp | 11 ++++-- intern/cycles/blender/blender_sync.h | 4 ++- intern/cycles/blender/blender_util.h | 12 ++++++- intern/cycles/render/alembic.cpp | 57 +++++++++++++++++++++++++++++--- intern/cycles/render/alembic.h | 9 +++++ 6 files changed, 85 insertions(+), 12 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index d1042277183..ebba6981502 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1078,7 +1078,7 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me return; } - BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true); + BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); if (!b_mesh_cache) { return; @@ -1241,7 +1241,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, } /* Cached motion blur already exported. */ - BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true); + BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); if (mesh_cache) { return; } diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 657ecdeeeb7..2dbebac4cc3 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -485,7 +485,9 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance /* Object Loop */ -void BlenderSync::sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache) +void BlenderSync::sync_procedural(BL::Object &b_ob, + BL::MeshSequenceCacheModifier &b_mesh_cache, + bool has_subdivision_modifier) { #ifdef WITH_ALEMBIC BL::CacheFile cache_file = b_mesh_cache.cache_file(); @@ -534,6 +536,8 @@ void BlenderSync::sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifie abc_object->set_subd_dicing_rate(subd_dicing_rate); abc_object->set_subd_max_level(max_subdivisions); + abc_object->set_ignore_subdivision(!has_subdivision_modifier); + if (abc_object->is_modified() || procedural->is_modified()) { procedural->tag_update(scene); } @@ -601,13 +605,14 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, if (b_instance.show_self()) { #ifdef WITH_ALEMBIC bool use_procedural = false; + bool has_subdivision_modifier = false; BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL); /* Experimental as Blender does not have good support for procedurals at the moment, also * only available in preview renders since currently do not have a good cache policy, the * data being loaded at once for all the frames. */ if (experimental && b_v3d) { - b_mesh_cache = object_mesh_cache_find(b_ob, false); + b_mesh_cache = object_mesh_cache_find(b_ob, false, &has_subdivision_modifier); use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural(); } @@ -615,7 +620,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, /* Skip in the motion case, as generating motion blur data will be handled in the * procedural. */ if (!motion) { - sync_procedural(b_ob, b_mesh_cache); + sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier); } } else diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 0e605fcbf16..44322dda6b9 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -151,7 +151,9 @@ class BlenderSync { TaskPool *geom_task_pool); void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object); - void sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache); + void sync_procedural(BL::Object &b_ob, + BL::MeshSequenceCacheModifier &b_mesh_cache, + bool has_subdivision); bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index e50b1a4760e..3cf75b338dc 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -573,7 +573,8 @@ static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b } static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob, - bool check_velocity) + bool check_velocity, + bool *has_subdivision_modifier) { for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) { BL::Modifier b_mod = b_ob.modifiers[i]; @@ -595,6 +596,15 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b continue; } + /* Only skip the subsurf modifier if we are not checking for the mesh sequence cache modifier + * for motion blur. */ + if (b_mod.type() == BL::Modifier::type_SUBSURF && !check_velocity) { + if (has_subdivision_modifier) { + *has_subdivision_modifier = true; + } + continue; + } + break; } diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index c1817016955..81f47256739 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -385,6 +385,8 @@ NODE_DEFINE(AlembicObject) SOCKET_STRING(path, "Alembic Path", ustring()); SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type()); + SOCKET_BOOLEAN(ignore_subdivision, "Ignore Subdivision", true); + SOCKET_INT(subd_max_level, "Max Subdivision Level", 1); SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f); @@ -470,6 +472,33 @@ void AlembicObject::load_data_in_cache(CachedData &cached_data, cached_data.clear(); + if (this->get_ignore_subdivision()) { + PolyMeshSchemaData data; + data.topology_variance = schema.getTopologyVariance(); + data.time_sampling = schema.getTimeSampling(); + data.positions = schema.getPositionsProperty(); + data.face_counts = schema.getFaceCountsProperty(); + data.face_indices = schema.getFaceIndicesProperty(); + data.num_samples = schema.getNumSamples(); + data.velocities = schema.getVelocitiesProperty(); + data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders()); + + read_geometry_data(proc, cached_data, data, progress); + + if (progress.get_cancel()) { + return; + } + + /* Use the schema as the base compound property to also be able to look for top level + * properties. */ + read_attributes( + proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress); + + cached_data.invalidate_last_loaded_time(true); + data_loaded = true; + return; + } + SubDSchemaData data; data.time_sampling = schema.getTimeSampling(); data.num_samples = schema.getNumSamples(); @@ -781,6 +810,19 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress) const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate); + /* Clear the subdivision caches as the data is stored differently. */ + for (Node *node : objects) { + AlembicObject *object = static_cast(node); + + if (object->schema_type != AlembicObject::SUBD) { + continue; + } + + if (object->ignore_subdivision_is_modified()) { + object->clear_cache(); + } + } + build_caches(progress); foreach (Node *node, objects) { @@ -967,13 +1009,13 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time) { - CachedData &cached_data = abc_object->get_cached_data(); - - if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) { - /* need to reset the current data is something changed */ - cached_data.invalidate_last_loaded_time(); + if (abc_object->get_ignore_subdivision()) { + read_mesh(abc_object, frame_time); + return; } + CachedData &cached_data = abc_object->get_cached_data(); + /* Update sockets. */ Object *object = abc_object->get_object(); @@ -988,6 +1030,11 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame return; } + if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) { + /* need to reset the current data is something changed */ + cached_data.invalidate_last_loaded_time(); + } + Mesh *mesh = static_cast(object->get_geometry()); /* Make sure shader ids are also updated. */ diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 61c0e40fe4a..9c58af720f6 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -353,6 +353,10 @@ class AlembicObject : public Node { /* Shaders used for rendering. */ NODE_SOCKET_API_ARRAY(array, used_shaders) + /* Treat this subdivision object as a regular polygon mesh, so no subdivision will be performed. + */ + NODE_SOCKET_API(bool, ignore_subdivision) + /* Maximum number of subdivisions for ISubD objects. */ NODE_SOCKET_API(int, subd_max_level) @@ -416,6 +420,11 @@ class AlembicObject : public Node { return cached_data_.is_constant(); } + void clear_cache() + { + cached_data_.clear(); + } + Object *object = nullptr; bool data_loaded = false; -- cgit v1.2.3