Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht>2021-09-09 18:22:20 +0300
committerBrecht Van Lommel <brecht@blender.org>2021-09-10 17:48:30 +0300
commit128eb6cbe928e58dfee1c64f340fd8d663134c26 (patch)
tree68c510ccb7bc3b60af06462392ec46da5baf53a6 /intern/cycles/blender
parent42215d7cb8797ba5b631b9df93d07e895c4b1dda (diff)
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
Diffstat (limited to 'intern/cycles/blender')
-rw-r--r--intern/cycles/blender/blender_geometry.cpp4
-rw-r--r--intern/cycles/blender/blender_mesh.cpp181
-rw-r--r--intern/cycles/blender/blender_object.cpp12
-rw-r--r--intern/cycles/blender/blender_sync.h1
-rw-r--r--intern/cycles/blender/blender_util.h28
5 files changed, 82 insertions, 144 deletions
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)
{
- /* Fluid motion blur already exported. */
- BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob_info.real_object);
- if (b_fluid_domain) {
- return;
- }
-
- /* Cached motion blur already exported. */
- BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(
- b_ob_info.real_object, true, nullptr);
- if (mesh_cache) {
- return;
- }
-
/* Skip if no vertices were exported. */
size_t numverts = mesh->get_verts().size();
if (numverts == 0) {
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 2243baca0b2..22d6edeb099 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -604,7 +604,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
* 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, &has_subdivision_modifier);
+ b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
}
@@ -719,6 +719,14 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
}
}
+ /* Check which geometry already has motion blur so it can be skipped. */
+ geometry_motion_attribute_synced.clear();
+ for (Geometry *geom : scene->geometry) {
+ if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
+ geometry_motion_attribute_synced.insert(geom);
+ }
+ }
+
/* note iteration over motion_times set happens in sorted order */
foreach (float relative_time, motion_times) {
/* center time is already handled. */
@@ -749,6 +757,8 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
sync_objects(b_depsgraph, b_v3d, relative_time);
}
+ geometry_motion_attribute_synced.clear();
+
/* we need to set the python thread state again because this
* function assumes it is being executed from python and will
* try to save the thread state */
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index 76e8f23864c..d25c0ce1bc3 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -236,6 +236,7 @@ class BlenderSync {
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Geometry *> geometry_synced;
set<Geometry *> geometry_motion_synced;
+ set<Geometry *> geometry_motion_attribute_synced;
set<float> motion_times;
void *world_map;
bool world_recalc;
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index e69531ea707..04008d77d89 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -573,22 +573,6 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
return use_deform_motion;
}
-static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
-{
- for (BL::Modifier &b_mod : b_ob.modifiers) {
- if (b_mod.is_a(&RNA_FluidModifier)) {
- BL::FluidModifier b_mmd(b_mod);
-
- if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
- b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
- return b_mmd.domain_settings();
- }
- }
- }
-
- return BL::FluidDomainSettings(PointerRNA_NULL);
-}
-
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
{
for (BL::Modifier &b_mod : b_ob.modifiers) {
@@ -606,7 +590,6 @@ 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 *has_subdivision_modifier)
{
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
@@ -614,13 +597,6 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
-
- if (check_velocity) {
- if (!MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
- return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
- }
- }
-
return mesh_cache;
}
@@ -629,9 +605,7 @@ 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 (b_mod.type() == BL::Modifier::type_SUBSURF) {
if (has_subdivision_modifier) {
*has_subdivision_modifier = true;
}