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
This commit is contained in:
parent
5b51df0f33
commit
f8637cd8af
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<AlembicObject *>(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<Mesh *>(object->get_geometry());
|
||||
|
||||
/* Make sure shader ids are also updated. */
|
||||
|
|
|
@ -353,6 +353,10 @@ class AlembicObject : public Node {
|
|||
/* Shaders used for rendering. */
|
||||
NODE_SOCKET_API_ARRAY(array<Node *>, 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;
|
||||
|
|
Loading…
Reference in New Issue