Blender  V2.93
lattice_deform.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_math.h"
34 #include "BLI_simd.h"
35 #include "BLI_task.h"
36 #include "BLI_utildefines.h"
37 
38 #include "DNA_curve_types.h"
39 #include "DNA_lattice_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 
44 #include "BKE_curve.h"
45 #include "BKE_displist.h"
46 #include "BKE_editmesh.h"
47 #include "BKE_key.h"
48 #include "BKE_lattice.h"
49 #include "BKE_modifier.h"
50 #include "BKE_object.h"
51 
52 #include "BKE_deform.h"
53 
54 /* -------------------------------------------------------------------- */
58 typedef struct LatticeDeformData {
59  /* Convert from object space to deform space */
60  float latmat[4][4];
61  /* Cached reference to the lattice to use for evaluation. When in edit mode this attribute
62  * is set to the edit mode lattice. */
63  const Lattice *lt;
64  /* Preprocessed lattice points (converted to deform space). */
65  float *latticedata;
66  /* Prefetched DeformWeights of the lattice. */
69 
71 {
72  /* we make an array with all differences */
73  Lattice *lt = BKE_object_get_lattice(oblatt);
74  BPoint *bp;
75  DispList *dl = oblatt->runtime.curve_cache ?
77  NULL;
78  const float *co = dl ? dl->verts : NULL;
79  float *fp, imat[4][4];
80  float fu, fv, fw;
81  int u, v, w;
82  float *latticedata;
83  float *lattice_weights = NULL;
84  float latmat[4][4];
85  LatticeDeformData *lattice_deform_data;
86 
87  bp = lt->def;
88 
89  const int32_t num_points = lt->pntsu * lt->pntsv * lt->pntsw;
90  /* We allocate one additional float for SSE2 optimizations. Without this
91  * the SSE2 instructions for the last item would read in unallocated memory. */
92  fp = latticedata = MEM_mallocN(sizeof(float[3]) * num_points + sizeof(float), "latticedata");
93 
94  /* for example with a particle system: (ob == NULL) */
95  if (ob == NULL) {
96  /* in deformspace, calc matrix */
97  invert_m4_m4(latmat, oblatt->obmat);
98 
99  /* back: put in deform array */
100  invert_m4_m4(imat, latmat);
101  }
102  else {
103  /* in deformspace, calc matrix */
104  invert_m4_m4(imat, oblatt->obmat);
105  mul_m4_m4m4(latmat, imat, ob->obmat);
106 
107  /* back: put in deform array */
108  invert_m4_m4(imat, latmat);
109  }
110 
111  /* Prefetch latice deform group weights. */
112  int defgrp_index = -1;
113  const MDeformVert *dvert = BKE_lattice_deform_verts_get(oblatt);
114  if (lt->vgroup[0] && dvert) {
115  defgrp_index = BKE_object_defgroup_name_index(oblatt, lt->vgroup);
116 
117  if (defgrp_index != -1) {
118  lattice_weights = MEM_malloc_arrayN(sizeof(float), num_points, "lattice_weights");
119  for (int index = 0; index < num_points; index++) {
120  lattice_weights[index] = BKE_defvert_find_weight(dvert + index, defgrp_index);
121  }
122  }
123  }
124 
125  for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
126  for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
127  for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
128  if (dl) {
129  fp[0] = co[0] - fu;
130  fp[1] = co[1] - fv;
131  fp[2] = co[2] - fw;
132  }
133  else {
134  fp[0] = bp->vec[0] - fu;
135  fp[1] = bp->vec[1] - fv;
136  fp[2] = bp->vec[2] - fw;
137  }
138 
139  mul_mat3_m4_v3(imat, fp);
140  }
141  }
142  }
143 
144  lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
145  lattice_deform_data->latticedata = latticedata;
146  lattice_deform_data->lattice_weights = lattice_weights;
147  lattice_deform_data->lt = lt;
148  copy_m4_m4(lattice_deform_data->latmat, latmat);
149 
150  return lattice_deform_data;
151 }
152 
154  float co[3],
155  float weight)
156 {
157  float *latticedata = lattice_deform_data->latticedata;
158  float *lattice_weights = lattice_deform_data->lattice_weights;
159  BLI_assert(latticedata);
160  const Lattice *lt = lattice_deform_data->lt;
161  float u, v, w, tu[4], tv[4], tw[4];
162  float vec[3];
163  int idx_w, idx_v, idx_u;
164  int ui, vi, wi, uu, vv, ww;
165 
166  /* vgroup influence */
167  float co_prev[4] = {0}, weight_blend = 0.0f;
168  copy_v3_v3(co_prev, co);
169 #ifdef BLI_HAVE_SSE2
170  __m128 co_vec = _mm_loadu_ps(co_prev);
171 #endif
172 
173  /* co is in local coords, treat with latmat */
174  mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
175 
176  /* u v w coords */
177 
178  if (lt->pntsu > 1) {
179  u = (vec[0] - lt->fu) / lt->du;
180  ui = (int)floor(u);
181  u -= ui;
182  key_curve_position_weights(u, tu, lt->typeu);
183  }
184  else {
185  tu[0] = tu[2] = tu[3] = 0.0;
186  tu[1] = 1.0;
187  ui = 0;
188  }
189 
190  if (lt->pntsv > 1) {
191  v = (vec[1] - lt->fv) / lt->dv;
192  vi = (int)floor(v);
193  v -= vi;
195  }
196  else {
197  tv[0] = tv[2] = tv[3] = 0.0;
198  tv[1] = 1.0;
199  vi = 0;
200  }
201 
202  if (lt->pntsw > 1) {
203  w = (vec[2] - lt->fw) / lt->dw;
204  wi = (int)floor(w);
205  w -= wi;
207  }
208  else {
209  tw[0] = tw[2] = tw[3] = 0.0;
210  tw[1] = 1.0;
211  wi = 0;
212  }
213 
214  const int w_stride = lt->pntsu * lt->pntsv;
215  const int idx_w_max = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
216  const int v_stride = lt->pntsu;
217  const int idx_v_max = (lt->pntsv - 1) * lt->pntsu;
218  const int idx_u_max = (lt->pntsu - 1);
219 
220  for (ww = wi - 1; ww <= wi + 2; ww++) {
221  w = weight * tw[ww - wi + 1];
222  idx_w = CLAMPIS(ww * w_stride, 0, idx_w_max);
223  for (vv = vi - 1; vv <= vi + 2; vv++) {
224  v = w * tv[vv - vi + 1];
225  idx_v = CLAMPIS(vv * v_stride, 0, idx_v_max);
226  for (uu = ui - 1; uu <= ui + 2; uu++) {
227  u = v * tu[uu - ui + 1];
228  idx_u = CLAMPIS(uu, 0, idx_u_max);
229  const int idx = idx_w + idx_v + idx_u;
230 #ifdef BLI_HAVE_SSE2
231  {
232  __m128 weight_vec = _mm_set1_ps(u);
233  /* We need to address special case for last item to avoid accessing invalid memory. */
234  __m128 lattice_vec;
235  if (idx * 3 == idx_w_max) {
236  copy_v3_v3((float *)&lattice_vec, &latticedata[idx * 3]);
237  }
238  else {
239  /* When not on last item, we can safely access one extra float, it will be ignored
240  * anyway. */
241  lattice_vec = _mm_loadu_ps(&latticedata[idx * 3]);
242  }
243  co_vec = _mm_add_ps(co_vec, _mm_mul_ps(lattice_vec, weight_vec));
244  }
245 #else
246  madd_v3_v3fl(co, &latticedata[idx * 3], u);
247 #endif
248  if (lattice_weights) {
249  weight_blend += (u * lattice_weights[idx]);
250  }
251  }
252  }
253  }
254 #ifdef BLI_HAVE_SSE2
255  {
256  copy_v3_v3(co, (float *)&co_vec);
257  }
258 #endif
259 
260  if (lattice_weights) {
261  interp_v3_v3v3(co, co_prev, co, weight_blend);
262  }
263 }
264 
266 {
267  if (lattice_deform_data->latticedata) {
268  MEM_freeN(lattice_deform_data->latticedata);
269  }
270 
271  MEM_freeN(lattice_deform_data);
272 }
273 
276 /* -------------------------------------------------------------------- */
282 typedef struct LatticeDeformUserdata {
287  float fac;
289 
291  struct {
293  } bmesh;
295 
297  const int index,
298  const MDeformVert *dvert)
299 {
300  if (dvert != NULL) {
301  const float weight = data->invert_vgroup ?
302  1.0f - BKE_defvert_find_weight(dvert, data->defgrp_index) :
303  BKE_defvert_find_weight(dvert, data->defgrp_index);
304  if (weight > 0.0f) {
306  data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
307  }
308  }
309  else {
311  data->lattice_deform_data, data->vert_coords[index], data->fac);
312  }
313 }
314 
315 static void lattice_deform_vert_task(void *__restrict userdata,
316  const int index,
317  const TaskParallelTLS *__restrict UNUSED(tls))
318 {
319  const LatticeDeformUserdata *data = userdata;
320  lattice_deform_vert_with_dvert(data, index, data->dvert ? &data->dvert[index] : NULL);
321 }
322 
323 static void lattice_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter)
324 {
325  const LatticeDeformUserdata *data = userdata;
326  BMVert *v = (BMVert *)iter;
327  MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset);
329 }
330 
331 static void lattice_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter)
332 {
333  const LatticeDeformUserdata *data = userdata;
334  BMVert *v = (BMVert *)iter;
336 }
337 
338 static void lattice_deform_coords_impl(const Object *ob_lattice,
339  const Object *ob_target,
340  float (*vert_coords)[3],
341  const int vert_coords_len,
342  const short flag,
343  const char *defgrp_name,
344  const float fac,
345  const Mesh *me_target,
346  BMEditMesh *em_target)
347 {
348  LatticeDeformData *lattice_deform_data;
349  const MDeformVert *dvert = NULL;
350  int defgrp_index = -1;
351  int cd_dvert_offset = -1;
352 
353  if (ob_lattice->type != OB_LATTICE) {
354  return;
355  }
356 
357  lattice_deform_data = BKE_lattice_deform_data_create(ob_lattice, ob_target);
358 
359  /* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
360  * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
361  */
362  if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
363  defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name);
364 
365  if (defgrp_index != -1) {
366  /* if there's derived data without deformverts, don't use vgroups */
367  if (em_target) {
368  cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
369  }
370  else if (me_target) {
371  dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT);
372  }
373  else if (ob_target->type == OB_LATTICE) {
374  dvert = ((Lattice *)ob_target->data)->dvert;
375  }
376  else {
377  dvert = ((Mesh *)ob_target->data)->dvert;
378  }
379  }
380  }
381 
383  .lattice_deform_data = lattice_deform_data,
384  .vert_coords = vert_coords,
385  .dvert = dvert,
386  .defgrp_index = defgrp_index,
387  .fac = fac,
388  .invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
389  .bmesh =
390  {
391  .cd_dvert_offset = cd_dvert_offset,
392  },
393  };
394 
395  if (em_target != NULL) {
396  /* While this could cause an extra loop over mesh data, in most cases this will
397  * have already been properly set. */
398  BM_mesh_elem_index_ensure(em_target->bm, BM_VERT);
399 
400  if (cd_dvert_offset != -1) {
402  }
403  else {
405  em_target->bm->vpool, &data, lattice_vert_task_editmesh_no_dvert, true);
406  }
407  }
408  else {
409  TaskParallelSettings settings;
411  settings.min_iter_per_thread = 32;
412  BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
413  }
414 
415  BKE_lattice_deform_data_destroy(lattice_deform_data);
416 }
417 
418 void BKE_lattice_deform_coords(const Object *ob_lattice,
419  const Object *ob_target,
420  float (*vert_coords)[3],
421  const int vert_coords_len,
422  const short flag,
423  const char *defgrp_name,
424  float fac)
425 {
427  ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL, NULL);
428 }
429 
431  const Object *ob_target,
432  float (*vert_coords)[3],
433  const int vert_coords_len,
434  const short flag,
435  const char *defgrp_name,
436  const float fac,
437  const Mesh *me_target)
438 {
439  lattice_deform_coords_impl(ob_lattice,
440  ob_target,
441  vert_coords,
442  vert_coords_len,
443  flag,
444  defgrp_name,
445  fac,
446  me_target,
447  NULL);
448 }
449 
450 void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
451  const struct Object *ob_target,
452  float (*vert_coords)[3],
453  const int vert_coords_len,
454  const short flag,
455  const char *defgrp_name,
456  const float fac,
457  struct BMEditMesh *em_target)
458 {
459  lattice_deform_coords_impl(ob_lattice,
460  ob_target,
461  vert_coords,
462  vert_coords_len,
463  flag,
464  defgrp_name,
465  fac,
466  NULL,
467  em_target);
468 }
469 
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.
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
display list (or rather multi purpose list) stuff.
DispList * BKE_displist_find(struct ListBase *lb, int type)
Definition: displist.c:105
@ DL_VERTS
Definition: BKE_displist.h:47
void key_curve_position_weights(float t, float data[4], int type)
Definition: key.c:348
struct MDeformVert * BKE_lattice_deform_verts_get(const struct Object *oblatt)
Definition: lattice.c:599
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:58
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
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 BLI_task_parallel_range(const int start, const int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:110
struct MempoolIterData MempoolIterData
Definition: BLI_task.h:223
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:231
void BLI_task_parallel_mempool(struct BLI_mempool *mempool, void *userdata, TaskParallelMempoolFunc func, const bool use_threading)
#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:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
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_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter)
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)
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(void *__restrict userdata, MempoolIterData *iter)
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:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
signed int int32_t
Definition: stdint.h:80
struct BMesh * bm
Definition: BKE_editmesh.h:52
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:49
float * verts
Definition: BKE_displist.h:74
const Lattice * lt
float latmat[4][4]
const MDeformVert * dvert
LatticeDeformData * lattice_deform_data
struct LatticeDeformUserdata::@92 bmesh
char vgroup[64]
struct BPoint * def
struct CurveCache * curve_cache
Object_Runtime runtime
float obmat[4][4]
void * data
ccl_device_inline float2 floor(const float2 &a)