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