Blender  V3.3
MOD_meshsequencecache.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <cstring>
8 #include <limits>
9 
10 #include "BLI_math_vector.hh"
11 #include "BLI_string.h"
12 #include "BLI_utildefines.h"
13 
14 #include "BLT_translation.h"
15 
16 #include "DNA_cachefile_types.h"
17 #include "DNA_defaults.h"
18 #include "DNA_mesh_types.h"
19 #include "DNA_modifier_types.h"
20 #include "DNA_object_types.h"
21 #include "DNA_scene_types.h"
22 #include "DNA_screen_types.h"
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BKE_cachefile.h"
27 #include "BKE_context.h"
28 #include "BKE_lib_query.h"
29 #include "BKE_mesh.h"
30 #include "BKE_object.h"
31 #include "BKE_scene.h"
32 #include "BKE_screen.h"
33 
34 #include "UI_interface.h"
35 #include "UI_resources.h"
36 
37 #include "RNA_access.h"
38 #include "RNA_prototypes.h"
39 
40 #include "BLO_read_write.h"
41 
42 #include "DEG_depsgraph_build.h"
43 #include "DEG_depsgraph_query.h"
44 
46 
47 #include "MOD_modifiertypes.h"
48 #include "MOD_ui_common.h"
49 
50 #if defined(WITH_USD) || defined(WITH_ALEMBIC)
51 # include "BKE_global.h"
52 # include "BKE_lib_id.h"
53 #endif
54 
55 #ifdef WITH_ALEMBIC
56 # include "ABC_alembic.h"
57 #endif
58 
59 #ifdef WITH_USD
60 # include "usd.h"
61 #endif
62 
63 static void initData(ModifierData *md)
64 {
65  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
66 
67  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier));
68 
69  mcmd->cache_file = nullptr;
70  mcmd->object_path[0] = '\0';
72 
74 }
75 
76 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
77 {
78 #if 0
79  const MeshSeqCacheModifierData *mcmd = (const MeshSeqCacheModifierData *)md;
80 #endif
82 
83  BKE_modifier_copydata_generic(md, target, flag);
84 
85  tmcmd->reader = nullptr;
86  tmcmd->reader_object_path[0] = '\0';
87 }
88 
89 static void freeData(ModifierData *md)
90 {
91  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
92 
93  if (mcmd->reader) {
94  mcmd->reader_object_path[0] = '\0';
96  }
97 }
98 
99 static bool isDisabled(const struct Scene *UNUSED(scene),
100  ModifierData *md,
101  bool UNUSED(useRenderParams))
102 {
103  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
104 
105  /* leave it up to the modifier to check the file is valid on calculation */
106  return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
107 }
108 
109 static Mesh *generate_bounding_box_mesh(const Mesh *org_mesh)
110 {
111  using namespace blender;
114  if (!BKE_mesh_minmax(org_mesh, min, max)) {
115  return nullptr;
116  }
117 
120 
121  return result;
122 }
123 
125 {
126 #if defined(WITH_USD) || defined(WITH_ALEMBIC)
127  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
128 
129  /* Only used to check whether we are operating on org data or not... */
130  Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr;
131  Mesh *org_mesh = mesh;
132 
134  CacheFile *cache_file = mcmd->cache_file;
135  const float frame = DEG_get_ctime(ctx->depsgraph);
136  const double time = BKE_cachefile_time_offset(cache_file, (double)frame, FPS);
137  const char *err_str = nullptr;
138 
139  if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
140  STRNCPY(mcmd->reader_object_path, mcmd->object_path);
141  BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
142  if (!mcmd->reader) {
144  ctx->object, md, "Could not create reader for file %s", cache_file->filepath);
145  return mesh;
146  }
147  }
148 
149  /* Do not process data if using a render procedural, return a box instead for displaying in the
150  * viewport. */
151  if (BKE_cache_file_uses_render_procedural(cache_file, scene)) {
152  return generate_bounding_box_mesh(org_mesh);
153  }
154 
155  /* If this invocation is for the ORCO mesh, and the mesh hasn't changed topology, we
156  * must return the mesh as-is instead of deforming it. */
157  if (ctx->flag & MOD_APPLY_ORCO) {
158  switch (cache_file->type) {
160 # ifdef WITH_ALEMBIC
161  if (!ABC_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
162  return mesh;
163  }
164 # endif
165  break;
166  case CACHEFILE_TYPE_USD:
167 # ifdef WITH_USD
168  if (!USD_mesh_topology_changed(mcmd->reader, ctx->object, mesh, time, &err_str)) {
169  return mesh;
170  }
171 # endif
172  break;
174  break;
175  }
176  }
177 
178  if (me != nullptr) {
179  MVert *mvert = mesh->mvert;
180  MEdge *medge = mesh->medge;
181  MPoly *mpoly = mesh->mpoly;
182 
183  /* TODO(sybren+bastien): possibly check relevant custom data layers (UV/color depending on
184  * flags) and duplicate those too. */
185  if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
186  /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
187  mesh = reinterpret_cast<Mesh *>(
188  BKE_id_copy_ex(nullptr,
189  &mesh->id,
190  nullptr,
193  }
194  }
195 
196  Mesh *result = nullptr;
197 
198  switch (cache_file->type) {
199  case CACHEFILE_TYPE_ALEMBIC: {
200 # ifdef WITH_ALEMBIC
201  /* Time (in frames or seconds) between two velocity samples. Automatically computed to
202  * scale the velocity vectors at render time for generating proper motion blur data. */
203  float velocity_scale = mcmd->velocity_scale;
205  velocity_scale *= FPS;
206  }
207 
208  ABCReadParams params = {};
209  params.time = time;
210  params.read_flags = mcmd->read_flag;
211  params.velocity_name = mcmd->cache_file->velocity_name;
212  params.velocity_scale = velocity_scale;
213 
214  result = ABC_read_mesh(mcmd->reader, ctx->object, mesh, &params, &err_str);
215 # endif
216  break;
217  }
218  case CACHEFILE_TYPE_USD:
219 # ifdef WITH_USD
221  mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag);
222 # endif
223  break;
225  break;
226  }
227 
228  if (err_str) {
229  BKE_modifier_set_error(ctx->object, md, "%s", err_str);
230  }
231 
232  if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) {
233  BKE_id_free(nullptr, mesh);
234  mesh = org_mesh;
235  }
236 
237  return result ? result : mesh;
238 #else
240  return mesh;
241 #endif
242 }
243 
245 {
246 #if defined(WITH_USD) || defined(WITH_ALEMBIC)
247  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
248  /* Do not evaluate animations if using the render engine procedural. */
249  return (mcmd->cache_file != nullptr) &&
251 #else
252  UNUSED_VARS(scene, md);
253  return false;
254 #endif
255 }
256 
257 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
258 {
259  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
260 
261  walk(userData, ob, reinterpret_cast<ID **>(&mcmd->cache_file), IDWALK_CB_USER);
262 }
263 
265 {
266  MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
267 
268  if (mcmd->cache_file != nullptr) {
270  ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
271  }
272 }
273 
274 static void panel_draw(const bContext *C, Panel *panel)
275 {
276  uiLayout *layout = panel->layout;
277 
278  PointerRNA ob_ptr;
280 
281  PointerRNA cache_file_ptr = RNA_pointer_get(ptr, "cache_file");
282  bool has_cache_file = !RNA_pointer_is_null(&cache_file_ptr);
283 
284  uiLayoutSetPropSep(layout, true);
285 
286  uiTemplateCacheFile(layout, C, ptr, "cache_file");
287 
288  if (has_cache_file) {
290  layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE);
291  }
292 
293  if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
294  uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
295  uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE);
296  }
297 
298  modifier_panel_end(layout, ptr);
299 }
300 
301 static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
302 {
303  uiLayout *layout = panel->layout;
304 
305  PointerRNA ob_ptr;
307 
308  PointerRNA fileptr;
309  if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
310  return;
311  }
312 
313  uiLayoutSetPropSep(layout, true);
314  uiTemplateCacheFileVelocity(layout, &fileptr);
315  uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE);
316 }
317 
318 static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
319 {
320  uiLayout *layout = panel->layout;
321 
322  PointerRNA ob_ptr;
324 
325  PointerRNA fileptr;
326  if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
327  return;
328  }
329 
330  uiLayoutSetPropSep(layout, true);
331  uiTemplateCacheFileTimeSettings(layout, &fileptr);
332 }
333 
334 static void render_procedural_panel_draw(const bContext *C, Panel *panel)
335 {
336  uiLayout *layout = panel->layout;
337 
338  PointerRNA ob_ptr;
340 
341  PointerRNA fileptr;
342  if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
343  return;
344  }
345 
346  uiLayoutSetPropSep(layout, true);
347  uiTemplateCacheFileProcedural(layout, C, &fileptr);
348 }
349 
350 static void override_layers_panel_draw(const bContext *C, Panel *panel)
351 {
352  uiLayout *layout = panel->layout;
353 
354  PointerRNA ob_ptr;
356 
357  PointerRNA fileptr;
358  if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
359  return;
360  }
361 
362  uiLayoutSetPropSep(layout, true);
363  uiTemplateCacheFileLayers(layout, C, &fileptr);
364 }
365 
366 static void panelRegister(ARegionType *region_type)
367 {
368  PanelType *panel_type = modifier_panel_register(
370  modifier_subpanel_register(region_type, "time", "Time", nullptr, time_panel_draw, panel_type);
371  modifier_subpanel_register(region_type,
372  "render_procedural",
373  "Render Procedural",
374  nullptr,
376  panel_type);
378  region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type);
379  modifier_subpanel_register(region_type,
380  "override_layers",
381  "Override Layers",
382  nullptr,
384  panel_type);
385 }
386 
387 static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
388 {
389  MeshSeqCacheModifierData *msmcd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
390  msmcd->reader = nullptr;
391  msmcd->reader_object_path[0] = '\0';
392 }
393 
395  /* name */ N_("MeshSequenceCache"),
396  /* structName */ "MeshSeqCacheModifierData",
397  /* structSize */ sizeof(MeshSeqCacheModifierData),
398  /* srna */ &RNA_MeshSequenceCacheModifier,
400  /* flags */
402  /* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
403 
404  /* copyData */ copyData,
405 
406  /* deformVerts */ nullptr,
407  /* deformMatrices */ nullptr,
408  /* deformVertsEM */ nullptr,
409  /* deformMatricesEM */ nullptr,
410  /* modifyMesh */ modifyMesh,
411  /* modifyGeometrySet */ nullptr,
412 
413  /* initData */ initData,
414  /* requiredDataMask */ nullptr,
415  /* freeData */ freeData,
416  /* isDisabled */ isDisabled,
417  /* updateDepsgraph */ updateDepsgraph,
418  /* dependsOnTime */ dependsOnTime,
419  /* dependsOnNormals */ nullptr,
420  /* foreachIDLink */ foreachIDLink,
421  /* foreachTexLink */ nullptr,
422  /* freeRuntimeData */ nullptr,
423  /* panelRegister */ panelRegister,
424  /* blendWrite */ nullptr,
425  /* blendRead */ blendRead,
426 };
struct Mesh * ABC_read_mesh(struct CacheReader *reader, struct Object *ob, struct Mesh *existing_mesh, const ABCReadParams *params, const char **err_str)
bool ABC_mesh_topology_changed(struct CacheReader *reader, struct Object *ob, const struct Mesh *existing_mesh, double time, const char **err_str)
void BKE_cachefile_reader_open(struct CacheFile *cache_file, struct CacheReader **reader, struct Object *object, const char *object_path)
Definition: cachefile.c:174
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader)
Definition: cachefile.c:223
double BKE_cachefile_time_offset(const struct CacheFile *cache_file, double time, double fps)
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, struct Scene *scene)
@ LIB_ID_COPY_NO_PREVIEW
Definition: BKE_lib_id.h:150
@ LIB_ID_CREATE_NO_USER_REFCOUNT
Definition: BKE_lib_id.h:126
@ LIB_ID_CREATE_NO_MAIN
Definition: BKE_lib_id.h:122
@ LIB_ID_CREATE_NO_DEG_TAG
Definition: BKE_lib_id.h:133
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag)
void BKE_id_free(struct Main *bmain, void *idv)
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:73
void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys)
Definition: mesh.cc:1632
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3])
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
ModifierTypeFlag
Definition: BKE_modifier.h:65
@ eModifierTypeFlag_AcceptsCVs
Definition: BKE_modifier.h:67
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:47
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_ORCO
Definition: BKE_modifier.h:120
General operations, lookup, etc. for blender objects.
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
#define UNUSED_VARS(...)
#define UNUSED(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
@ DEG_OB_COMP_CACHE
void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description)
float DEG_get_ctime(const Depsgraph *graph)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ CACHE_FILE_TYPE_INVALID
@ CACHEFILE_TYPE_ALEMBIC
@ CACHEFILE_TYPE_USD
@ CACHEFILE_VELOCITY_UNIT_FRAME
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
struct MeshSeqCacheModifierData MeshSeqCacheModifierData
@ eModifierType_MeshSequenceCache
#define MOD_MESHSEQ_READ_ALL
Object is a sort of wrapper for general info.
@ OB_MESH
#define FPS
Read Guarded memory(de)allocation.
static Mesh * generate_bounding_box_mesh(const Mesh *org_mesh)
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
ModifierTypeInfo modifierType_MeshSequenceCache
static void override_layers_panel_draw(const bContext *C, Panel *panel)
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static bool dependsOnTime(Scene *scene, ModifierData *md)
static void freeData(ModifierData *md)
static void render_procedural_panel_draw(const bContext *C, Panel *panel)
static void panel_draw(const bContext *C, Panel *panel)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
#define C
Definition: RandGen.cpp:25
void uiTemplateCacheFileLayers(uiLayout *layout, const struct bContext *C, struct PointerRNA *fileptr)
void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr)
void uiTemplateCacheFileProcedural(uiLayout *layout, const struct bContext *C, struct PointerRNA *fileptr)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
@ UI_ITEM_R_EXPAND
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
bool uiTemplateCacheFilePointer(struct PointerRNA *ptr, const char *propname, struct PointerRNA *r_file_ptr)
void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr)
void uiTemplateCacheFile(uiLayout *layout, const struct bContext *C, struct PointerRNA *ptr, const char *propname)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
double time
Scene scene
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Mesh * create_cuboid_mesh(const float3 &size, int verts_x, int verts_y, int verts_z, const bke::AttributeIDRef &uv_id)
T midpoint(const T &a, const T &b)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:164
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
#define min(a, b)
Definition: sort.c:35
char filepath[1024]
char velocity_name[64]
Definition: DNA_ID.h:368
struct CacheReader * reader
struct CacheFile * cache_file
struct MEdge * medge
struct MVert * mvert
struct MPoly * mpoly
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:140
ModifierApplyFlag flag
Definition: BKE_modifier.h:142
struct Object * object
Definition: BKE_modifier.h:141
struct DepsNodeHandle * node
Definition: BKE_modifier.h:134
void * data
struct uiLayout * layout
float max
struct Mesh * USD_read_mesh(struct CacheReader *reader, struct Object *ob, struct Mesh *existing_mesh, const double time, const char **err_str, const int read_flag)
bool USD_mesh_topology_changed(CacheReader *reader, Object *ob, Mesh *existing_mesh, const double time, const char **err_str)
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480