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