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
This commit is contained in:
Brecht Van Lommel 2021-09-09 17:22:20 +02:00 committed by Brecht Van Lommel
parent 42215d7cb8
commit 128eb6cbe9
Notes: blender-bot 2024-01-15 13:40:54 +01:00
Referenced by commit 43394e41a8, Fix Alembic point cloud streaming.
Referenced by issue #109185, Instancing Geometry on Imported Alembic Particles produces extremely long render times when motion blur is enabled.
Referenced by pull request #116749, Alembic: read velocities on Points
Referenced by commit 472cf44166, Alembic: read velocities on Points
Referenced by issue #116792, Rendering multiple deformation motion blur steps with "velocity" attribute is wrong and can cause memory problems
Referenced by issue #117104, Cycles: motion blur on native fluid simulation
30 changed files with 300 additions and 570 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -66,6 +66,11 @@ bool BKE_id_attribute_remove(struct ID *id,
struct CustomDataLayer *layer,
struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
const int type,
const AttributeDomain domain);
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);

View File

@ -51,7 +51,7 @@ typedef struct DomainInfo {
int length;
} DomainInfo;
static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
{
memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM);
@ -223,6 +223,29 @@ bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports
return true;
}
CustomDataLayer *BKE_id_attribute_find(const ID *id,
const char *name,
const int type,
const AttributeDomain domain)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
CustomData *customdata = info[domain].customdata;
if (customdata == NULL) {
return NULL;
}
for (int i = 0; i < customdata->totlayer; i++) {
CustomDataLayer *layer = &customdata->layers[i];
if (layer->type == type && STREQ(layer->name, name)) {
return layer;
}
}
return NULL;
}
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];

View File

@ -39,6 +39,7 @@
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "BKE_attribute.h"
#include "BKE_effect.h"
#include "BKE_fluid.h"
#include "BKE_global.h"
@ -529,8 +530,7 @@ static bool BKE_fluid_modifier_init(
copy_v3_v3_int(fds->res_max, res);
/* Set time, frame length = 0.1 is at 25fps. */
float fps = scene->r.frs_sec / scene->r.frs_sec_base;
fds->frame_length = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
fds->frame_length = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
/* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
fds->dt = fds->frame_length;
fds->time_per_frame = 0;
@ -3256,7 +3256,10 @@ static void update_effectors(
BKE_effectors_free(effectors);
}
static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Object *ob)
static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
Scene *scene,
Mesh *orgmesh,
Object *ob)
{
Mesh *me;
MVert *mverts;
@ -3303,22 +3306,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obj
/* Normals are per vertex, so these must match. */
BLI_assert(num_verts == num_normals);
/* If needed, vertex velocities will be read too. */
bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
FluidDomainVertexVelocity *velarray = NULL;
float time_mult = 25.0f * DT_DEFAULT;
if (use_speedvectors) {
if (fds->mesh_velocities) {
MEM_freeN(fds->mesh_velocities);
}
fds->mesh_velocities = MEM_calloc_arrayN(
num_verts, sizeof(FluidDomainVertexVelocity), "fluid_mesh_vertvelocities");
fds->totvert = num_verts;
velarray = fds->mesh_velocities;
}
me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
if (!me) {
return NULL;
@ -3350,6 +3337,18 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obj
/* Normals. */
normals = MEM_callocN(sizeof(short[3]) * num_normals, "Fluidmesh_tmp_normals");
/* Velocities. */
/* If needed, vertex velocities will be read too. */
bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
float(*velarray)[3] = NULL;
float time_mult = fds->dx / (DT_DEFAULT * (25.0f / FPS));
if (use_speedvectors) {
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
&me->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, NULL);
velarray = velocity_layer->data;
}
/* Loop for vertices and normals. */
for (i = 0, no_s = normals; i < num_verts && i < num_normals; i++, mverts++, no_s += 3) {
@ -3389,18 +3388,18 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Obj
# endif
if (use_speedvectors) {
velarray[i].vel[0] = manta_liquid_get_vertvel_x_at(fds->fluid, i) * (fds->dx / time_mult);
velarray[i].vel[1] = manta_liquid_get_vertvel_y_at(fds->fluid, i) * (fds->dx / time_mult);
velarray[i].vel[2] = manta_liquid_get_vertvel_z_at(fds->fluid, i) * (fds->dx / time_mult);
velarray[i][0] = manta_liquid_get_vertvel_x_at(fds->fluid, i) * time_mult;
velarray[i][1] = manta_liquid_get_vertvel_y_at(fds->fluid, i) * time_mult;
velarray[i][2] = manta_liquid_get_vertvel_z_at(fds->fluid, i) * time_mult;
# ifdef DEBUG_PRINT
/* Debugging: Print velocities of vertices. */
printf("velarray[%d].vel[0]: %f, velarray[%d].vel[1]: %f, velarray[%d].vel[2]: %f\n",
printf("velarray[%d][0]: %f, velarray[%d][1]: %f, velarray[%d][2]: %f\n",
i,
velarray[i].vel[0],
velarray[i][0],
i,
velarray[i].vel[1],
velarray[i][1],
i,
velarray[i].vel[2]);
velarray[i][2]);
# endif
}
}
@ -3670,8 +3669,7 @@ static void manta_guiding(
Depsgraph *depsgraph, Scene *scene, Object *ob, FluidModifierData *fmd, int frame)
{
FluidDomainSettings *fds = fmd->domain;
float fps = scene->r.frs_sec / scene->r.frs_sec_base;
float dt = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
float dt = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
BLI_mutex_lock(&object_update_lock);
@ -3842,8 +3840,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
copy_v3_v3_int(o_shift, fds->shift);
/* Ensure that time parameters are initialized correctly before every step. */
float fps = scene->r.frs_sec / scene->r.frs_sec_base;
fds->frame_length = DT_DEFAULT * (25.0f / fps) * fds->time_scale;
fds->frame_length = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
fds->dt = fds->frame_length;
fds->time_per_frame = 0;
@ -4216,7 +4213,7 @@ struct Mesh *BKE_fluid_modifier_do(
if (needs_viewport_update) {
/* Return generated geometry depending on domain type. */
if (fmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
result = create_liquid_geometry(fmd->domain, me, ob);
result = create_liquid_geometry(fmd->domain, scene, me, ob);
}
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
result = create_smoke_geometry(fmd->domain, me, ob);
@ -4773,8 +4770,6 @@ static void BKE_fluid_modifier_freeDomain(FluidModifierData *fmd)
fmd->domain->point_cache[0] = NULL;
}
MEM_SAFE_FREE(fmd->domain->mesh_velocities);
if (fmd->domain->coba) {
MEM_freeN(fmd->domain->coba);
}
@ -5010,16 +5005,12 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
tfds->viscosity_exponent = fds->viscosity_exponent;
/* mesh options */
if (fds->mesh_velocities) {
tfds->mesh_velocities = MEM_dupallocN(fds->mesh_velocities);
}
tfds->mesh_concave_upper = fds->mesh_concave_upper;
tfds->mesh_concave_lower = fds->mesh_concave_lower;
tfds->mesh_particle_radius = fds->mesh_particle_radius;
tfds->mesh_smoothen_pos = fds->mesh_smoothen_pos;
tfds->mesh_smoothen_neg = fds->mesh_smoothen_neg;
tfds->mesh_scale = fds->mesh_scale;
tfds->totvert = fds->totvert;
tfds->mesh_generator = fds->mesh_generator;
/* secondary particle options */

View File

@ -1473,7 +1473,6 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object
fmd->domain->tex_velocity_y = NULL;
fmd->domain->tex_velocity_z = NULL;
fmd->domain->tex_wt = NULL;
fmd->domain->mesh_velocities = NULL;
BLO_read_data_address(reader, &fmd->domain->coba);
BLO_read_data_address(reader, &fmd->domain->effector_weights);

View File

@ -1092,8 +1092,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (md->type == eModifierType_MeshSequenceCache) {
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
mcmd->velocity_scale = 1.0f;
mcmd->vertex_velocities = NULL;
mcmd->num_vertices = 0;
}
}
}

View File

@ -117,7 +117,9 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader,
struct Mesh *existing_mesh,
const float time,
const char **err_str,
int read_flags);
const int read_flags,
const char *velocity_name,
const float velocity_scale);
bool ABC_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
@ -133,16 +135,6 @@ struct CacheReader *CacheReader_open_alembic_object(struct CacheArchiveHandle *h
struct Object *object,
const char *object_path);
bool ABC_has_vec3_array_property_named(struct CacheReader *reader, const char *name);
/* r_vertex_velocities should point to a preallocated array of num_vertices floats */
int ABC_read_velocity_cache(struct CacheReader *reader,
const char *velocity_name,
float time,
float velocity_scale,
int num_vertices,
float *r_vertex_velocities);
#ifdef __cplusplus
}
#endif

View File

@ -25,6 +25,7 @@
#include "BLI_assert.h"
#include "BLI_math_vector.h"
#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@ -108,9 +109,6 @@ void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *contex
OBoolProperty type(typeContainer, "meshtype");
type.set(subsurf_modifier_ == nullptr);
}
Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph);
liquid_sim_modifier_ = get_liquid_sim_modifier(scene_eval, context->object);
}
Alembic::Abc::OObject ABCGenericMeshWriter::get_alembic_object() const
@ -144,21 +142,6 @@ bool ABCGenericMeshWriter::export_as_subdivision_surface(Object *ob_eval) const
return false;
}
ModifierData *ABCGenericMeshWriter::get_liquid_sim_modifier(Scene *scene, Object *ob)
{
ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluidsim);
if (md && (BKE_modifier_is_enabled(scene, md, eModifierMode_Render))) {
FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) {
return md;
}
}
return nullptr;
}
bool ABCGenericMeshWriter::is_supported(const HierarchyContext *context) const
{
if (args_.export_params->visible_objects_only) {
@ -284,8 +267,7 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
}
if (liquid_sim_modifier_ != nullptr) {
get_velocities(mesh, velocities);
if (get_velocities(mesh, velocities)) {
mesh_sample.setVelocities(V3fArraySample(velocities));
}
@ -368,11 +350,6 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc
void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
{
if (liquid_sim_modifier_ != nullptr) {
/* We don't need anything more for liquid meshes. */
return;
}
if (frame_has_been_written_ || !args_.export_params->vcolors) {
return;
}
@ -387,27 +364,28 @@ void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me)
write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL);
}
void ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
bool ABCGenericMeshWriter::get_velocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
{
/* Export velocity attribute output by fluid sim, sequence cache modifier
* and geometry nodes. */
CustomDataLayer *velocity_layer = BKE_id_attribute_find(
&mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT);
if (velocity_layer == nullptr) {
return false;
}
const int totverts = mesh->totvert;
const float(*mesh_velocities)[3] = reinterpret_cast<float(*)[3]>(velocity_layer->data);
vels.clear();
vels.resize(totverts);
FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(liquid_sim_modifier_);
FluidsimSettings *fss = fmd->fss;
if (fss->meshVelocities) {
float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
for (int i = 0; i < totverts; i++) {
copy_yup_from_zup(vels[i].getValue(), mesh_vels);
mesh_vels += 3;
}
}
else {
std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f));
for (int i = 0; i < totverts; i++) {
copy_yup_from_zup(vels[i].getValue(), mesh_velocities[i]);
}
return true;
}
void ABCGenericMeshWriter::get_geo_groups(Object *object,

View File

@ -45,7 +45,6 @@ class ABCGenericMeshWriter : public ABCAbstractWriter {
* exported object. */
bool is_subd_;
ModifierData *subsurf_modifier_;
ModifierData *liquid_sim_modifier_;
CDStreamConfig m_custom_data_config;
@ -70,10 +69,8 @@ class ABCGenericMeshWriter : public ABCAbstractWriter {
void write_subd(HierarchyContext &context, Mesh *mesh);
template<typename Schema> void write_face_sets(Object *object, Mesh *mesh, Schema &schema);
ModifierData *get_liquid_sim_modifier(Scene *scene_eval, Object *ob_eval);
void write_arb_geo_params(Mesh *me);
void get_velocities(Mesh *mesh, std::vector<Imath::V3f> &vels);
bool get_velocities(Mesh *mesh, std::vector<Imath::V3f> &vels);
void get_geo_groups(Object *object,
Mesh *mesh,
std::map<std::string, std::vector<int32_t>> &geo_groups);

View File

@ -122,6 +122,12 @@ void read_custom_data(const std::string &iobject_full_name,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);
void read_velocity(const Alembic::Abc::ICompoundProperty &prop,
const Alembic::Abc::PropertyHeader *prop_header,
const Alembic::Abc::ISampleSelector &selector,
const CDStreamConfig &config,
const char *velocity_name,
const float velocity_scale);
typedef enum {
ABC_UV_SCOPE_NONE,
ABC_UV_SCOPE_LOOP,

View File

@ -283,6 +283,8 @@ void AbcCurveReader::read_curve_sample(Curve *cu,
Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int /*read_flag*/,
const char * /*velocity_name*/,
const float /*velocity_scale*/,
const char **err_str)
{
ICurvesSchema::Sample sample;

View File

@ -45,7 +45,9 @@ class AbcCurveReader : public AbcObjectReader {
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str);
void read_curve_sample(Curve *cu,

View File

@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_customdata_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -36,6 +37,7 @@
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BKE_attribute.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@ -43,8 +45,10 @@
#include "BKE_object.h"
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::IV3fArrayProperty;
using Alembic::Abc::P3fArraySamplePtr;
using Alembic::Abc::PropertyHeader;
using Alembic::Abc::V3fArraySamplePtr;
using Alembic::AbcGeom::IC3fGeomParam;
using Alembic::AbcGeom::IC4fGeomParam;
@ -420,6 +424,52 @@ static void get_weight_and_index(CDStreamConfig &config,
config.ceil_index = i1;
}
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
const ISampleSelector &selector,
const std::string &name)
{
for (size_t i = 0; i < schema.getNumProperties(); i++) {
const PropertyHeader &header = schema.getPropertyHeader(i);
if (header.isCompound()) {
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
if (has_property(prop, name)) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
if (velocity_prop) {
return velocity_prop.getValue(selector);
}
}
}
else if (header.isArray()) {
if (header.getName() == name) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
return velocity_prop.getValue(selector);
}
}
}
return V3fArraySamplePtr();
}
static void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale)
{
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
&config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, NULL);
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
const int num_velocity_vectors = static_cast<int>(velocities->size());
BLI_assert(num_velocity_vectors == config.mesh->totvert);
for (int i = 0; i < num_velocity_vectors; i++) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(velocity[i], vel_in.getValue());
mul_v3_fl(velocity[i], velocity_scale);
}
}
static void read_mesh_sample(const std::string &iobject_full_name,
ImportSettings *settings,
const IPolyMeshSchema &schema,
@ -458,6 +508,13 @@ static void read_mesh_sample(const std::string &iobject_full_name,
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
}
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
if (velocities) {
read_velocity(velocities, config, settings->velocity_scale);
}
}
}
CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
@ -563,7 +620,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr);
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
if (read_mesh != mesh) {
/* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
/* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
@ -630,7 +687,9 @@ bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector
Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str)
{
IPolyMeshSchema::Sample sample;
@ -673,6 +732,8 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
/* Only read point data when streaming meshes, unless we need to create new ones. */
ImportSettings settings;
settings.read_flag |= read_flag;
settings.velocity_name = velocity_name;
settings.velocity_scale = velocity_scale;
if (topology_changed(existing_mesh, sample_sel)) {
new_mesh = BKE_mesh_new_nomain_from_template(
@ -829,6 +890,13 @@ static void read_subd_sample(const std::string &iobject_full_name,
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
}
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
if (velocities) {
read_velocity(velocities, config, settings->velocity_scale);
}
}
}
/* ************************************************************************** */
@ -876,7 +944,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, nullptr);
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
if (read_mesh != mesh) {
BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
}
@ -935,7 +1003,9 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str)
{
ISubDSchema::Sample sample;
@ -962,6 +1032,8 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
ImportSettings settings;
settings.read_flag |= read_flag;
settings.velocity_name = velocity_name;
settings.velocity_scale = velocity_scale;
if (existing_mesh->totvert != positions->size()) {
new_mesh = BKE_mesh_new_nomain_from_template(

View File

@ -42,7 +42,9 @@ class AbcMeshReader : public AbcObjectReader {
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str) override;
bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel) override;
@ -73,7 +75,9 @@ class AbcSubDReader : public AbcObjectReader {
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str);
};

View File

@ -167,6 +167,8 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
int UNUSED(read_flag),
const char *UNUSED(velocity_name),
const float UNUSED(velocity_scale),
const char **UNUSED(err_str))
{
return existing_mesh;

View File

@ -50,6 +50,10 @@ struct ImportSettings {
/* From MeshSeqCacheModifierData.read_flag */
int read_flag;
/* From CacheFile and MeshSeqCacheModifierData */
std::string velocity_name;
float velocity_scale;
bool validate_meshes;
bool always_add_cache_reader;
@ -65,6 +69,8 @@ struct ImportSettings {
sequence_len(1),
sequence_offset(0),
read_flag(0),
velocity_name(""),
velocity_scale(1.0f),
validate_meshes(false),
always_add_cache_reader(false),
cache_file(NULL)
@ -143,7 +149,9 @@ class AbcObjectReader {
virtual struct Mesh *read_mesh(struct Mesh *mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const int read_flag,
const char *velocity_name,
const float velocity_scale,
const char **err_str);
virtual bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel);

View File

@ -786,7 +786,9 @@ Mesh *ABC_read_mesh(CacheReader *reader,
Mesh *existing_mesh,
const float time,
const char **err_str,
int read_flag)
const int read_flag,
const char *velocity_name,
const float velocity_scale)
{
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
if (abc_reader == nullptr) {
@ -794,7 +796,8 @@ Mesh *ABC_read_mesh(CacheReader *reader,
}
ISampleSelector sample_sel = sample_selector_for_time(time);
return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str);
return abc_reader->read_mesh(
existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str);
}
bool ABC_mesh_topology_changed(
@ -860,136 +863,3 @@ CacheReader *CacheReader_open_alembic_object(CacheArchiveHandle *handle,
return reinterpret_cast<CacheReader *>(abc_reader);
}
/* ************************************************************************** */
static const PropertyHeader *get_property_header(const IPolyMeshSchema &schema, const char *name)
{
const PropertyHeader *prop_header = schema.getPropertyHeader(name);
if (prop_header) {
return prop_header;
}
ICompoundProperty prop = schema.getArbGeomParams();
if (!has_property(prop, name)) {
return nullptr;
}
return prop.getPropertyHeader(name);
}
bool ABC_has_vec3_array_property_named(struct CacheReader *reader, const char *name)
{
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
if (!abc_reader) {
return false;
}
IObject iobject = abc_reader->iobject();
if (!iobject.valid()) {
return false;
}
const ObjectHeader &header = iobject.getHeader();
if (!IPolyMesh::matches(header)) {
return false;
}
IPolyMesh mesh(iobject, kWrapExisting);
IPolyMeshSchema schema = mesh.getSchema();
const PropertyHeader *prop_header = get_property_header(schema, name);
if (!prop_header) {
return false;
}
return IV3fArrayProperty::matches(prop_header->getMetaData());
}
static V3fArraySamplePtr get_velocity_prop(const IPolyMeshSchema &schema,
const ISampleSelector &iss,
const std::string &name)
{
const PropertyHeader *prop_header = schema.getPropertyHeader(name);
if (prop_header) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
return velocity_prop.getValue(iss);
}
ICompoundProperty prop = schema.getArbGeomParams();
if (!has_property(prop, name)) {
return V3fArraySamplePtr();
}
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
if (velocity_prop) {
return velocity_prop.getValue(iss);
}
return V3fArraySamplePtr();
}
int ABC_read_velocity_cache(CacheReader *reader,
const char *velocity_name,
const float time,
float velocity_scale,
int num_vertices,
float *r_vertex_velocities)
{
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
if (!abc_reader) {
return -1;
}
IObject iobject = abc_reader->iobject();
if (!iobject.valid()) {
return -1;
}
const ObjectHeader &header = iobject.getHeader();
if (!IPolyMesh::matches(header)) {
return -1;
}
IPolyMesh mesh(iobject, kWrapExisting);
IPolyMeshSchema schema = mesh.getSchema();
ISampleSelector sample_sel(time);
const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel);
V3fArraySamplePtr velocities = get_velocity_prop(schema, sample_sel, velocity_name);
if (!velocities) {
return -1;
}
float vel[3];
int num_velocity_vectors = static_cast<int>(velocities->size());
if (num_velocity_vectors != num_vertices) {
return -1;
}
for (size_t i = 0; i < velocities->size(); ++i) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(vel, vel_in.getValue());
mul_v3_fl(vel, velocity_scale);
copy_v3_v3(r_vertex_velocities + i * 3, vel);
}
return num_vertices;
}

View File

@ -26,6 +26,7 @@
#include "BLI_assert.h"
#include "BLI_math_vector.h"
#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@ -219,7 +220,7 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
if (usd_export_context_.export_params.export_normals) {
write_normals(mesh, usd_mesh);
}
write_surface_velocity(context.object, mesh, usd_mesh);
write_surface_velocity(mesh, usd_mesh);
/* TODO(Sybren): figure out what happens when the face groups change. */
if (frame_has_been_written_) {
@ -409,42 +410,25 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
usd_mesh.SetNormalsInterpolation(pxr::UsdGeomTokens->faceVarying);
}
void USDGenericMeshWriter::write_surface_velocity(Object *object,
const Mesh *mesh,
pxr::UsdGeomMesh usd_mesh)
void USDGenericMeshWriter::write_surface_velocity(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
{
/* Only velocities from the fluid simulation are exported. This is the most important case,
* though, as the baked mesh changes topology all the time, and thus computing the velocities
* at import time in a post-processing step is hard. */
ModifierData *md = BKE_modifiers_findby_type(object, eModifierType_Fluidsim);
if (md == nullptr) {
/* Export velocity attribute output by fluid sim, sequence cache modifier
* and geometry nodes. */
CustomDataLayer *velocity_layer = BKE_id_attribute_find(
&mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT);
if (velocity_layer == nullptr) {
return;
}
/* Check that the fluid sim modifier is enabled and has useful data. */
const bool use_render = (DEG_get_mode(usd_export_context_.depsgraph) == DAG_EVAL_RENDER);
const ModifierMode required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
const Scene *scene = DEG_get_evaluated_scene(usd_export_context_.depsgraph);
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
return;
}
FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
if (!fsmd->fss || fsmd->fss->type != OB_FLUIDSIM_DOMAIN) {
return;
}
FluidsimSettings *fss = fsmd->fss;
if (!fss->meshVelocities) {
return;
}
const float(*velocities)[3] = reinterpret_cast<float(*)[3]>(velocity_layer->data);
/* Export per-vertex velocity vectors. */
pxr::VtVec3fArray usd_velocities;
usd_velocities.reserve(mesh->totvert);
FluidVertexVelocity *mesh_velocities = fss->meshVelocities;
for (int vertex_idx = 0, totvert = mesh->totvert; vertex_idx < totvert;
++vertex_idx, ++mesh_velocities) {
usd_velocities.push_back(pxr::GfVec3f(mesh_velocities->vel));
for (int vertex_idx = 0, totvert = mesh->totvert; vertex_idx < totvert; ++vertex_idx) {
usd_velocities.push_back(pxr::GfVec3f(velocities[vertex_idx]));
}
pxr::UsdTimeCode timecode = get_export_time_code();

View File

@ -49,7 +49,7 @@ class USDGenericMeshWriter : public USDAbstractWriter {
const MaterialFaceGroups &usd_face_groups);
void write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_surface_velocity(Object *object, const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
void write_surface_velocity(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
};
class USDMeshWriter : public USDGenericMeshWriter {

View File

@ -50,7 +50,6 @@
.tex_flags = NULL, \
.tex_range_field = NULL, \
.guide_parent = NULL, \
.mesh_velocities = NULL, \
.effector_weights = NULL, /* #BKE_effector_add_weights. */ \
.p0 = {0.0f, 0.0f, 0.0f}, \
.p1 = {0.0f, 0.0f, 0.0f}, \
@ -122,7 +121,6 @@
.mesh_smoothen_pos = 1, \
.mesh_smoothen_neg = 1, \
.mesh_scale = 2, \
.totvert = 0, \
.mesh_generator = FLUID_DOMAIN_MESH_IMPROVED, \
.particle_type = 0, \
.particle_scale = 1, \

View File

@ -480,10 +480,6 @@ enum {
SM_HRES_FULLSAMPLE = 2,
};
typedef struct FluidDomainVertexVelocity {
float vel[3];
} FluidDomainVertexVelocity;
typedef struct FluidDomainSettings {
/* -- Runtime-only fields (from here on). -- */
@ -509,8 +505,6 @@ typedef struct FluidDomainSettings {
struct GPUTexture *tex_flags;
struct GPUTexture *tex_range_field;
struct Object *guide_parent;
/** Vertex velocities of simulated fluid mesh. */
struct FluidDomainVertexVelocity *mesh_velocities;
struct EffectorWeights *effector_weights;
/* Domain object data. */
@ -607,9 +601,8 @@ typedef struct FluidDomainSettings {
int mesh_smoothen_pos;
int mesh_smoothen_neg;
int mesh_scale;
int totvert;
short mesh_generator;
char _pad6[6]; /* Unused. */
char _pad6[2]; /* Unused. */
/* Secondary particle options. */
int particle_type;

View File

@ -419,10 +419,6 @@
.velocity_scale = 1.0f, \
.reader = NULL, \
.reader_object_path = "", \
.vertex_velocities = NULL, \
.num_vertices = 0, \
.velocity_delta = 0.0f, \
.last_lookup_time = 0.0f, \
}
#define _DNA_DEFAULT_MirrorModifierData \

View File

@ -2144,10 +2144,6 @@ enum {
MOD_NORMALEDIT_MIX_MUL = 3,
};
typedef struct MeshCacheVertexVelocity {
float vel[3];
} MeshCacheVertexVelocity;
typedef struct MeshSeqCacheModifierData {
ModifierData modifier;
@ -2163,25 +2159,6 @@ typedef struct MeshSeqCacheModifierData {
/* Runtime. */
struct CacheReader *reader;
char reader_object_path[1024];
/* Vertex velocities read from the cache. The velocities are not automatically read during
* modifier execution, and therefore have to manually be read when needed. This is only used
* through the RNA for now. */
struct MeshCacheVertexVelocity *vertex_velocities;
/* The number of vertices of the Alembic mesh, set when the modifier is executed. */
int num_vertices;
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
* scale the velocity vectors at render time for generating proper motion blur data. */
float velocity_delta;
/* Caches the scene time (in seconds) used to lookup data in the Alembic archive when the
* modifier was last executed. Used to access Alembic samples through the RNA. */
float last_lookup_time;
int _pad1;
void *_pad2;
} MeshSeqCacheModifierData;
/* MeshSeqCacheModifierData.read_flag */

View File

@ -1242,22 +1242,6 @@ static void rna_Fluid_flowtype_set(struct PointerRNA *ptr, int value)
#else
static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "FluidDomainVertexVelocity", NULL);
RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
RNA_def_property_array(prop, 3);
RNA_def_property_float_sdna(prop, NULL, "vel");
RNA_def_property_ui_text(prop, "Velocity", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_fluid_domain_settings(BlenderRNA *brna)
{
StructRNA *srna;
@ -2019,14 +2003,6 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mesh generator", "Which particle level set generator to use");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
prop = RNA_def_property(srna, "mesh_vertices", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mesh_velocities", "totvert");
RNA_def_property_struct_type(prop, "FluidDomainVertexVelocity");
RNA_def_property_ui_text(
prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
rna_def_fluid_mesh_vertices(brna);
prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_MESH);
RNA_def_property_ui_text(prop, "Use Mesh", "Enable fluid mesh (using amplification)");

View File

@ -1601,51 +1601,6 @@ static bool rna_Modifier_show_expanded_get(PointerRNA *ptr)
return md->ui_expand_flag & UI_PANEL_DATA_EXPAND_ROOT;
}
static int rna_MeshSequenceCacheModifier_has_velocity_get(PointerRNA *ptr)
{
# ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
return ABC_has_vec3_array_property_named(mcmd->reader, mcmd->cache_file->velocity_name);
# else
return false;
UNUSED_VARS(ptr);
# endif
}
static int rna_MeshSequenceCacheModifier_read_velocity_get(PointerRNA *ptr)
{
# ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
if (mcmd->num_vertices == 0) {
return 0;
}
if (mcmd->vertex_velocities) {
MEM_freeN(mcmd->vertex_velocities);
}
mcmd->vertex_velocities = MEM_mallocN(sizeof(MeshCacheVertexVelocity) * mcmd->num_vertices,
"Mesh Cache Velocities");
int num_read = ABC_read_velocity_cache(mcmd->reader,
mcmd->cache_file->velocity_name,
mcmd->last_lookup_time,
mcmd->velocity_scale * mcmd->velocity_delta,
mcmd->num_vertices,
(float *)mcmd->vertex_velocities);
if (num_read == -1 || num_read != mcmd->num_vertices) {
return false;
}
return true;
# else
return false;
UNUSED_VARS(ptr);
# endif
}
static bool rna_NodesModifier_node_group_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
bNodeTree *ntree = value.data;
@ -6118,22 +6073,6 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
static void rna_def_mesh_cache_velocities(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshCacheVertexVelocity", NULL);
RNA_def_struct_ui_text(srna, "Mesh Cache Velocity", "Velocity attribute of an Alembic mesh");
RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
RNA_def_property_array(prop, 3);
RNA_def_property_float_sdna(prop, NULL, "vel");
RNA_def_property_ui_text(prop, "Velocity", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
{
StructRNA *srna;
@ -6190,26 +6129,6 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
"Multiplier used to control the magnitude of the velocity vectors for time effects");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* -------------------------- Velocity Vectors -------------------------- */
prop = RNA_def_property(srna, "vertex_velocities", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vertex_velocities", "num_vertices");
RNA_def_property_struct_type(prop, "MeshCacheVertexVelocity");
RNA_def_property_ui_text(
prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
rna_def_mesh_cache_velocities(brna);
prop = RNA_def_property(srna, "has_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Has Velocity Cache", "");
RNA_def_property_boolean_funcs(prop, "rna_MeshSequenceCacheModifier_has_velocity_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "read_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Read Velocity Cache", "");
RNA_def_property_boolean_funcs(prop, "rna_MeshSequenceCacheModifier_read_velocity_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_define_lib_overridable(false);
}

View File

@ -105,10 +105,6 @@ static void freeData(ModifierData *md)
mcmd->reader_object_path[0] = '\0';
BKE_cachefile_reader_free(mcmd->cache_file, &mcmd->reader);
}
if (mcmd->vertex_velocities) {
MEM_freeN(mcmd->vertex_velocities);
}
}
static bool isDisabled(const struct Scene *UNUSED(scene),
@ -233,11 +229,26 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Mesh *result = NULL;
switch (cache_file->type) {
case CACHEFILE_TYPE_ALEMBIC:
case CACHEFILE_TYPE_ALEMBIC: {
# ifdef WITH_ALEMBIC
result = ABC_read_mesh(mcmd->reader, ctx->object, mesh, time, &err_str, mcmd->read_flag);
/* Time (in frames or seconds) between two velocity samples. Automatically computed to
* scale the velocity vectors at render time for generating proper motion blur data. */
float velocity_scale = mcmd->velocity_scale;
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_FRAME) {
velocity_scale *= FPS;
}
result = ABC_read_mesh(mcmd->reader,
ctx->object,
mesh,
time,
&err_str,
mcmd->read_flag,
mcmd->cache_file->velocity_name,
velocity_scale);
# endif
break;
}
case CACHEFILE_TYPE_USD:
# ifdef WITH_USD
result = USD_read_mesh(
@ -248,17 +259,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
break;
}
mcmd->velocity_delta = 1.0f;
if (mcmd->cache_file->velocity_unit == CACHEFILE_VELOCITY_UNIT_SECOND) {
mcmd->velocity_delta /= FPS;
}
mcmd->last_lookup_time = time;
if (result != NULL) {
mcmd->num_vertices = result->totvert;
}
if (err_str) {
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
}