Blender V4.3
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
9#include <cstdio>
10
11#include "BLI_utildefines.h"
12
13#include "BLI_math_matrix.h"
14#include "BLI_math_rotation.h"
15#include "BLI_math_vector.h"
16#include "BLI_path_utils.hh"
17#include "BLI_string.h"
18
19#include "BLT_translation.hh"
20
21#include "DNA_defaults.h"
22#include "DNA_mesh_types.h"
23#include "DNA_meshdata_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_screen_types.h"
27
28#include "BKE_deform.hh"
29#include "BKE_main.hh"
30#include "BKE_mesh.hh"
31#include "BKE_scene.hh"
32
33#include "UI_interface.hh"
34#include "UI_resources.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
40
41#include "MEM_guardedalloc.h"
42
43#include "MOD_meshcache_util.hh" /* utility functions */
44#include "MOD_modifiertypes.hh"
45#include "MOD_ui_common.hh"
46#include "MOD_util.hh"
47
56
57static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
58{
60 return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA);
61}
62
63static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
64{
66
67 /* leave it up to the modifier to check the file is valid on calculation */
68 return (mcmd->factor <= 0.0f) || (mcmd->filepath[0] == '\0');
69}
70
72 Scene *scene,
73 Object *ob,
74 Mesh *mesh,
75 float (*vertexCos_Real)[3],
76 int verts_num)
77{
78 const bool use_factor = mcmd->factor < 1.0f;
79 int influence_group_index;
80 const MDeformVert *dvert;
81 MOD_get_vgroup(ob, mesh, mcmd->defgrp_name, &dvert, &influence_group_index);
82
83 float(*vertexCos_Store)[3] = (use_factor || influence_group_index != -1 ||
85 static_cast<float(*)[3]>(MEM_malloc_arrayN(
86 verts_num, sizeof(*vertexCos_Store), __func__)) :
87 nullptr;
88 float(*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real;
89
90 const float fps = FPS;
91
92 char filepath[FILE_MAX];
93 const char *err_str = nullptr;
94 bool ok;
95
96 float time;
97
98 /* -------------------------------------------------------------------- */
99 /* Interpret Time (the reading functions also do some of this). */
100 if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) {
101 const float ctime = BKE_scene_ctime_get(scene);
102
103 switch (mcmd->time_mode) {
105 time = ctime;
106 break;
107 }
109 time = ctime / fps;
110 break;
111 }
113 default: {
114 time = ctime / fps;
115 break;
116 }
117 }
118
119 /* apply offset and scale */
120 time = (mcmd->frame_scale * time) - mcmd->frame_start;
121 }
122 else { /* if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) { */
123 switch (mcmd->time_mode) {
125 time = mcmd->eval_frame;
126 break;
127 }
129 time = mcmd->eval_time;
130 break;
131 }
133 default: {
134 time = mcmd->eval_factor;
135 break;
136 }
137 }
138 }
139
140 /* -------------------------------------------------------------------- */
141 /* Read the File (or error out when the file is bad) */
142
143 /* would be nice if we could avoid doing this _every_ frame */
144 STRNCPY(filepath, mcmd->filepath);
145 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL((ID *)ob));
146
147 switch (mcmd->type) {
150 filepath, vertexCos, verts_num, mcmd->interp, time, fps, mcmd->time_mode, &err_str);
151 break;
154 filepath, vertexCos, verts_num, mcmd->interp, time, fps, mcmd->time_mode, &err_str);
155 break;
156 default:
157 ok = false;
158 break;
159 }
160
161 /* -------------------------------------------------------------------- */
162 /* tricky shape key integration (slow!) */
164 Mesh *mesh = static_cast<Mesh *>(ob->data);
165
166 /* we could support any object type */
167 if (UNLIKELY(ob->type != OB_MESH)) {
168 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' only valid for Mesh objects");
169 }
170 else if (UNLIKELY(mesh->verts_num != verts_num)) {
171 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' original mesh vertex mismatch");
172 }
173 else if (UNLIKELY(mesh->faces_num == 0)) {
174 BKE_modifier_set_error(ob, &mcmd->modifier, "'Integrate' requires faces");
175 }
176 else {
177 float(*vertexCos_New)[3] = static_cast<float(*)[3]>(
178 MEM_malloc_arrayN(verts_num, sizeof(*vertexCos_New), __func__));
179
181 mesh->face_offsets().data(),
182 mesh->faces_num,
183 mesh->corner_verts().data(),
184 mesh->verts_num,
185 /* From the original Mesh. */
186 reinterpret_cast<const float(*)[3]>(mesh->vert_positions().data()),
187 /* the input we've been given (shape keys!) */
188 const_cast<const float(*)[3]>(vertexCos_Real),
189 /* The result of this modifier. */
190 const_cast<const float(*)[3]>(vertexCos),
191 /* The result of this function. */
192 vertexCos_New);
193
194 /* write the corrected locations back into the result */
195 memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * verts_num);
196
197 MEM_freeN(vertexCos_New);
198 }
199 }
200
201 /* -------------------------------------------------------------------- */
202 /* Apply the transformation matrix (if needed) */
203 if (UNLIKELY(err_str)) {
204 BKE_modifier_set_error(ob, &mcmd->modifier, "%s", err_str);
205 }
206 else if (ok) {
207 bool use_matrix = false;
208 float mat[3][3];
209 unit_m3(mat);
210
211 if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) {
212 use_matrix = true;
213 }
214
215 if (mcmd->flip_axis) {
216 float tmat[3][3];
217 unit_m3(tmat);
218 if (mcmd->flip_axis & (1 << 0)) {
219 tmat[0][0] = -1.0f;
220 }
221 if (mcmd->flip_axis & (1 << 1)) {
222 tmat[1][1] = -1.0f;
223 }
224 if (mcmd->flip_axis & (1 << 2)) {
225 tmat[2][2] = -1.0f;
226 }
227 mul_m3_m3m3(mat, tmat, mat);
228
229 use_matrix = true;
230 }
231
232 if (use_matrix) {
233 int i;
234 for (i = 0; i < verts_num; i++) {
235 mul_m3_v3(mat, vertexCos[i]);
236 }
237 }
238 }
239
240 if (vertexCos_Store) {
241 if (ok) {
242 if (influence_group_index != -1) {
243 const float global_factor = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ?
244 -mcmd->factor :
245 mcmd->factor;
246 const float global_offset = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ?
247 mcmd->factor :
248 0.0f;
249 if (!mesh->deform_verts().is_empty()) {
250 for (int i = 0; i < verts_num; i++) {
251 /* For each vertex, compute its blending factor between the mesh cache (for `fac = 0`)
252 * and the former position of the vertex (for `fac = 1`). */
253 const MDeformVert *currentIndexDVert = dvert + i;
254 const float local_vertex_fac = global_offset +
255 BKE_defvert_find_weight(currentIndexDVert,
256 influence_group_index) *
257 global_factor;
259 vertexCos_Real[i], vertexCos_Real[i], vertexCos_Store[i], local_vertex_fac);
260 }
261 }
262 }
263 else if (use_factor) {
264 /* Influence_group_index is -1. */
265 interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, verts_num * 3);
266 }
267 else {
268 memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * verts_num);
269 }
270 }
271
272 MEM_freeN(vertexCos_Store);
273 }
274}
275
277 const ModifierEvalContext *ctx,
278 Mesh *mesh,
280{
283
284 meshcache_do(mcmd,
285 scene,
286 ctx->object,
287 mesh,
288 reinterpret_cast<float(*)[3]>(positions.data()),
289 positions.size());
290}
291
292static void panel_draw(const bContext * /*C*/, Panel *panel)
293{
294 uiLayout *layout = panel->layout;
295
296 PointerRNA ob_ptr;
298
299 uiLayoutSetPropSep(layout, true);
300
301 uiItemR(layout, ptr, "cache_format", UI_ITEM_NONE, nullptr, ICON_NONE);
302 uiItemR(layout, ptr, "filepath", UI_ITEM_NONE, nullptr, ICON_NONE);
303
304 uiItemR(layout, ptr, "factor", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
305 uiItemR(layout, ptr, "deform_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
306 uiItemR(layout, ptr, "interpolation", UI_ITEM_NONE, nullptr, ICON_NONE);
307 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
308
309 modifier_panel_end(layout, ptr);
310}
311
312static void time_remapping_panel_draw(const bContext * /*C*/, Panel *panel)
313{
314 uiLayout *layout = panel->layout;
315
317
318 uiItemR(layout, ptr, "time_mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
319
320 uiLayoutSetPropSep(layout, true);
321
322 uiItemR(layout, ptr, "play_mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
323
324 if (RNA_enum_get(ptr, "play_mode") == MOD_MESHCACHE_PLAY_CFEA) {
325 uiItemR(layout, ptr, "frame_start", UI_ITEM_NONE, nullptr, ICON_NONE);
326 uiItemR(layout, ptr, "frame_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
327 }
328 else { /* play_mode == MOD_MESHCACHE_PLAY_EVAL */
329 int time_mode = RNA_enum_get(ptr, "time_mode");
330 if (time_mode == MOD_MESHCACHE_TIME_FRAME) {
331 uiItemR(layout, ptr, "eval_frame", UI_ITEM_NONE, nullptr, ICON_NONE);
332 }
333 else if (time_mode == MOD_MESHCACHE_TIME_SECONDS) {
334 uiItemR(layout, ptr, "eval_time", UI_ITEM_NONE, nullptr, ICON_NONE);
335 }
336 else { /* time_mode == MOD_MESHCACHE_TIME_FACTOR */
337 uiItemR(layout, ptr, "eval_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
338 }
339 }
340}
341
342static void axis_mapping_panel_draw(const bContext * /*C*/, Panel *panel)
343{
344 uiLayout *col;
345 uiLayout *layout = panel->layout;
346
348
349 uiLayoutSetPropSep(layout, true);
350
351 col = uiLayoutColumn(layout, true);
352 uiLayoutSetRedAlert(col, RNA_enum_get(ptr, "forward_axis") == RNA_enum_get(ptr, "up_axis"));
353 uiItemR(col, ptr, "forward_axis", UI_ITEM_NONE, nullptr, ICON_NONE);
354 uiItemR(col, ptr, "up_axis", UI_ITEM_NONE, nullptr, ICON_NONE);
355
356 uiItemR(layout, ptr, "flip_axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
357}
358
359static void panel_register(ARegionType *region_type)
360{
362 region_type, eModifierType_MeshCache, panel_draw);
363 modifier_subpanel_register(region_type,
364 "time_remapping",
365 "Time Remapping",
366 nullptr,
368 panel_type);
370 region_type, "axis_mapping", "Axis Mapping", nullptr, axis_mapping_panel_draw, panel_type);
371}
372
374 /*idname*/ "MeshCache",
375 /*name*/ N_("MeshCache"),
376 /*struct_name*/ "MeshCacheModifierData",
377 /*struct_size*/ sizeof(MeshCacheModifierData),
378 /*srna*/ &RNA_MeshCacheModifier,
382 /*icon*/ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
383
384 /*copy_data*/ BKE_modifier_copydata_generic,
385
386 /*deform_verts*/ deform_verts,
387 /*deform_matrices*/ nullptr,
388 /*deform_verts_EM*/ nullptr,
389 /*deform_matrices_EM*/ nullptr,
390 /*modify_mesh*/ nullptr,
391 /*modify_geometry_set*/ nullptr,
392
393 /*init_data*/ init_data,
394 /*required_data_mask*/ nullptr,
395 /*free_data*/ nullptr,
396 /*is_disabled*/ is_disabled,
397 /*update_depsgraph*/ nullptr,
398 /*depends_on_time*/ depends_on_time,
399 /*depends_on_normals*/ nullptr,
400 /*foreach_ID_link*/ nullptr,
401 /*foreach_tex_link*/ nullptr,
402 /*free_runtime_data*/ nullptr,
403 /*panel_register*/ panel_register,
404 /*blend_write*/ nullptr,
405 /*blend_read*/ nullptr,
406 /*foreach_cache*/ nullptr,
407};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
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:2317
#define BLI_assert(a)
Definition BLI_assert.h:50
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)
Definition math_vector.c:36
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
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define UNLIKELY(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:649
#define DNA_struct_default_get(struct_name)
struct MeshCacheModifierData MeshCacheModifierData
@ MOD_MESHCACHE_INVERT_VERTEX_GROUP
@ MOD_MESHCACHE_TYPE_PC2
@ MOD_MESHCACHE_TYPE_MDD
@ eModifierType_MeshCache
@ MOD_MESHCACHE_DEFORM_INTEGRATE
@ MOD_MESHCACHE_PLAY_CFEA
@ MOD_MESHCACHE_TIME_FRAME
@ MOD_MESHCACHE_TIME_FACTOR
@ MOD_MESHCACHE_TIME_SECONDS
Object is a sort of wrapper for general info.
@ OB_MESH
#define FPS
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 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)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
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_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_SLIDER
double time
draw_view in_light_buf[] float
uint col
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:413
struct uiLayout * layout
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126