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