Blender  V3.3
curve_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 "BLI_math.h"
16 #include "BLI_utildefines.h"
17 
18 #include "DNA_curve_types.h"
19 #include "DNA_meshdata_types.h"
20 #include "DNA_object_types.h"
21 
22 #include "BKE_anim_path.h"
23 #include "BKE_curve.h"
24 #include "BKE_editmesh.h"
25 #include "BKE_lattice.h"
26 #include "BKE_modifier.h"
27 
28 #include "BKE_deform.h"
29 
30 /* -------------------------------------------------------------------- */
38 typedef struct {
39  float dmin[3], dmax[3];
40  float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
42 } CurveDeform;
43 
44 static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd)
45 {
46  float imat[4][4];
47  invert_m4_m4(imat, ob_target->obmat);
48  mul_m4_m4m4(cd->objectspace, imat, ob_curve->obmat);
51  cd->no_rot_axis = 0;
52 }
53 
61 static bool calc_curve_deform(
62  const Object *ob_curve, float co[3], const short axis, const CurveDeform *cd, float r_quat[4])
63 {
64  Curve *cu = ob_curve->data;
65  float fac, loc[4], dir[3], new_quat[4], radius;
66  short index;
67  const bool is_neg_axis = (axis > 2);
68 
69  if (ob_curve->runtime.curve_cache == NULL) {
70  /* Happens with a cyclic dependencies. */
71  return false;
72  }
73 
74  if (ob_curve->runtime.curve_cache->anim_path_accum_length == NULL) {
75  return false; /* happens on append, cyclic dependencies and empty curves */
76  }
77 
78  /* options */
79  if (is_neg_axis) {
80  index = axis - 3;
81  if (cu->flag & CU_STRETCH) {
82  const float divisor = cd->dmax[index] - cd->dmin[index];
83  if (LIKELY(divisor > FLT_EPSILON)) {
84  fac = -(co[index] - cd->dmax[index]) / divisor;
85  }
86  else {
87  fac = 0.0f;
88  }
89  }
90  else {
91  CurveCache *cc = ob_curve->runtime.curve_cache;
92  float totdist = BKE_anim_path_get_length(cc);
93  if (LIKELY(totdist > FLT_EPSILON)) {
94  fac = -(co[index] - cd->dmax[index]) / totdist;
95  }
96  else {
97  fac = 0.0f;
98  }
99  }
100  }
101  else {
102  index = axis;
103  if (cu->flag & CU_STRETCH) {
104  const float divisor = cd->dmax[index] - cd->dmin[index];
105  if (LIKELY(divisor > FLT_EPSILON)) {
106  fac = (co[index] - cd->dmin[index]) / divisor;
107  }
108  else {
109  fac = 0.0f;
110  }
111  }
112  else {
113  CurveCache *cc = ob_curve->runtime.curve_cache;
114  float totdist = BKE_anim_path_get_length(cc);
115  if (LIKELY(totdist > FLT_EPSILON)) {
116  fac = +(co[index] - cd->dmin[index]) / totdist;
117  }
118  else {
119  fac = 0.0f;
120  }
121  }
122  }
123 
124  if (BKE_where_on_path(ob_curve, fac, loc, dir, new_quat, &radius, NULL)) { /* returns OK */
125  float quat[4], cent[3];
126 
127  if (cd->no_rot_axis) { /* set by caller */
128 
129  /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather
130  * than changing the axis before calculating the tilt but serves much the same purpose. */
131  float dir_flat[3] = {0, 0, 0}, q[4];
132  copy_v3_v3(dir_flat, dir);
133  dir_flat[cd->no_rot_axis - 1] = 0.0f;
134 
135  normalize_v3(dir);
136  normalize_v3(dir_flat);
137 
138  rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
139 
140  mul_qt_qtqt(new_quat, q, new_quat);
141  }
142 
143  /* Logic for 'cent' orientation *
144  *
145  * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
146  *
147  * Use a curve modifier to stretch a cube out, color each side RGB,
148  * positive side light, negative dark.
149  * view with X up (default), from the angle that you can see 3 faces RGB colors (light),
150  * anti-clockwise
151  * Notice X,Y,Z Up all have light colors and each ordered CCW.
152  *
153  * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
154  *
155  * NOTE: moved functions into quat_apply_track/vec_apply_track
156  */
157  copy_qt_qt(quat, new_quat);
158  copy_v3_v3(cent, co);
159 
160  /* Zero the axis which is not used,
161  * the big block of text above now applies to these 3 lines.
162  * The `upflag` argument may be a dummy, set so no rotation is done. */
163  quat_apply_track(quat, axis, (ELEM(axis, 0, 2)) ? 1 : 0);
164  vec_apply_track(cent, axis);
165  cent[index] = 0.0f;
166 
167  /* scale if enabled */
168  if (cu->flag & CU_PATH_RADIUS) {
169  mul_v3_fl(cent, radius);
170  }
171 
172  /* local rotation */
173  normalize_qt(quat);
174  mul_qt_v3(quat, cent);
175 
176  /* translation */
177  add_v3_v3v3(co, cent, loc);
178 
179  if (r_quat) {
180  copy_qt_qt(r_quat, quat);
181  }
182 
183  return true;
184  }
185  return false;
186 }
187 
190 /* -------------------------------------------------------------------- */
196 static void curve_deform_coords_impl(const Object *ob_curve,
197  const Object *ob_target,
198  float (*vert_coords)[3],
199  const int vert_coords_len,
200  const MDeformVert *dvert,
201  const int defgrp_index,
202  const short flag,
203  const short defaxis,
204  BMEditMesh *em_target)
205 {
206  Curve *cu;
207  int a;
208  CurveDeform cd;
209  const bool is_neg_axis = (defaxis > 2);
210  const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0;
211  bool use_dverts = false;
212  int cd_dvert_offset;
213 
214  if (ob_curve->type != OB_CURVES_LEGACY) {
215  return;
216  }
217 
218  cu = ob_curve->data;
219 
220  init_curve_deform(ob_curve, ob_target, &cd);
221 
222  if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
223  /* Dummy bounds. */
224  if (is_neg_axis == false) {
225  cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
226  cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
227  }
228  else {
229  /* Negative, these bounds give a good rest position. */
230  cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
231  cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
232  }
233  }
234  else {
235  /* Set mesh min/max bounds. */
236  INIT_MINMAX(cd.dmin, cd.dmax);
237  }
238 
239  if (em_target != NULL) {
240  cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
241  if (cd_dvert_offset != -1) {
242  use_dverts = true;
243  }
244  }
245  else {
246  if (dvert != NULL) {
247  use_dverts = true;
248  }
249  }
250 
251  if (use_dverts) {
252  if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
253 
254 #define DEFORM_OP(dvert) \
255  { \
256  const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
257  BKE_defvert_find_weight(dvert, defgrp_index); \
258  if (weight > 0.0f) { \
259  float vec[3]; \
260  mul_m4_v3(cd.curvespace, vert_coords[a]); \
261  copy_v3_v3(vec, vert_coords[a]); \
262  calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \
263  interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \
264  mul_m4_v3(cd.objectspace, vert_coords[a]); \
265  } \
266  } \
267  ((void)0)
268 
269  if (em_target != NULL) {
270  BMIter iter;
271  BMVert *v;
272  BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
273  dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
274  DEFORM_OP(dvert);
275  }
276  }
277  else {
278  for (a = 0; a < vert_coords_len; a++) {
279  DEFORM_OP(&dvert[a]);
280  }
281  }
282 
283 #undef DEFORM_OP
284  }
285  else {
286 
287 #define DEFORM_OP_MINMAX(dvert) \
288  { \
289  const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
290  BKE_defvert_find_weight(dvert, defgrp_index); \
291  if (weight > 0.0f) { \
292  mul_m4_v3(cd.curvespace, vert_coords[a]); \
293  minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]); \
294  } \
295  } \
296  ((void)0)
297 
298  /* Already in 'cd.curvespace', previous for loop. */
299 #define DEFORM_OP_CLAMPED(dvert) \
300  { \
301  const float weight = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dvert, defgrp_index) : \
302  BKE_defvert_find_weight(dvert, defgrp_index); \
303  if (weight > 0.0f) { \
304  float vec[3]; \
305  copy_v3_v3(vec, vert_coords[a]); \
306  calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL); \
307  interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight); \
308  mul_m4_v3(cd.objectspace, vert_coords[a]); \
309  } \
310  } \
311  ((void)0)
312 
313  if (em_target != NULL) {
314  BMIter iter;
315  BMVert *v;
316  BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
317  dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
318  DEFORM_OP_MINMAX(dvert);
319  }
320 
321  BM_ITER_MESH_INDEX (v, &iter, em_target->bm, BM_VERTS_OF_MESH, a) {
322  dvert = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
323  DEFORM_OP_CLAMPED(dvert);
324  }
325  }
326  else {
327 
328  for (a = 0; a < vert_coords_len; a++) {
329  DEFORM_OP_MINMAX(&dvert[a]);
330  }
331 
332  for (a = 0; a < vert_coords_len; a++) {
333  DEFORM_OP_CLAMPED(&dvert[a]);
334  }
335  }
336  }
337 
338 #undef DEFORM_OP_MINMAX
339 #undef DEFORM_OP_CLAMPED
340  }
341  else {
342  if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
343  for (a = 0; a < vert_coords_len; a++) {
344  mul_m4_v3(cd.curvespace, vert_coords[a]);
345  calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
346  mul_m4_v3(cd.objectspace, vert_coords[a]);
347  }
348  }
349  else {
350  for (a = 0; a < vert_coords_len; a++) {
351  mul_m4_v3(cd.curvespace, vert_coords[a]);
352  minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
353  }
354 
355  for (a = 0; a < vert_coords_len; a++) {
356  /* Already in 'cd.curvespace', previous for loop. */
357  calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
358  mul_m4_v3(cd.objectspace, vert_coords[a]);
359  }
360  }
361  }
362 }
363 
364 void BKE_curve_deform_coords(const Object *ob_curve,
365  const Object *ob_target,
366  float (*vert_coords)[3],
367  const int vert_coords_len,
368  const MDeformVert *dvert,
369  const int defgrp_index,
370  const short flag,
371  const short defaxis)
372 {
374  ob_curve, ob_target, vert_coords, vert_coords_len, dvert, defgrp_index, flag, defaxis, NULL);
375 }
376 
378  const Object *ob_target,
379  float (*vert_coords)[3],
380  const int vert_coords_len,
381  const int defgrp_index,
382  const short flag,
383  const short defaxis,
384  BMEditMesh *em_target)
385 {
386  curve_deform_coords_impl(ob_curve,
387  ob_target,
388  vert_coords,
389  vert_coords_len,
390  NULL,
391  defgrp_index,
392  flag,
393  defaxis,
394  em_target);
395 }
396 
397 void BKE_curve_deform_co(const Object *ob_curve,
398  const Object *ob_target,
399  const float orco[3],
400  float vec[3],
401  const int no_rot_axis,
402  float r_mat[3][3])
403 {
404  CurveDeform cd;
405  float quat[4];
406 
407  if (ob_curve->type != OB_CURVES_LEGACY) {
408  unit_m3(r_mat);
409  return;
410  }
411 
412  init_curve_deform(ob_curve, ob_target, &cd);
413  cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
414 
415  copy_v3_v3(cd.dmin, orco);
416  copy_v3_v3(cd.dmax, orco);
417 
418  mul_m4_v3(cd.curvespace, vec);
419 
420  if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) {
421  float qmat[3][3];
422 
423  quat_to_mat3(qmat, quat);
424  mul_m3_m3m3(r_mat, qmat, cd.objectspace3);
425  }
426  else {
427  unit_m3(r_mat);
428  }
429 
430  mul_m4_v3(cd.objectspace, vec);
431 }
432 
bool BKE_where_on_path(const struct Object *ob, float ctime, float r_vec[4], float r_dir[3], float r_quat[4], float *r_radius, float *r_weight)
float BKE_anim_path_get_length(const struct CurveCache *curve_cache)
int CustomData_get_offset(const struct CustomData *data, int type)
support for deformation groups and hooks.
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void unit_m3(float m[3][3])
Definition: math_matrix.c:40
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:388
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
void vec_apply_track(float vec[3], short axis)
float normalize_qt(float q[4])
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:59
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:46
void quat_apply_track(float quat[4], short axis, short upflag)
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:33
void quat_to_mat3(float mat[3][3], const float q[4])
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
#define INIT_MINMAX(min, max)
#define ELEM(...)
#define LIKELY(x)
@ CU_STRETCH
@ CU_PATH_RADIUS
@ CU_DEFORM_BOUNDS_OFF
@ CD_MDEFORMVERT
@ MOD_CURVE_INVERT_VGROUP
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
ATTR_WARN_UNUSED_RESULT const BMVert * v
static void init_curve_deform(const Object *ob_curve, const Object *ob_target, CurveDeform *cd)
Definition: curve_deform.c:44
void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const int defgrp_index, const short flag, const short defaxis, BMEditMesh *em_target)
Definition: curve_deform.c:377
#define DEFORM_OP_MINMAX(dvert)
void BKE_curve_deform_coords(const Object *ob_curve, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const MDeformVert *dvert, const int defgrp_index, const short flag, const short defaxis)
Definition: curve_deform.c:364
static void curve_deform_coords_impl(const Object *ob_curve, const Object *ob_target, float(*vert_coords)[3], const int vert_coords_len, const MDeformVert *dvert, const int defgrp_index, const short flag, const short defaxis, BMEditMesh *em_target)
Definition: curve_deform.c:196
static bool calc_curve_deform(const Object *ob_curve, float co[3], const short axis, const CurveDeform *cd, float r_quat[4])
Definition: curve_deform.c:61
void BKE_curve_deform_co(const Object *ob_curve, const Object *ob_target, const float orco[3], float vec[3], const int no_rot_axis, float r_mat[3][3])
Definition: curve_deform.c:397
#define DEFORM_OP(dvert)
#define DEFORM_OP_CLAMPED(dvert)
static unsigned a[3]
Definition: RandGen.cpp:78
struct BMesh * bm
Definition: BKE_editmesh.h:40
CustomData vdata
Definition: bmesh_class.h:337
const float * anim_path_accum_length
Definition: BKE_curve.h:42
float objectspace[4][4]
Definition: curve_deform.c:40
float dmin[3]
Definition: curve_deform.c:39
float dmax[3]
Definition: curve_deform.c:39
float curvespace[4][4]
Definition: curve_deform.c:40
float objectspace3[3][3]
Definition: curve_deform.c:40
struct CurveCache * curve_cache
Object_Runtime runtime
float obmat[4][4]
short trackflag
void * data