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