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