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:
@@ -1078,7 +1078,7 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me
|
|||||||
return;
|
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) {
|
if (!b_mesh_cache) {
|
||||||
return;
|
return;
|
||||||
@@ -1241,7 +1241,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Cached motion blur already exported. */
|
/* 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) {
|
if (mesh_cache) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,7 +485,9 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
|
|||||||
|
|
||||||
/* Object Loop */
|
/* 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
|
#ifdef WITH_ALEMBIC
|
||||||
BL::CacheFile cache_file = b_mesh_cache.cache_file();
|
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_dicing_rate(subd_dicing_rate);
|
||||||
abc_object->set_subd_max_level(max_subdivisions);
|
abc_object->set_subd_max_level(max_subdivisions);
|
||||||
|
|
||||||
|
abc_object->set_ignore_subdivision(!has_subdivision_modifier);
|
||||||
|
|
||||||
if (abc_object->is_modified() || procedural->is_modified()) {
|
if (abc_object->is_modified() || procedural->is_modified()) {
|
||||||
procedural->tag_update(scene);
|
procedural->tag_update(scene);
|
||||||
}
|
}
|
||||||
@@ -601,13 +605,14 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
|||||||
if (b_instance.show_self()) {
|
if (b_instance.show_self()) {
|
||||||
#ifdef WITH_ALEMBIC
|
#ifdef WITH_ALEMBIC
|
||||||
bool use_procedural = false;
|
bool use_procedural = false;
|
||||||
|
bool has_subdivision_modifier = false;
|
||||||
BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
|
BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
|
||||||
|
|
||||||
/* Experimental as Blender does not have good support for procedurals at the moment, also
|
/* 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
|
* only available in preview renders since currently do not have a good cache policy, the
|
||||||
* data being loaded at once for all the frames. */
|
* data being loaded at once for all the frames. */
|
||||||
if (experimental && b_v3d) {
|
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();
|
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
|
/* Skip in the motion case, as generating motion blur data will be handled in the
|
||||||
* procedural. */
|
* procedural. */
|
||||||
if (!motion) {
|
if (!motion) {
|
||||||
sync_procedural(b_ob, b_mesh_cache);
|
sync_procedural(b_ob, b_mesh_cache, has_subdivision_modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ class BlenderSync {
|
|||||||
TaskPool *geom_task_pool);
|
TaskPool *geom_task_pool);
|
||||||
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
|
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);
|
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,
|
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) {
|
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
|
||||||
BL::Modifier b_mod = b_ob.modifiers[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;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -385,6 +385,8 @@ NODE_DEFINE(AlembicObject)
|
|||||||
SOCKET_STRING(path, "Alembic Path", ustring());
|
SOCKET_STRING(path, "Alembic Path", ustring());
|
||||||
SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type());
|
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_INT(subd_max_level, "Max Subdivision Level", 1);
|
||||||
SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
|
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();
|
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;
|
SubDSchemaData data;
|
||||||
data.time_sampling = schema.getTimeSampling();
|
data.time_sampling = schema.getTimeSampling();
|
||||||
data.num_samples = schema.getNumSamples();
|
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);
|
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);
|
build_caches(progress);
|
||||||
|
|
||||||
foreach (Node *node, objects) {
|
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)
|
void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time)
|
||||||
{
|
{
|
||||||
CachedData &cached_data = abc_object->get_cached_data();
|
if (abc_object->get_ignore_subdivision()) {
|
||||||
|
read_mesh(abc_object, frame_time);
|
||||||
if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
|
return;
|
||||||
/* need to reset the current data is something changed */
|
|
||||||
cached_data.invalidate_last_loaded_time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CachedData &cached_data = abc_object->get_cached_data();
|
||||||
|
|
||||||
/* Update sockets. */
|
/* Update sockets. */
|
||||||
|
|
||||||
Object *object = abc_object->get_object();
|
Object *object = abc_object->get_object();
|
||||||
@@ -988,6 +1030,11 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame
|
|||||||
return;
|
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());
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
||||||
|
|
||||||
/* Make sure shader ids are also updated. */
|
/* Make sure shader ids are also updated. */
|
||||||
|
|||||||
@@ -353,6 +353,10 @@ class AlembicObject : public Node {
|
|||||||
/* Shaders used for rendering. */
|
/* Shaders used for rendering. */
|
||||||
NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
|
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. */
|
/* Maximum number of subdivisions for ISubD objects. */
|
||||||
NODE_SOCKET_API(int, subd_max_level)
|
NODE_SOCKET_API(int, subd_max_level)
|
||||||
|
|
||||||
@@ -416,6 +420,11 @@ class AlembicObject : public Node {
|
|||||||
return cached_data_.is_constant();
|
return cached_data_.is_constant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_cache()
|
||||||
|
{
|
||||||
|
cached_data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
Object *object = nullptr;
|
Object *object = nullptr;
|
||||||
|
|
||||||
bool data_loaded = false;
|
bool data_loaded = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user