Commit: 128eb6cbe928e58dfee1c64f340fd8d663134c26 Author: Brecht Van Lommel Date: Thu Sep 9 17:22:20 2021 +0200 Branches: master https://developer.blender.org/rB128eb6cbe928e58dfee1c64f340fd8d663134c26
Modifiers: export motion blur velocity through attribute Previously fluid simulation and Alembic modifiers had a dedicated function to query the velocity for motion blur. Now use a more generic system where those modifiers output a velocity attribute. Advantages: * Geometry and particle nodes can output velocity through the same mechanism, or read the attribute coming from earlier modifiers. * The velocity can be preserved through modifiers like subdivision surface or auto smooth. * USD and Alembic previously only output velocity from fluid simulation, now they work with velocity from other sources too. * Simplifies the code for renderers like Cycles and exporters like Alembic and USD. This breaks compatibility: * External renderers and exporters accessing these velocities through the Python API now need to use the attribute instead. * Existing modifier node setups that create an attribute named "velocity" will render differently with motion blur. Differential Revision: https://developer.blender.org/D12305 =================================================================== M intern/cycles/blender/blender_geometry.cpp M intern/cycles/blender/blender_mesh.cpp M intern/cycles/blender/blender_object.cpp M intern/cycles/blender/blender_sync.h M intern/cycles/blender/blender_util.h M source/blender/blenkernel/BKE_attribute.h M source/blender/blenkernel/intern/attribute.c M source/blender/blenkernel/intern/fluid.c M source/blender/blenkernel/intern/modifier.c M source/blender/blenloader/intern/versioning_290.c M source/blender/io/alembic/ABC_alembic.h M source/blender/io/alembic/exporter/abc_writer_mesh.cc M source/blender/io/alembic/exporter/abc_writer_mesh.h M source/blender/io/alembic/intern/abc_customdata.h M source/blender/io/alembic/intern/abc_reader_curves.cc M source/blender/io/alembic/intern/abc_reader_curves.h M source/blender/io/alembic/intern/abc_reader_mesh.cc M source/blender/io/alembic/intern/abc_reader_mesh.h M source/blender/io/alembic/intern/abc_reader_object.cc M source/blender/io/alembic/intern/abc_reader_object.h M source/blender/io/alembic/intern/alembic_capi.cc M source/blender/io/usd/intern/usd_writer_mesh.cc M source/blender/io/usd/intern/usd_writer_mesh.h M source/blender/makesdna/DNA_fluid_defaults.h M source/blender/makesdna/DNA_fluid_types.h M source/blender/makesdna/DNA_modifier_defaults.h M source/blender/makesdna/DNA_modifier_types.h M source/blender/makesrna/intern/rna_fluid.c M source/blender/makesrna/intern/rna_modifier.c M source/blender/modifiers/intern/MOD_meshsequencecache.c =================================================================== diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index acc089a286c..b1de37dac10 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -189,8 +189,10 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, /* Ensure we only sync instanced geometry once. */ Geometry *geom = object->get_geometry(); - if (geometry_motion_synced.find(geom) != geometry_motion_synced.end()) + if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() || + geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end()) { return; + } geometry_motion_synced.insert(geom); diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 9bb3447f56b..7ec430eb7fe 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -347,16 +347,57 @@ static void fill_generic_attribute(BL::Mesh &b_mesh, } } -static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) +static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale) +{ + if (!(b_attribute.domain() == BL::Attribute::domain_POINT) && + (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) { + return; + } + + BL::FloatVectorAttribute b_vector_attribute(b_attribute); + const int numverts = mesh->get_verts().size(); + + /* Find or add attribute */ + float3 *P = &mesh->get_verts()[0]; + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + const float relative_time = motion_times[step] * 0.5f * motion_scale; + float3 *mP = attr_mP->data_float3() + step * numverts; + + for (int i = 0; i < numverts; i++) { + mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; + } + } +} + +static void attr_create_generic(Scene *scene, + Mesh *mesh, + BL::Mesh &b_mesh, + const bool subdivision, + const bool need_motion, + const float motion_scale) { if (subdivision) { /* TODO: Handle subdivision correctly. */ return; } AttributeSet &attributes = mesh->attributes; + static const ustring u_velocity("velocity"); for (BL::Attribute &b_attribute : b_mesh.attributes) { const ustring name{b_attribute.name().c_str()}; + + if (need_motion && name == u_velocity) { + attr_create_motion(mesh, b_attribute, motion_scale); + } + if (!mesh->need_attribute(scene, name)) { continue; } @@ -859,8 +900,10 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, const array<Node *> &used_shaders, - bool subdivision = false, - bool subdivide_uvs = true) + const bool need_motion, + const float motion_scale, + const bool subdivision = false, + const bool subdivide_uvs = true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); @@ -974,7 +1017,7 @@ static void create_mesh(Scene *scene, attr_create_vertex_color(scene, mesh, b_mesh, subdivision); attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision); attr_create_random_per_island(scene, mesh, b_mesh, subdivision); - attr_create_generic(scene, mesh, b_mesh, subdivision); + attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale); if (subdivision) { attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); @@ -1002,6 +1045,8 @@ static void create_subd_mesh(Scene *scene, BObjectInfo &b_ob_info, BL::Mesh &b_mesh, const array<Node *> &used_shaders, + const bool need_motion, + const float motion_scale, float dicing_rate, int max_subdivisions) { @@ -1010,7 +1055,7 @@ static void create_subd_mesh(Scene *scene, BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]); bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; - create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs); + create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs); /* export creases */ size_t num_creases = 0; @@ -1074,96 +1119,6 @@ static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene) return true; } -static void sync_mesh_cached_velocities(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) -{ - if (!mesh_need_motion_attribute(b_ob_info, scene)) { - return; - } - - BL::Object b_ob = b_ob_info.real_object; - BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); - - if (!b_mesh_cache) { - return; - } - - if (!MeshSequenceCacheModifier_read_velocity_get(&b_mesh_cache.ptr)) { - return; - } - - const size_t numverts = mesh->get_verts().size(); - - if (b_mesh_cache.vertex_velocities.length() != numverts) { - return; - } - - /* Find or add attribute */ - float3 *P = &mesh->get_verts()[0]; - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (!attr_mP) { - attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); - } - - /* Only export previous and next frame, we don't have any in between data. */ - float motion_times[2] = {-1.0f, 1.0f}; - for (int step = 0; step < 2; step++) { - const float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; - float3 *mP = attr_mP->data_float3() + step * numverts; - - BL::MeshSequenceCacheModifier::vertex_velocities_iterator vvi; - int i = 0; - - for (b_mesh_cache.vertex_velocities.begin(vvi); vvi != b_mesh_cache.vertex_velocities.end(); - ++vvi, ++i) { - mP[i] = P[i] + get_float3(vvi->velocity()) * relative_time; - } - } -} - -static void sync_mesh_fluid_motion(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) -{ - if (!b_ob_info.is_real_object_data()) { - return; - } - if (!mesh_need_motion_attribute(b_ob_info, scene)) { - return; - } - - BL::Object b_ob = b_ob_info.real_object; - BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob); - - if (!b_fluid_domain) - return; - - /* If the mesh has modifiers following the fluid domain we can't export motion. */ - if (b_fluid_domain.mesh_vertices.length() != mesh->get_verts().size()) - return; - - /* Find or add attribute */ - float3 *P = &mesh->get_verts()[0]; - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (!attr_mP) { - attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); - } - - /* Only export previous and next frame, we don't have any in between data. */ - float motion_times[2] = {-1.0f, 1.0f}; - for (int step = 0; step < 2; step++) { - float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; - float3 *mP = attr_mP->data_float3() + step * mesh->get_verts().size(); - - BL::FluidDomainSettings::mesh_vertices_iterator svi; - int i = 0; - - for (b_fluid_domain.mesh_vertices.begin(svi); svi != b_fluid_domain.mesh_vertices.end(); - ++svi, ++i) { - mP[i] = P[i] + get_float3(svi->velocity()) * relative_time; - } - } -} - void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) { /* make a copy of the shaders as the caller in the main thread still need them for syncing the @@ -1187,6 +1142,13 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type()); if (b_mesh) { + /* Motion blur attribute is relative to seconds, we need it relative to frames. */ + const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene); + const float motion_scale = (need_motion) ? + scene->motion_shutter_time() / + (b_scene.render().fps() / b_scene.render().fps_base()) : + 0.0f; + /* Sync mesh itself. */ if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) create_subd_mesh(scene, @@ -1194,21 +1156,23 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M b_ob_info, b_mesh, new_mesh.get_used_shaders(), + need_motion, + motion_scale, dicing_rate, max_subdivisions); else - create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false); + create_mesh(scene, + &new_mesh, + b_mesh, + new_mesh.get_used_shaders(), + need_motion, + motion_scale, + false); free_object_to_mesh(b_data, b_ob_info, b_mesh); } } - /* cached velocities (e.g. from alembic archive) */ - sync_mesh_cached_velocities(b_ob_info, scene, &new_mesh); - - /* mesh fluid motion mantaflow */ - sync_mesh_fluid_motion(b_ob_info, scene, &new_mesh); - /* update original sockets */ mesh->clear_non_sockets(); @@ -1242,19 +1206,6 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, Mesh *mesh, int motion_step) { - /* Flui @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
