Blender V5.0
MOD_meshcache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_utildefines.h"
10
11#include "BLI_math_matrix.h"
12#include "BLI_math_rotation.h"
13#include "BLI_math_vector.h"
14#include "BLI_path_utils.hh"
15#include "BLI_string.h"
16
17#include "BLT_translation.hh"
18
19#include "DNA_defaults.h"
20#include "DNA_mesh_types.h"
21#include "DNA_meshdata_types.h"
22#include "DNA_object_types.h"
23#include "DNA_scene_types.h"
24#include "DNA_screen_types.h"
25
26#include "BKE_deform.hh"
27#include "BKE_library.hh"
28#include "BKE_main.hh"
29#include "BKE_mesh.hh"
30#include "BKE_scene.hh"
31
33#include "UI_resources.hh"
34
35#include "RNA_access.hh"
36#include "RNA_prototypes.hh"
37
39
40#include "MEM_guardedalloc.h"
41
42#include "MOD_meshcache_util.hh" /* utility functions */
43#include "MOD_modifiertypes.hh"
44#include "MOD_ui_common.hh"
45#include "MOD_util.hh"
46
55
56static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
57{
59 return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA);
60}
61
62static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
63{
65
66 /* leave it up to the modifier to check the file is valid on calculation */
67 return (mcmd->factor <= 0.0f) || (mcmd->filepath[0] == '\0');
68}
69
71 Scene *scene,
72 Object *ob,
73 Mesh *mesh,
74 float (*vertexCos_Real)[3],
75 int verts_num)
76{
77 const bool use_factor = mcmd->factor < 1.0f;
78 int influence_group_index;
79 const MDeformVert *dvert;
80 MOD_get_vgroup(ob, mesh, mcmd->defgrp_name, &dvert, &influence_group_index);
81
82 float (*vertexCos_Store)[3] = (use_factor || influence_group_index != -1 ||
84 MEM_malloc_arrayN<float[3]>(size_t(verts_num), __func__) :
85 nullptr;
86 float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real;
87
88 const float fps = scene->frames_per_second();
89
90 char filepath[FILE_MAX];
91 const char *err_str = nullptr;
92 bool ok;
93
94 float time;
95
96 /* -------------------------------------------------------------------- */
97 /* Interpret Time (the reading functions also do some of this). */
99 const float ctime = BKE_scene_ctime_get(scene);
100
101 switch (mcmd->time_mode) {
103 time = ctime;
104 break;
105 }
107 time = ctime / fps;
108 break;
109 }
111 default: {
112 time = ctime / fps;
113 break;
114 }
115 }
116
117 /* apply offset and scale */
118 time = (mcmd->frame_scale * time) - mcmd->frame_start;
119 }
120 else { /* `if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) {`. */
121 switch (mcmd->time_mode) {
123 time = mcmd->eval_frame;
124 break;
125 }
127 time = mcmd->eval_time;
128 break;
129 }
131 default: {
132 time = mcmd->eval_factor;
133 break;
134 }
135 }
136 }
137
138 /* -------------------------------------------------------------------- */
139 /* Read the File (or error out when the file is bad) */
140
141 /* would be nice if we could avoid doing this _every_ frame */
142 STRNCPY(filepath, mcmd->filepath);
143 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL((ID *)ob));
144
145 switch (mcmd->type) {
148 filepath, vertexCos, verts_num, mcmd->interp, time, fps, mcmd->time_mode, &err_str);
149 break;
152 filepath, vertexCos, verts_num, mcmd->interp, time, fps, mcmd->time_mode, &err_str);
153 break;
154 default:
155 ok = false;
156 break;
157 }
158
159 /* -------------------------------------------------------------------- */
160 /* tricky shape key integration (slow!) */
162 Mesh *mesh = static_cast<Mesh *>(ob->data);
163
164 /* we could support any object type */
165 if (UNLIKELY(ob->type != OB_MESH)) {
166 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' only valid for Mesh objects");
167 }
168 else if (UNLIKELY(mesh->verts_num != verts_num)) {
169 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' original mesh vertex mismatch");
170 }
171 else if (UNLIKELY(mesh->faces_num == 0)) {
172 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' requires faces");
173 }
174 else {
175 float (*vertexCos_New)[3] = MEM_malloc_arrayN<float[3]>(size_t(verts_num), __func__);
176
178 mesh->face_offsets().data(),
179 mesh->faces_num,
180 mesh->corner_verts().data(),
181 mesh->verts_num,
182 /* From the original Mesh. */
183 reinterpret_cast<const float (*)[3]>(mesh->vert_positions().data()),
184 /* the input we've been given (shape keys!) */
185 const_cast<const float (*)[3]>(vertexCos_Real),
186 /* The result of this modifier. */
187 const_cast<const float (*)[3]>(vertexCos),
188 /* The result of this function. */
189 vertexCos_New);
190
191 /* write the corrected locations back into the result */
192 memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * verts_num);
193
194 MEM_freeN(vertexCos_New);
195 }
196 }
197
198 /* -------------------------------------------------------------------- */
199 /* Apply the transformation matrix (if needed) */
200 if (UNLIKELY(err_str)) {
201 BKE_modifier_set_error(ob, &mcmd->modifier, "%s", err_str);
202 }
203 else if (ok) {
204 bool use_matrix = false;
205 float mat[3][3];
206 unit_m3(mat);
207
208 if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) {
209 use_matrix = true;
210 }
211
212 if (mcmd->flip_axis) {
213 float tmat[3][3];
214 unit_m3(tmat);
216 tmat[0][0] = -1.0f;
217 }
219 tmat[1][1] = -1.0f;
220 }
222 tmat[2][2] = -1.0f;
223 }
224 mul_m3_m3m3(mat, tmat, mat);
225
226 use_matrix = true;
227 }
228
229 if (use_matrix) {
230 int i;
231 for (i = 0; i < verts_num; i++) {
232 mul_m3_v3(mat, vertexCos[i]);
233 }
234 }
235 }
236
237 if (vertexCos_Store) {
238 if (ok) {
239 if (influence_group_index != -1) {
240 const float global_factor = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ?
241 -mcmd->factor :
242 mcmd->factor;
243 const float global_offset = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ?
244 mcmd->factor :
245 0.0f;
246 if (!mesh->deform_verts().is_empty()) {
247 for (int i = 0; i < verts_num; i++) {
248 /* For each vertex, compute its blending factor between the mesh cache (for `fac = 0`)
249 * and the former position of the vertex (for `fac = 1`). */
250 const MDeformVert *currentIndexDVert = dvert + i;
251 const float local_vertex_fac = global_offset +
252 BKE_defvert_find_weight(currentIndexDVert,
253 influence_group_index) *
254 global_factor;
256 vertexCos_Real[i], vertexCos_Real[i], vertexCos_Store[i], local_vertex_fac);
257 }
258 }
259 }
260 else if (use_factor) {
261 /* Influence_group_index is -1. */
262 interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, verts_num * 3);
263 }
264 else {
265 memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * verts_num);
266 }
267 }
268
269 MEM_freeN(vertexCos_Store);
270 }
271}
272
274 const ModifierEvalContext *ctx,
275 Mesh *mesh,
277{
280
281 meshcache_do(mcmd,
282 scene,
283 ctx->object,
284 mesh,
285 reinterpret_cast<float (*)[3]>(positions.data()),
286 positions.size());
287}
288
289static void panel_draw(const bContext * /*C*/, Panel *panel)
290{
291 uiLayout *layout = panel->layout;
292
293 PointerRNA ob_ptr;
295
296 layout->use_property_split_set(true);
297
298 layout->prop(ptr, "cache_format", UI_ITEM_NONE, std::nullopt, ICON_NONE);
299 layout->prop(ptr, "filepath", UI_ITEM_NONE, std::nullopt, ICON_NONE);
300
301 layout->prop(ptr, "factor", UI_ITEM_R_SLIDER, std::nullopt, ICON_NONE);
302 layout->prop(ptr, "deform_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
303 layout->prop(ptr, "interpolation", UI_ITEM_NONE, std::nullopt, ICON_NONE);
304 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
305
307}
308
309static void time_remapping_panel_draw(const bContext * /*C*/, Panel *panel)
310{
311 uiLayout *layout = panel->layout;
312
314
315 layout->prop(ptr, "time_mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
316
317 layout->use_property_split_set(true);
318
319 layout->prop(ptr, "play_mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
320
321 if (RNA_enum_get(ptr, "play_mode") == MOD_MESHCACHE_PLAY_CFEA) {
322 layout->prop(ptr, "frame_start", UI_ITEM_NONE, std::nullopt, ICON_NONE);
323 layout->prop(ptr, "frame_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
324 }
325 else { /* play_mode == MOD_MESHCACHE_PLAY_EVAL */
326 int time_mode = RNA_enum_get(ptr, "time_mode");
327 if (time_mode == MOD_MESHCACHE_TIME_FRAME) {
328 layout->prop(ptr, "eval_frame", UI_ITEM_NONE, std::nullopt, ICON_NONE);
329 }
330 else if (time_mode == MOD_MESHCACHE_TIME_SECONDS) {
331 layout->prop(ptr, "eval_time", UI_ITEM_NONE, std::nullopt, ICON_NONE);
332 }
333 else { /* time_mode == MOD_MESHCACHE_TIME_FACTOR */
334 layout->prop(ptr, "eval_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
335 }
336 }
337}
338
339static void axis_mapping_panel_draw(const bContext * /*C*/, Panel *panel)
340{
341 uiLayout *col;
342 uiLayout *layout = panel->layout;
343
345
346 layout->use_property_split_set(true);
347
348 col = &layout->column(true);
349 col->red_alert_set(RNA_enum_get(ptr, "forward_axis") == RNA_enum_get(ptr, "up_axis"));
350 col->prop(ptr, "forward_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
351 col->prop(ptr, "up_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
352
354 PropertyRNA *prop = RNA_struct_find_property(ptr, "flip_axis");
355 uiLayout *row = &col->row(true, IFACE_("Flip Axis"));
356 row->prop(ptr, prop, 0, 0, toggles_flag, IFACE_("X"), ICON_NONE);
357 row->prop(ptr, prop, 1, 0, toggles_flag, IFACE_("Y"), ICON_NONE);
358 row->prop(ptr, prop, 2, 0, toggles_flag, IFACE_("Z"), ICON_NONE);
359}
360
361static void panel_register(ARegionType *region_type)
362{
364 region_type, eModifierType_MeshCache, panel_draw);
365 modifier_subpanel_register(region_type,
366 "time_remapping",
367 "Time Remapping",
368 nullptr,
370 panel_type);
372 region_type, "axis_mapping", "Axis Mapping", nullptr, axis_mapping_panel_draw, panel_type);
373}
374
376 /*idname*/ "MeshCache",
377 /*name*/ N_("MeshCache"),
378 /*struct_name*/ "MeshCacheModifierData",
379 /*struct_size*/ sizeof(MeshCacheModifierData),
380 /*srna*/ &RNA_MeshCacheModifier,
384 /*icon*/ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
385
386 /*copy_data*/ BKE_modifier_copydata_generic,
387
388 /*deform_verts*/ deform_verts,
389 /*deform_matrices*/ nullptr,
390 /*deform_verts_EM*/ nullptr,
391 /*deform_matrices_EM*/ nullptr,
392 /*modify_mesh*/ nullptr,
393 /*modify_geometry_set*/ nullptr,
394
395 /*init_data*/ init_data,
396 /*required_data_mask*/ nullptr,
397 /*free_data*/ nullptr,
398 /*is_disabled*/ is_disabled,
399 /*update_depsgraph*/ nullptr,
400 /*depends_on_time*/ depends_on_time,
401 /*depends_on_normals*/ nullptr,
402 /*foreach_ID_link*/ nullptr,
403 /*foreach_tex_link*/ nullptr,
404 /*free_runtime_data*/ nullptr,
405 /*panel_register*/ panel_register,
406 /*blend_write*/ nullptr,
407 /*blend_read*/ nullptr,
408 /*foreach_cache*/ nullptr,
409 /*foreach_working_space_color*/ nullptr,
410};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
void BKE_mesh_calc_relative_deform(const int *face_offsets, int faces_num, const int *corner_verts, int totvert, const float(*vert_cos_src)[3], const float(*vert_cos_dst)[3], const float(*vert_cos_org)[3], float(*vert_cos_new)[3])
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsVertexCosOnly
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
#define BLI_assert(a)
Definition BLI_assert.h:46
void mul_m3_v3(const float M[3][3], float r[3])
void unit_m3(float m[3][3])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
void interp_vn_vn(float *array_tar, const float *array_src, float t, int size)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define UNLIKELY(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:688
#define DNA_struct_default_get(struct_name)
@ MOD_MESHCACHE_INVERT_VERTEX_GROUP
@ MOD_MESHCACHE_FLIP_AXIS_Z
@ MOD_MESHCACHE_FLIP_AXIS_X
@ MOD_MESHCACHE_FLIP_AXIS_Y
@ MOD_MESHCACHE_DEFORM_INTEGRATE
@ MOD_MESHCACHE_PLAY_CFEA
@ MOD_MESHCACHE_TIME_FRAME
@ MOD_MESHCACHE_TIME_FACTOR
@ MOD_MESHCACHE_TIME_SECONDS
@ eModifierType_MeshCache
@ MOD_MESHCACHE_TYPE_PC2
@ MOD_MESHCACHE_TYPE_MDD
Object is a sort of wrapper for general info.
@ OB_MESH
static bool is_disabled
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
static void panel_draw(const bContext *, Panel *panel)
static bool depends_on_time(Scene *, ModifierData *)
Definition MOD_build.cc:47
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
static void time_remapping_panel_draw(const bContext *, Panel *panel)
static void meshcache_do(MeshCacheModifierData *mcmd, Scene *scene, Object *ob, Mesh *mesh, float(*vertexCos_Real)[3], int verts_num)
ModifierTypeInfo modifierType_MeshCache
static bool depends_on_time(Scene *, ModifierData *md)
static void axis_mapping_panel_draw(const bContext *, Panel *panel)
static void panel_draw(const bContext *, Panel *panel)
bool MOD_meshcache_read_mdd_times(const char *filepath, float(*vertexCos)[3], const int verts_tot, const char interp, const float time, const float fps, const char time_mode, const char **r_err_str)
bool MOD_meshcache_read_pc2_times(const char *filepath, float(*vertexCos)[3], const int verts_tot, const char interp, const float time, const float fps, const char time_mode, const char **r_err_str)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:156
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_SLIDER
#define UI_ITEM_NONE
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
nullptr float
uint col
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:414
int faces_num
int verts_num
struct uiLayout * layout
uiLayout & column(bool align)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238