Blender V5.0
lattice_deform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <algorithm>
12#include <cmath>
13#include <cstdlib>
14#include <cstring>
15
16#include "MEM_guardedalloc.h"
17
18#include "BLI_math_matrix.h"
19#include "BLI_math_vector.h"
20#include "BLI_simd.hh"
21#include "BLI_task.h"
22#include "BLI_utildefines.h"
23
24#include "DNA_curve_types.h"
25#include "DNA_lattice_types.h"
26#include "DNA_mesh_types.h"
27#include "DNA_meshdata_types.h"
28#include "DNA_object_types.h"
29
30#include "BKE_curve.hh"
31#include "BKE_displist.h"
32#include "BKE_editmesh.hh"
33#include "BKE_key.hh"
34#include "BKE_lattice.hh"
35#include "BKE_modifier.hh"
36#include "BKE_object.hh"
37#include "BKE_object_types.hh"
38
39#include "BKE_deform.hh"
40
41/* -------------------------------------------------------------------- */
44
46 /* Convert from object space to deform space */
47 float latmat[4][4];
48 /* Cached reference to the lattice to use for evaluation. When in edit mode this attribute
49 * is set to the edit mode lattice. */
50 const Lattice *lt;
51 /* Preprocessed lattice points (converted to deform space). */
53 /* Prefetched DeformWeights of the lattice. */
55};
56
58{
59 /* we make an array with all differences */
60 Lattice *lt = BKE_object_get_lattice(oblatt);
61 DispList *dl = oblatt->runtime->curve_cache ?
62 BKE_displist_find(&oblatt->runtime->curve_cache->disp, DL_VERTS) :
63 nullptr;
64 const float *co = dl ? dl->verts : nullptr;
65 float *fp, imat[4][4];
66 float fu, fv, fw;
67 int u, v, w;
68 float *latticedata;
69 float *lattice_weights = nullptr;
70 float latmat[4][4];
71 LatticeDeformData *lattice_deform_data;
72 /* May be null. */
73 BPoint *bp = lt->def;
74
75 const int32_t num_points = lt->pntsu * lt->pntsv * lt->pntsw;
76 /* We allocate one additional float for SSE2 optimizations. Without this
77 * the SSE2 instructions for the last item would read in unallocated memory. */
78 fp = latticedata = MEM_malloc_arrayN<float>(3 * size_t(num_points) + 1, "latticedata");
79
80 /* for example with a particle system: (ob == nullptr) */
81 if (ob == nullptr) {
82 /* In deform-space, calc matrix. */
83 invert_m4_m4(latmat, oblatt->object_to_world().ptr());
84
85 /* back: put in deform array */
86 invert_m4_m4(imat, latmat);
87 }
88 else {
89 /* In deform-space, calc matrix. */
90 invert_m4_m4(imat, oblatt->object_to_world().ptr());
91 mul_m4_m4m4(latmat, imat, ob->object_to_world().ptr());
92
93 /* back: put in deform array. */
94 invert_m4_m4(imat, latmat);
95 }
96
97 /* Prefetch lattice deform group weights. */
98 int defgrp_index = -1;
99 const MDeformVert *dvert = BKE_lattice_deform_verts_get(oblatt);
100 if (lt->vgroup[0] && dvert) {
101 defgrp_index = BKE_id_defgroup_name_index(&lt->id, lt->vgroup);
102
103 if (defgrp_index != -1) {
104 lattice_weights = MEM_malloc_arrayN<float>(size_t(num_points), "lattice_weights");
105 for (int index = 0; index < num_points; index++) {
106 lattice_weights[index] = BKE_defvert_find_weight(dvert + index, defgrp_index);
107 }
108 }
109 }
110
111 for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
112 for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
113 for (u = 0, fu = lt->fu; u < lt->pntsu; u++, fp += 3, fu += lt->du) {
114 if (dl) {
115 fp[0] = co[0] - fu;
116 fp[1] = co[1] - fv;
117 fp[2] = co[2] - fw;
118 co += 3;
119 }
120 else {
121 fp[0] = bp->vec[0] - fu;
122 fp[1] = bp->vec[1] - fv;
123 fp[2] = bp->vec[2] - fw;
124 bp++;
125 }
126
127 mul_mat3_m4_v3(imat, fp);
128 }
129 }
130 }
131
132 lattice_deform_data = MEM_mallocN<LatticeDeformData>("Lattice Deform Data");
133 lattice_deform_data->latticedata = latticedata;
134 lattice_deform_data->lattice_weights = lattice_weights;
135 lattice_deform_data->lt = lt;
136 copy_m4_m4(lattice_deform_data->latmat, latmat);
137
138 return lattice_deform_data;
139}
140
142 float co[3],
143 float weight)
144{
145 float *latticedata = lattice_deform_data->latticedata;
146 float *lattice_weights = lattice_deform_data->lattice_weights;
147 BLI_assert(latticedata);
148 const Lattice *lt = lattice_deform_data->lt;
149 float u, v, w, tu[4], tv[4], tw[4];
150 float vec[3];
151 int idx_w, idx_v, idx_u;
152 int ui, vi, wi, uu, vv, ww;
153
154 /* vgroup influence */
155 float co_prev[4] = {0}, weight_blend = 0.0f;
156 copy_v3_v3(co_prev, co);
157#if BLI_HAVE_SSE2
158 __m128 co_vec = _mm_loadu_ps(co_prev);
159#endif
160
161 /* co is in local coords, treat with latmat */
162 mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
163
164 /* u v w coords */
165
166 if (lt->pntsu > 1) {
167 u = (vec[0] - lt->fu) / lt->du;
168 ui = int(floor(u));
169 u -= ui;
171 }
172 else {
173 tu[0] = tu[2] = tu[3] = 0.0;
174 tu[1] = 1.0;
175 ui = 0;
176 }
177
178 if (lt->pntsv > 1) {
179 v = (vec[1] - lt->fv) / lt->dv;
180 vi = int(floor(v));
181 v -= vi;
183 }
184 else {
185 tv[0] = tv[2] = tv[3] = 0.0;
186 tv[1] = 1.0;
187 vi = 0;
188 }
189
190 if (lt->pntsw > 1) {
191 w = (vec[2] - lt->fw) / lt->dw;
192 wi = int(floor(w));
193 w -= wi;
195 }
196 else {
197 tw[0] = tw[2] = tw[3] = 0.0;
198 tw[1] = 1.0;
199 wi = 0;
200 }
201
202 const int w_stride = lt->pntsu * lt->pntsv;
203 const int idx_w_max = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
204 const int v_stride = lt->pntsu;
205 const int idx_v_max = (lt->pntsv - 1) * lt->pntsu;
206 const int idx_u_max = (lt->pntsu - 1);
207
208 for (ww = wi - 1; ww <= wi + 2; ww++) {
209 w = weight * tw[ww - wi + 1];
210 idx_w = std::clamp(ww * w_stride, 0, idx_w_max);
211 for (vv = vi - 1; vv <= vi + 2; vv++) {
212 v = w * tv[vv - vi + 1];
213 idx_v = std::clamp(vv * v_stride, 0, idx_v_max);
214 for (uu = ui - 1; uu <= ui + 2; uu++) {
215 u = v * tu[uu - ui + 1];
216 idx_u = std::clamp(uu, 0, idx_u_max);
217 const int idx = idx_w + idx_v + idx_u;
218#if BLI_HAVE_SSE2
219 {
220 __m128 weight_vec = _mm_set1_ps(u);
221 /* We need to address special case for last item to avoid accessing invalid memory. */
222 __m128 lattice_vec;
223 if (idx * 3 == idx_w_max) {
224 copy_v3_v3((float *)&lattice_vec, &latticedata[idx * 3]);
225 }
226 else {
227 /* When not on last item, we can safely access one extra float, it will be ignored
228 * anyway. */
229 lattice_vec = _mm_loadu_ps(&latticedata[idx * 3]);
230 }
231 co_vec = _mm_add_ps(co_vec, _mm_mul_ps(lattice_vec, weight_vec));
232 }
233#else
234 madd_v3_v3fl(co, &latticedata[idx * 3], u);
235#endif
236 if (lattice_weights) {
237 weight_blend += (u * lattice_weights[idx]);
238 }
239 }
240 }
241 }
242#if BLI_HAVE_SSE2
243 {
244 copy_v3_v3(co, (float *)&co_vec);
245 }
246#endif
247
248 if (lattice_weights) {
249 interp_v3_v3v3(co, co_prev, co, weight_blend);
250 }
251}
252
254{
255 if (lattice_deform_data->latticedata) {
256 MEM_freeN(lattice_deform_data->latticedata);
257 }
258
259 MEM_freeN(lattice_deform_data);
260}
261
263
264/* -------------------------------------------------------------------- */
269
283
285 const int index,
286 const MDeformVert *dvert)
287{
288 if (dvert != nullptr) {
289 const float weight = data->invert_vgroup ?
290 1.0f - BKE_defvert_find_weight(dvert, data->defgrp_index) :
291 BKE_defvert_find_weight(dvert, data->defgrp_index);
292 if (weight > 0.0f) {
294 data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
295 }
296 }
297 else {
299 data->lattice_deform_data, data->vert_coords[index], data->fac);
300 }
301}
302
303static void lattice_deform_vert_task(void *__restrict userdata,
304 const int index,
305 const TaskParallelTLS *__restrict /*tls*/)
306{
307 const LatticeDeformUserdata *data = static_cast<const LatticeDeformUserdata *>(userdata);
308 lattice_deform_vert_with_dvert(data, index, data->dvert ? &data->dvert[index] : nullptr);
309}
310
311static void lattice_vert_task_editmesh(void *__restrict userdata,
312 MempoolIterData *iter,
313 const TaskParallelTLS *__restrict /*tls*/)
314{
315 const LatticeDeformUserdata *data = static_cast<const LatticeDeformUserdata *>(userdata);
316 BMVert *v = (BMVert *)iter;
317 MDeformVert *dvert = static_cast<MDeformVert *>(
318 BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset));
320}
321
322static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata,
323 MempoolIterData *iter,
324 const TaskParallelTLS *__restrict /*tls*/)
325{
326 const LatticeDeformUserdata *data = static_cast<const LatticeDeformUserdata *>(userdata);
327 BMVert *v = (BMVert *)iter;
329}
330
331static void lattice_deform_coords_impl(const Object *ob_lattice,
332 const Object *ob_target,
333 float (*vert_coords)[3],
334 const int vert_coords_len,
335 const short flag,
336 const char *defgrp_name,
337 const float fac,
338 const Mesh *me_target,
339 const BMEditMesh *em_target)
340{
341 LatticeDeformData *lattice_deform_data;
342 const MDeformVert *dvert = nullptr;
343 int defgrp_index = -1;
344 int cd_dvert_offset = -1;
345
346 if (ob_lattice->type != OB_LATTICE) {
347 return;
348 }
349
350 lattice_deform_data = BKE_lattice_deform_data_create(ob_lattice, ob_target);
351
352 /* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
353 * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
354 */
355 if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
356 defgrp_index = BKE_id_defgroup_name_index(me_target ? &me_target->id : (ID *)ob_target->data,
357 defgrp_name);
358
359 if (defgrp_index != -1) {
360 /* if there's derived data without deformverts, don't use vgroups */
361 if (em_target) {
362 cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
363 }
364 else if (me_target) {
365 dvert = me_target->deform_verts().data();
366 }
367 else if (ob_target->type == OB_LATTICE) {
368 dvert = ((Lattice *)ob_target->data)->dvert;
369 }
370 else {
371 dvert = ((Mesh *)ob_target->data)->deform_verts().data();
372 }
373 }
374 }
375
377 data.lattice_deform_data = lattice_deform_data;
378 data.vert_coords = vert_coords;
379 data.dvert = dvert;
380 data.defgrp_index = defgrp_index;
381 data.fac = fac;
382 data.invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0;
383 data.bmesh.cd_dvert_offset = cd_dvert_offset;
384
385 if (em_target != nullptr) {
386 /* While this could cause an extra loop over mesh data, in most cases this will
387 * have already been properly set. */
389
390 TaskParallelSettings settings;
392
393 if (cd_dvert_offset != -1) {
395 em_target->bm->vpool, &data, lattice_vert_task_editmesh, &settings);
396 }
397 else {
399 em_target->bm->vpool, &data, lattice_vert_task_editmesh_no_dvert, &settings);
400 }
401 }
402 else {
403 TaskParallelSettings settings;
405 settings.min_iter_per_thread = 32;
406 BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
407 }
408
409 BKE_lattice_deform_data_destroy(lattice_deform_data);
410}
411
412void BKE_lattice_deform_coords(const Object *ob_lattice,
413 const Object *ob_target,
414 float (*vert_coords)[3],
415 const int vert_coords_len,
416 const short flag,
417 const char *defgrp_name,
418 float fac)
419{
421 ob_target,
422 vert_coords,
423 vert_coords_len,
424 flag,
425 defgrp_name,
426 fac,
427 nullptr,
428 nullptr);
429}
430
432 const Object *ob_target,
433 float (*vert_coords)[3],
434 const int vert_coords_len,
435 const short flag,
436 const char *defgrp_name,
437 const float fac,
438 const Mesh *me_target)
439{
441 ob_target,
442 vert_coords,
443 vert_coords_len,
444 flag,
445 defgrp_name,
446 fac,
447 me_target,
448 nullptr);
449}
450
452 const Object *ob_target,
453 float (*vert_coords)[3],
454 const int vert_coords_len,
455 const short flag,
456 const char *defgrp_name,
457 const float fac,
458 const BMEditMesh *em_target)
459{
461 ob_target,
462 vert_coords,
463 vert_coords_len,
464 flag,
465 defgrp_name,
466 fac,
467 nullptr,
468 em_target);
469}
470
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:549
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
display list (or rather multi purpose list) stuff.
DispList * BKE_displist_find(struct ListBase *lb, int type)
Definition displist.cc:71
@ DL_VERTS
void key_curve_position_weights(float t, float data[4], KeyInterpolationType type)
Definition key.cc:308
MDeformVert * BKE_lattice_deform_verts_get(const Object *oblatt)
Definition lattice.cc:569
General operations, lookup, etc. for blender objects.
Lattice * BKE_object_get_lattice(const Object *object)
#define BLI_assert(a)
Definition BLI_assert.h:46
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_mat3_m4_v3(const float mat[4][4], float r[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
struct MempoolIterData MempoolIterData
Definition BLI_task.h:200
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:221
void BLI_task_parallel_mempool(struct BLI_mempool *mempool, void *userdata, TaskParallelMempoolFunc func, const TaskParallelSettings *settings)
BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:229
#define ELEM(...)
@ CD_MDEFORMVERT
KeyInterpolationType
@ MOD_LATTICE_INVERT_VGROUP
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MESH
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
BMesh const char void * data
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
#define floor
static void lattice_deform_vert_with_dvert(const LatticeDeformUserdata *data, const int index, const MDeformVert *dvert)
static void lattice_deform_coords_impl(const Object *ob_lattice, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const short flag, const char *defgrp_name, const float fac, const Mesh *me_target, const BMEditMesh *em_target)
static void lattice_deform_vert_task(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict)
void BKE_lattice_deform_coords_with_mesh(const Object *ob_lattice, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const short flag, const char *defgrp_name, const float fac, const Mesh *me_target)
static void lattice_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict)
void BKE_lattice_deform_coords(const Object *ob_lattice, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const short flag, const char *defgrp_name, float fac)
void BKE_lattice_deform_data_destroy(LatticeDeformData *lattice_deform_data)
static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict)
LatticeDeformData * BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob)
void BKE_lattice_deform_coords_with_editmesh(const Object *ob_lattice, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const short flag, const char *defgrp_name, const float fac, const BMEditMesh *em_target)
void BKE_lattice_deform_data_eval_co(LatticeDeformData *lattice_deform_data, float co[3], float weight)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
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
CustomData vdata
struct BLI_mempool * vpool
float vec[4]
float * verts
Definition DNA_ID.h:414
const Lattice * lt
const MDeformVert * dvert
LatticeDeformData * lattice_deform_data
struct LatticeDeformUserdata::@361275110175213310073053217006263004362342100204 bmesh
char vgroup[64]
struct BPoint * def
ObjectRuntimeHandle * runtime
uint8_t flag
Definition wm_window.cc:145