Cleanup: split object data deform functions into their own files
Move armature/curve functions into their headers, they were previously in BKE_lattice.h
This commit is contained in:
@@ -32,11 +32,13 @@ struct Bone;
|
||||
struct Depsgraph;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
struct PoseTree;
|
||||
struct Scene;
|
||||
struct bArmature;
|
||||
struct bConstraint;
|
||||
struct bGPDstroke;
|
||||
struct bPose;
|
||||
struct bPoseChannel;
|
||||
|
||||
@@ -342,6 +344,35 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph,
|
||||
struct Object *object,
|
||||
int pchan_index);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deform 3D Coordinates by Armature (armature_deform.c)
|
||||
* \{ */
|
||||
|
||||
/* Note that we could have a 'BKE_armature_deform_coords' that doesn't take object data
|
||||
* currently there are no callers for this though. */
|
||||
|
||||
void BKE_armature_deform_coords_with_gpencil_stroke(struct Object *ob_arm,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
struct bGPDstroke *gps_target);
|
||||
|
||||
void BKE_armature_deform_coords_with_mesh(struct Object *ob_arm,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const struct Mesh *me_target);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,7 @@ struct Curve;
|
||||
struct Depsgraph;
|
||||
struct GHash;
|
||||
struct ListBase;
|
||||
struct MDeformVert;
|
||||
struct Main;
|
||||
struct Nurb;
|
||||
struct Object;
|
||||
@@ -278,7 +279,15 @@ enum {
|
||||
void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode);
|
||||
void BKE_curve_batch_cache_free(struct Curve *cu);
|
||||
|
||||
/* curve_decimate.c */
|
||||
extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode);
|
||||
extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Decimate Curve (curve_decimate.c)
|
||||
*
|
||||
* Simplify curve data.
|
||||
* \{ */
|
||||
|
||||
unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array,
|
||||
const unsigned int bezt_array_len,
|
||||
const unsigned int resolu,
|
||||
@@ -293,8 +302,28 @@ void BKE_curve_decimate_nurb(struct Nurb *nu,
|
||||
const float error_sq_max,
|
||||
const unsigned int error_target_len);
|
||||
|
||||
extern void (*BKE_curve_batch_cache_dirty_tag_cb)(struct Curve *cu, int mode);
|
||||
extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu);
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deform 3D Coordinates by Curve (curve_deform.c)
|
||||
* \{ */
|
||||
|
||||
void BKE_curve_deform_coords(struct Object *ob_curve,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const struct MDeformVert *dvert,
|
||||
const int defgrp_index,
|
||||
const short flag,
|
||||
const short defaxis);
|
||||
void BKE_curve_deform_co(struct Object *ob_curve,
|
||||
struct Object *ob_target,
|
||||
const float orco[3],
|
||||
float vec[3],
|
||||
float mat[3][3],
|
||||
const int no_rot_axis);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -45,77 +45,9 @@ struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
|
||||
struct Lattice *BKE_lattice_copy(struct Main *bmain, const struct Lattice *lt);
|
||||
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
|
||||
|
||||
struct LatticeDeformData *init_latt_deform(struct Object *oblatt,
|
||||
struct Object *ob) ATTR_WARN_UNUSED_RESULT;
|
||||
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
|
||||
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
|
||||
|
||||
bool object_deform_mball(struct Object *ob, struct ListBase *dispbase);
|
||||
void outside_lattice(struct Lattice *lt);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deform 3D Coordinates by Object Data
|
||||
*
|
||||
* Used by modifiers (odd location for this API, for now keep these related functions together).
|
||||
* \{ */
|
||||
|
||||
void BKE_curve_deform_coords(struct Object *ob_curve,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const struct MDeformVert *dvert,
|
||||
const int defgrp_index,
|
||||
const short flag,
|
||||
const short defaxis);
|
||||
void BKE_curve_deform_co(struct Object *ob_curve,
|
||||
struct Object *ob_target,
|
||||
const float orco[3],
|
||||
float vec[3],
|
||||
float mat[3][3],
|
||||
const int no_rot_axis);
|
||||
|
||||
void BKE_lattice_deform_coords(struct Object *ob_lattice,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const short flag,
|
||||
const char *defgrp_name,
|
||||
float influence);
|
||||
|
||||
void BKE_lattice_deform_coords_with_mesh(struct Object *ob_lattice,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const short flag,
|
||||
const char *defgrp_name,
|
||||
const float influence,
|
||||
const struct Mesh *me_target);
|
||||
|
||||
/* Note that we could have a 'BKE_armature_deform_coords' that doesn't take object data
|
||||
* currently there are no callers for this though. */
|
||||
|
||||
void BKE_armature_deform_coords_with_gpencil_stroke(struct Object *ob_arm,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
struct bGPDstroke *gps_target);
|
||||
|
||||
void BKE_armature_deform_coords_with_mesh(struct Object *ob_arm,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const struct Mesh *me_target);
|
||||
|
||||
/** \} */
|
||||
|
||||
float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3];
|
||||
void BKE_lattice_vert_coords_get(const struct Lattice *lt, float (*vert_coords)[3]);
|
||||
void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt,
|
||||
@@ -166,6 +98,33 @@ void BKE_lattice_batch_cache_free(struct Lattice *lt);
|
||||
extern void (*BKE_lattice_batch_cache_dirty_tag_cb)(struct Lattice *lt, int mode);
|
||||
extern void (*BKE_lattice_batch_cache_free_cb)(struct Lattice *lt);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deform 3D Coordinates by Lattice (lattice_deform.c)
|
||||
* \{ */
|
||||
|
||||
struct LatticeDeformData *init_latt_deform(struct Object *oblatt,
|
||||
struct Object *ob) ATTR_WARN_UNUSED_RESULT;
|
||||
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
|
||||
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
|
||||
|
||||
void BKE_lattice_deform_coords(struct Object *ob_lattice,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const short flag,
|
||||
const char *defgrp_name,
|
||||
float influence);
|
||||
|
||||
void BKE_lattice_deform_coords_with_mesh(struct Object *ob_lattice,
|
||||
struct Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
const int vert_coords_len,
|
||||
const short flag,
|
||||
const char *defgrp_name,
|
||||
const float influence,
|
||||
const struct Mesh *me_target);
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -74,6 +74,7 @@ set(SRC
|
||||
intern/anim_visualization.c
|
||||
intern/appdir.c
|
||||
intern/armature.c
|
||||
intern/armature_deform.c
|
||||
intern/armature_update.c
|
||||
intern/autoexec.c
|
||||
intern/blender.c
|
||||
@@ -99,6 +100,7 @@ set(SRC
|
||||
intern/crazyspace.c
|
||||
intern/curve.c
|
||||
intern/curve_decimate.c
|
||||
intern/curve_deform.c
|
||||
intern/curveprofile.c
|
||||
intern/customdata.c
|
||||
intern/customdata_file.c
|
||||
@@ -138,6 +140,7 @@ set(SRC
|
||||
intern/key.c
|
||||
intern/keyconfig.c
|
||||
intern/lattice.c
|
||||
intern/lattice_deform.c
|
||||
intern/layer.c
|
||||
intern/layer_utils.c
|
||||
intern/lib_id.c
|
||||
|
||||
@@ -35,18 +35,12 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
@@ -55,11 +49,8 @@
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_displist.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_main.h"
|
||||
@@ -71,8 +62,6 @@
|
||||
|
||||
#include "BIK_api.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"bke.armature"};
|
||||
@@ -1385,557 +1374,6 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Armature Deform Internal Utilities
|
||||
* \{ */
|
||||
|
||||
/* Add the effect of one bone or B-Bone segment to the accumulated result. */
|
||||
static void pchan_deform_accumulate(const DualQuat *deform_dq,
|
||||
const float deform_mat[4][4],
|
||||
const float co_in[3],
|
||||
float weight,
|
||||
float co_accum[3],
|
||||
DualQuat *dq_accum,
|
||||
float mat_accum[3][3])
|
||||
{
|
||||
if (weight == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dq_accum) {
|
||||
BLI_assert(!co_accum);
|
||||
|
||||
add_weighted_dq_dq(dq_accum, deform_dq, weight);
|
||||
}
|
||||
else {
|
||||
float tmp[3];
|
||||
mul_v3_m4v3(tmp, deform_mat, co_in);
|
||||
|
||||
sub_v3_v3(tmp, co_in);
|
||||
madd_v3_v3fl(co_accum, tmp, weight);
|
||||
|
||||
if (mat_accum) {
|
||||
float tmpmat[3][3];
|
||||
copy_m3_m4(tmpmat, deform_mat);
|
||||
|
||||
madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void b_bone_deform(const bPoseChannel *pchan,
|
||||
const float co[3],
|
||||
float weight,
|
||||
float vec[3],
|
||||
DualQuat *dq,
|
||||
float defmat[3][3])
|
||||
{
|
||||
const DualQuat *quats = pchan->runtime.bbone_dual_quats;
|
||||
const Mat4 *mats = pchan->runtime.bbone_deform_mats;
|
||||
const float(*mat)[4] = mats[0].mat;
|
||||
float blend, y;
|
||||
int index;
|
||||
|
||||
/* Transform co to bone space and get its y component. */
|
||||
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
|
||||
|
||||
/* Calculate the indices of the 2 affecting b_bone segments. */
|
||||
BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend);
|
||||
|
||||
pchan_deform_accumulate(
|
||||
&quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat);
|
||||
pchan_deform_accumulate(
|
||||
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
|
||||
}
|
||||
|
||||
/* using vec with dist to bone b1 - b2 */
|
||||
float distfactor_to_bone(
|
||||
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
|
||||
{
|
||||
float dist_sq;
|
||||
float bdelta[3];
|
||||
float pdelta[3];
|
||||
float hsqr, a, l, rad;
|
||||
|
||||
sub_v3_v3v3(bdelta, b2, b1);
|
||||
l = normalize_v3(bdelta);
|
||||
|
||||
sub_v3_v3v3(pdelta, vec, b1);
|
||||
|
||||
a = dot_v3v3(bdelta, pdelta);
|
||||
hsqr = len_squared_v3(pdelta);
|
||||
|
||||
if (a < 0.0f) {
|
||||
/* If we're past the end of the bone, do a spherical field attenuation thing */
|
||||
dist_sq = len_squared_v3v3(b1, vec);
|
||||
rad = rad1;
|
||||
}
|
||||
else if (a > l) {
|
||||
/* If we're past the end of the bone, do a spherical field attenuation thing */
|
||||
dist_sq = len_squared_v3v3(b2, vec);
|
||||
rad = rad2;
|
||||
}
|
||||
else {
|
||||
dist_sq = (hsqr - (a * a));
|
||||
|
||||
if (l != 0.0f) {
|
||||
rad = a / l;
|
||||
rad = rad * rad2 + (1.0f - rad) * rad1;
|
||||
}
|
||||
else {
|
||||
rad = rad1;
|
||||
}
|
||||
}
|
||||
|
||||
a = rad * rad;
|
||||
if (dist_sq < a) {
|
||||
return 1.0f;
|
||||
}
|
||||
else {
|
||||
l = rad + rdist;
|
||||
l *= l;
|
||||
if (rdist == 0.0f || dist_sq >= l) {
|
||||
return 0.0f;
|
||||
}
|
||||
else {
|
||||
a = sqrtf(dist_sq) - rad;
|
||||
return 1.0f - (a * a) / (rdist * rdist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float dist_bone_deform(
|
||||
bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3])
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
float fac, contrib = 0.0;
|
||||
|
||||
if (bone == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
fac = distfactor_to_bone(
|
||||
co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
|
||||
|
||||
if (fac > 0.0f) {
|
||||
fac *= bone->weight;
|
||||
contrib = fac;
|
||||
if (contrib > 0.0f) {
|
||||
if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
|
||||
b_bone_deform(pchan, co, fac, vec, dq, mat);
|
||||
}
|
||||
else {
|
||||
pchan_deform_accumulate(
|
||||
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return contrib;
|
||||
}
|
||||
|
||||
static void pchan_bone_deform(bPoseChannel *pchan,
|
||||
float weight,
|
||||
float vec[3],
|
||||
DualQuat *dq,
|
||||
float mat[3][3],
|
||||
const float co[3],
|
||||
float *contrib)
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
|
||||
if (!weight) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
|
||||
b_bone_deform(pchan, co, weight, vec, dq, mat);
|
||||
}
|
||||
else {
|
||||
pchan_deform_accumulate(
|
||||
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat);
|
||||
}
|
||||
|
||||
(*contrib) += weight;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Armature Deform #BKE_armature_deform_coords API
|
||||
*
|
||||
* #BKE_armature_deform_coords and related functions.
|
||||
* \{ */
|
||||
|
||||
typedef struct ArmatureUserdata {
|
||||
Object *ob_arm;
|
||||
Object *ob_target;
|
||||
const Mesh *me_target;
|
||||
float (*vert_coords)[3];
|
||||
float (*vert_deform_mats)[3][3];
|
||||
float (*vert_coords_prev)[3];
|
||||
|
||||
bool use_envelope;
|
||||
bool use_quaternion;
|
||||
bool invert_vgroup;
|
||||
bool use_dverts;
|
||||
|
||||
int armature_def_nr;
|
||||
|
||||
const MDeformVert *dverts;
|
||||
int dverts_len;
|
||||
|
||||
bPoseChannel **pchan_from_defbase;
|
||||
int defbase_len;
|
||||
|
||||
float premat[4][4];
|
||||
float postmat[4][4];
|
||||
} ArmatureUserdata;
|
||||
|
||||
static void armature_vert_task(void *__restrict userdata,
|
||||
const int i,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const ArmatureUserdata *data = userdata;
|
||||
float(*const vert_coords)[3] = data->vert_coords;
|
||||
float(*const vert_deform_mats)[3][3] = data->vert_deform_mats;
|
||||
float(*const vert_coords_prev)[3] = data->vert_coords_prev;
|
||||
const bool use_envelope = data->use_envelope;
|
||||
const bool use_quaternion = data->use_quaternion;
|
||||
const bool use_dverts = data->use_dverts;
|
||||
const int armature_def_nr = data->armature_def_nr;
|
||||
|
||||
const MDeformVert *dvert;
|
||||
DualQuat sumdq, *dq = NULL;
|
||||
bPoseChannel *pchan;
|
||||
float *co, dco[3];
|
||||
float sumvec[3], summat[3][3];
|
||||
float *vec = NULL, (*smat)[3] = NULL;
|
||||
float contrib = 0.0f;
|
||||
float armature_weight = 1.0f; /* default to 1 if no overall def group */
|
||||
float prevco_weight = 1.0f; /* weight for optional cached vertexcos */
|
||||
|
||||
if (use_quaternion) {
|
||||
memset(&sumdq, 0, sizeof(DualQuat));
|
||||
dq = &sumdq;
|
||||
}
|
||||
else {
|
||||
zero_v3(sumvec);
|
||||
vec = sumvec;
|
||||
|
||||
if (vert_deform_mats) {
|
||||
zero_m3(summat);
|
||||
smat = summat;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_dverts || armature_def_nr != -1) {
|
||||
if (data->me_target) {
|
||||
BLI_assert(i < data->me_target->totvert);
|
||||
if (data->me_target->dvert != NULL) {
|
||||
dvert = data->me_target->dvert + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else if (data->dverts && i < data->dverts_len) {
|
||||
dvert = data->dverts + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
|
||||
if (armature_def_nr != -1 && dvert) {
|
||||
armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr);
|
||||
|
||||
if (data->invert_vgroup) {
|
||||
armature_weight = 1.0f - armature_weight;
|
||||
}
|
||||
|
||||
/* hackish: the blending factor can be used for blending with vert_coords_prev too */
|
||||
if (vert_coords_prev) {
|
||||
prevco_weight = armature_weight;
|
||||
armature_weight = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if there's any point in calculating for this vert */
|
||||
if (armature_weight == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the coord we work on */
|
||||
co = vert_coords_prev ? vert_coords_prev[i] : vert_coords[i];
|
||||
|
||||
/* Apply the object's matrix */
|
||||
mul_m4_v3(data->premat, co);
|
||||
|
||||
if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
|
||||
const MDeformWeight *dw = dvert->dw;
|
||||
int deformed = 0;
|
||||
unsigned int j;
|
||||
for (j = dvert->totweight; j != 0; j--, dw++) {
|
||||
const uint index = dw->def_nr;
|
||||
if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) {
|
||||
float weight = dw->weight;
|
||||
Bone *bone = pchan->bone;
|
||||
|
||||
deformed = 1;
|
||||
|
||||
if (bone && bone->flag & BONE_MULT_VG_ENV) {
|
||||
weight *= distfactor_to_bone(
|
||||
co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
|
||||
}
|
||||
|
||||
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
|
||||
}
|
||||
}
|
||||
/* if there are vertexgroups but not groups with bones
|
||||
* (like for softbody groups) */
|
||||
if (deformed == 0 && use_envelope) {
|
||||
for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
|
||||
contrib += dist_bone_deform(pchan, vec, dq, smat, co);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (use_envelope) {
|
||||
for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
|
||||
contrib += dist_bone_deform(pchan, vec, dq, smat, co);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
|
||||
if (contrib > 0.0001f) {
|
||||
if (use_quaternion) {
|
||||
normalize_dq(dq, contrib);
|
||||
|
||||
if (armature_weight != 1.0f) {
|
||||
copy_v3_v3(dco, co);
|
||||
mul_v3m3_dq(dco, (vert_deform_mats) ? summat : NULL, dq);
|
||||
sub_v3_v3(dco, co);
|
||||
mul_v3_fl(dco, armature_weight);
|
||||
add_v3_v3(co, dco);
|
||||
}
|
||||
else {
|
||||
mul_v3m3_dq(co, (vert_deform_mats) ? summat : NULL, dq);
|
||||
}
|
||||
|
||||
smat = summat;
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, armature_weight / contrib);
|
||||
add_v3_v3v3(co, vec, co);
|
||||
}
|
||||
|
||||
if (vert_deform_mats) {
|
||||
float pre[3][3], post[3][3], tmpmat[3][3];
|
||||
|
||||
copy_m3_m4(pre, data->premat);
|
||||
copy_m3_m4(post, data->postmat);
|
||||
copy_m3_m3(tmpmat, vert_deform_mats[i]);
|
||||
|
||||
if (!use_quaternion) { /* quaternion already is scale corrected */
|
||||
mul_m3_fl(smat, armature_weight / contrib);
|
||||
}
|
||||
|
||||
mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat);
|
||||
}
|
||||
}
|
||||
|
||||
/* always, check above code */
|
||||
mul_m4_v3(data->postmat, co);
|
||||
|
||||
/* interpolate with previous modifier position using weight group */
|
||||
if (vert_coords_prev) {
|
||||
float mw = 1.0f - prevco_weight;
|
||||
vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0];
|
||||
vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1];
|
||||
vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void armature_deform_coords_impl(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
const int vert_coords_len,
|
||||
const int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const Mesh *me_target,
|
||||
bGPDstroke *gps_target)
|
||||
{
|
||||
bArmature *arm = ob_arm->data;
|
||||
bPoseChannel **pchan_from_defbase = NULL;
|
||||
const MDeformVert *dverts = NULL;
|
||||
bDeformGroup *dg;
|
||||
const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
|
||||
const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
|
||||
const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
|
||||
int defbase_len = 0; /* safety for vertexgroup index overflow */
|
||||
int i, dverts_len = 0; /* safety for vertexgroup overflow */
|
||||
bool use_dverts = false;
|
||||
int armature_def_nr;
|
||||
|
||||
/* in editmode, or not an armature */
|
||||
if (arm->edbo || (ob_arm->pose == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ob_arm->pose->flag & POSE_RECALC) != 0) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Trying to evaluate influence of armature '%s' which needs Pose recalc!",
|
||||
ob_arm->id.name);
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
/* get the def_nr for the overall armature vertex group if present */
|
||||
armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name);
|
||||
|
||||
if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
|
||||
defbase_len = BLI_listbase_count(&ob_target->defbase);
|
||||
|
||||
if (ob_target->type == OB_MESH) {
|
||||
Mesh *me = ob_target->data;
|
||||
dverts = me->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = me->totvert;
|
||||
}
|
||||
}
|
||||
else if (ob_target->type == OB_LATTICE) {
|
||||
Lattice *lt = ob_target->data;
|
||||
dverts = lt->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = lt->pntsu * lt->pntsv * lt->pntsw;
|
||||
}
|
||||
}
|
||||
else if (ob_target->type == OB_GPENCIL) {
|
||||
dverts = gps_target->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = gps_target->totpoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get a vertex-deform-index to posechannel array */
|
||||
if (deformflag & ARM_DEF_VGROUP) {
|
||||
if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
|
||||
/* if we have a Mesh, only use dverts if it has them */
|
||||
if (me_target) {
|
||||
use_dverts = (me_target->dvert != NULL);
|
||||
}
|
||||
else if (dverts) {
|
||||
use_dverts = true;
|
||||
}
|
||||
|
||||
if (use_dverts) {
|
||||
pchan_from_defbase = MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone");
|
||||
/* TODO(sergey): Some considerations here:
|
||||
*
|
||||
* - Check whether keeping this consistent across frames gives speedup.
|
||||
*/
|
||||
for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) {
|
||||
pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name);
|
||||
/* exclude non-deforming bones */
|
||||
if (pchan_from_defbase[i]) {
|
||||
if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) {
|
||||
pchan_from_defbase[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArmatureUserdata data = {
|
||||
.ob_arm = ob_arm,
|
||||
.ob_target = ob_target,
|
||||
.me_target = me_target,
|
||||
.vert_coords = vert_coords,
|
||||
.vert_deform_mats = vert_deform_mats,
|
||||
.vert_coords_prev = vert_coords_prev,
|
||||
.use_envelope = use_envelope,
|
||||
.use_quaternion = use_quaternion,
|
||||
.invert_vgroup = invert_vgroup,
|
||||
.use_dverts = use_dverts,
|
||||
.armature_def_nr = armature_def_nr,
|
||||
.dverts = dverts,
|
||||
.dverts_len = dverts_len,
|
||||
.pchan_from_defbase = pchan_from_defbase,
|
||||
.defbase_len = defbase_len,
|
||||
};
|
||||
|
||||
float obinv[4][4];
|
||||
invert_m4_m4(obinv, ob_target->obmat);
|
||||
|
||||
mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat);
|
||||
invert_m4_m4(data.premat, data.postmat);
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings);
|
||||
|
||||
if (pchan_from_defbase) {
|
||||
MEM_freeN(pchan_from_defbase);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_armature_deform_coords_with_gpencil_stroke(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
bGPDstroke *gps_target)
|
||||
{
|
||||
armature_deform_coords_impl(ob_arm,
|
||||
ob_target,
|
||||
vert_coords,
|
||||
vert_deform_mats,
|
||||
vert_coords_len,
|
||||
deformflag,
|
||||
vert_coords_prev,
|
||||
defgrp_name,
|
||||
NULL,
|
||||
gps_target);
|
||||
}
|
||||
|
||||
void BKE_armature_deform_coords_with_mesh(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const Mesh *me_target)
|
||||
{
|
||||
armature_deform_coords_impl(ob_arm,
|
||||
ob_target,
|
||||
vert_coords,
|
||||
vert_deform_mats,
|
||||
vert_coords_len,
|
||||
deformflag,
|
||||
vert_coords_prev,
|
||||
defgrp_name,
|
||||
me_target,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Bone Space to Space Conversion API
|
||||
* \{ */
|
||||
|
||||
608
source/blender/blenkernel/intern/armature_deform.c
Normal file
608
source/blender/blenkernel/intern/armature_deform.c
Normal file
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* Deform coordinates by a armature object (used by modifier).
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_lattice.h"
|
||||
|
||||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"bke.armature_deform"};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Armature Deform Internal Utilities
|
||||
* \{ */
|
||||
|
||||
/* Add the effect of one bone or B-Bone segment to the accumulated result. */
|
||||
static void pchan_deform_accumulate(const DualQuat *deform_dq,
|
||||
const float deform_mat[4][4],
|
||||
const float co_in[3],
|
||||
float weight,
|
||||
float co_accum[3],
|
||||
DualQuat *dq_accum,
|
||||
float mat_accum[3][3])
|
||||
{
|
||||
if (weight == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dq_accum) {
|
||||
BLI_assert(!co_accum);
|
||||
|
||||
add_weighted_dq_dq(dq_accum, deform_dq, weight);
|
||||
}
|
||||
else {
|
||||
float tmp[3];
|
||||
mul_v3_m4v3(tmp, deform_mat, co_in);
|
||||
|
||||
sub_v3_v3(tmp, co_in);
|
||||
madd_v3_v3fl(co_accum, tmp, weight);
|
||||
|
||||
if (mat_accum) {
|
||||
float tmpmat[3][3];
|
||||
copy_m3_m4(tmpmat, deform_mat);
|
||||
|
||||
madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void b_bone_deform(const bPoseChannel *pchan,
|
||||
const float co[3],
|
||||
float weight,
|
||||
float vec[3],
|
||||
DualQuat *dq,
|
||||
float defmat[3][3])
|
||||
{
|
||||
const DualQuat *quats = pchan->runtime.bbone_dual_quats;
|
||||
const Mat4 *mats = pchan->runtime.bbone_deform_mats;
|
||||
const float(*mat)[4] = mats[0].mat;
|
||||
float blend, y;
|
||||
int index;
|
||||
|
||||
/* Transform co to bone space and get its y component. */
|
||||
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
|
||||
|
||||
/* Calculate the indices of the 2 affecting b_bone segments. */
|
||||
BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend);
|
||||
|
||||
pchan_deform_accumulate(
|
||||
&quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat);
|
||||
pchan_deform_accumulate(
|
||||
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
|
||||
}
|
||||
|
||||
/* using vec with dist to bone b1 - b2 */
|
||||
float distfactor_to_bone(
|
||||
const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
|
||||
{
|
||||
float dist_sq;
|
||||
float bdelta[3];
|
||||
float pdelta[3];
|
||||
float hsqr, a, l, rad;
|
||||
|
||||
sub_v3_v3v3(bdelta, b2, b1);
|
||||
l = normalize_v3(bdelta);
|
||||
|
||||
sub_v3_v3v3(pdelta, vec, b1);
|
||||
|
||||
a = dot_v3v3(bdelta, pdelta);
|
||||
hsqr = len_squared_v3(pdelta);
|
||||
|
||||
if (a < 0.0f) {
|
||||
/* If we're past the end of the bone, do a spherical field attenuation thing */
|
||||
dist_sq = len_squared_v3v3(b1, vec);
|
||||
rad = rad1;
|
||||
}
|
||||
else if (a > l) {
|
||||
/* If we're past the end of the bone, do a spherical field attenuation thing */
|
||||
dist_sq = len_squared_v3v3(b2, vec);
|
||||
rad = rad2;
|
||||
}
|
||||
else {
|
||||
dist_sq = (hsqr - (a * a));
|
||||
|
||||
if (l != 0.0f) {
|
||||
rad = a / l;
|
||||
rad = rad * rad2 + (1.0f - rad) * rad1;
|
||||
}
|
||||
else {
|
||||
rad = rad1;
|
||||
}
|
||||
}
|
||||
|
||||
a = rad * rad;
|
||||
if (dist_sq < a) {
|
||||
return 1.0f;
|
||||
}
|
||||
else {
|
||||
l = rad + rdist;
|
||||
l *= l;
|
||||
if (rdist == 0.0f || dist_sq >= l) {
|
||||
return 0.0f;
|
||||
}
|
||||
else {
|
||||
a = sqrtf(dist_sq) - rad;
|
||||
return 1.0f - (a * a) / (rdist * rdist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float dist_bone_deform(
|
||||
bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3])
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
float fac, contrib = 0.0;
|
||||
|
||||
if (bone == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
fac = distfactor_to_bone(
|
||||
co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
|
||||
|
||||
if (fac > 0.0f) {
|
||||
fac *= bone->weight;
|
||||
contrib = fac;
|
||||
if (contrib > 0.0f) {
|
||||
if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
|
||||
b_bone_deform(pchan, co, fac, vec, dq, mat);
|
||||
}
|
||||
else {
|
||||
pchan_deform_accumulate(
|
||||
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return contrib;
|
||||
}
|
||||
|
||||
static void pchan_bone_deform(bPoseChannel *pchan,
|
||||
float weight,
|
||||
float vec[3],
|
||||
DualQuat *dq,
|
||||
float mat[3][3],
|
||||
const float co[3],
|
||||
float *contrib)
|
||||
{
|
||||
Bone *bone = pchan->bone;
|
||||
|
||||
if (!weight) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
|
||||
b_bone_deform(pchan, co, weight, vec, dq, mat);
|
||||
}
|
||||
else {
|
||||
pchan_deform_accumulate(
|
||||
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat);
|
||||
}
|
||||
|
||||
(*contrib) += weight;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Armature Deform #BKE_armature_deform_coords API
|
||||
*
|
||||
* #BKE_armature_deform_coords and related functions.
|
||||
* \{ */
|
||||
|
||||
typedef struct ArmatureUserdata {
|
||||
Object *ob_arm;
|
||||
Object *ob_target;
|
||||
const Mesh *me_target;
|
||||
float (*vert_coords)[3];
|
||||
float (*vert_deform_mats)[3][3];
|
||||
float (*vert_coords_prev)[3];
|
||||
|
||||
bool use_envelope;
|
||||
bool use_quaternion;
|
||||
bool invert_vgroup;
|
||||
bool use_dverts;
|
||||
|
||||
int armature_def_nr;
|
||||
|
||||
const MDeformVert *dverts;
|
||||
int dverts_len;
|
||||
|
||||
bPoseChannel **pchan_from_defbase;
|
||||
int defbase_len;
|
||||
|
||||
float premat[4][4];
|
||||
float postmat[4][4];
|
||||
} ArmatureUserdata;
|
||||
|
||||
static void armature_vert_task(void *__restrict userdata,
|
||||
const int i,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const ArmatureUserdata *data = userdata;
|
||||
float(*const vert_coords)[3] = data->vert_coords;
|
||||
float(*const vert_deform_mats)[3][3] = data->vert_deform_mats;
|
||||
float(*const vert_coords_prev)[3] = data->vert_coords_prev;
|
||||
const bool use_envelope = data->use_envelope;
|
||||
const bool use_quaternion = data->use_quaternion;
|
||||
const bool use_dverts = data->use_dverts;
|
||||
const int armature_def_nr = data->armature_def_nr;
|
||||
|
||||
const MDeformVert *dvert;
|
||||
DualQuat sumdq, *dq = NULL;
|
||||
bPoseChannel *pchan;
|
||||
float *co, dco[3];
|
||||
float sumvec[3], summat[3][3];
|
||||
float *vec = NULL, (*smat)[3] = NULL;
|
||||
float contrib = 0.0f;
|
||||
float armature_weight = 1.0f; /* default to 1 if no overall def group */
|
||||
float prevco_weight = 1.0f; /* weight for optional cached vertexcos */
|
||||
|
||||
if (use_quaternion) {
|
||||
memset(&sumdq, 0, sizeof(DualQuat));
|
||||
dq = &sumdq;
|
||||
}
|
||||
else {
|
||||
zero_v3(sumvec);
|
||||
vec = sumvec;
|
||||
|
||||
if (vert_deform_mats) {
|
||||
zero_m3(summat);
|
||||
smat = summat;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_dverts || armature_def_nr != -1) {
|
||||
if (data->me_target) {
|
||||
BLI_assert(i < data->me_target->totvert);
|
||||
if (data->me_target->dvert != NULL) {
|
||||
dvert = data->me_target->dvert + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else if (data->dverts && i < data->dverts_len) {
|
||||
dvert = data->dverts + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
|
||||
if (armature_def_nr != -1 && dvert) {
|
||||
armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr);
|
||||
|
||||
if (data->invert_vgroup) {
|
||||
armature_weight = 1.0f - armature_weight;
|
||||
}
|
||||
|
||||
/* hackish: the blending factor can be used for blending with vert_coords_prev too */
|
||||
if (vert_coords_prev) {
|
||||
prevco_weight = armature_weight;
|
||||
armature_weight = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if there's any point in calculating for this vert */
|
||||
if (armature_weight == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the coord we work on */
|
||||
co = vert_coords_prev ? vert_coords_prev[i] : vert_coords[i];
|
||||
|
||||
/* Apply the object's matrix */
|
||||
mul_m4_v3(data->premat, co);
|
||||
|
||||
if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
|
||||
const MDeformWeight *dw = dvert->dw;
|
||||
int deformed = 0;
|
||||
unsigned int j;
|
||||
for (j = dvert->totweight; j != 0; j--, dw++) {
|
||||
const uint index = dw->def_nr;
|
||||
if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) {
|
||||
float weight = dw->weight;
|
||||
Bone *bone = pchan->bone;
|
||||
|
||||
deformed = 1;
|
||||
|
||||
if (bone && bone->flag & BONE_MULT_VG_ENV) {
|
||||
weight *= distfactor_to_bone(
|
||||
co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
|
||||
}
|
||||
|
||||
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
|
||||
}
|
||||
}
|
||||
/* if there are vertexgroups but not groups with bones
|
||||
* (like for softbody groups) */
|
||||
if (deformed == 0 && use_envelope) {
|
||||
for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
|
||||
contrib += dist_bone_deform(pchan, vec, dq, smat, co);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (use_envelope) {
|
||||
for (pchan = data->ob_arm->pose->chanbase.first; pchan; pchan = pchan->next) {
|
||||
if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
|
||||
contrib += dist_bone_deform(pchan, vec, dq, smat, co);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
|
||||
if (contrib > 0.0001f) {
|
||||
if (use_quaternion) {
|
||||
normalize_dq(dq, contrib);
|
||||
|
||||
if (armature_weight != 1.0f) {
|
||||
copy_v3_v3(dco, co);
|
||||
mul_v3m3_dq(dco, (vert_deform_mats) ? summat : NULL, dq);
|
||||
sub_v3_v3(dco, co);
|
||||
mul_v3_fl(dco, armature_weight);
|
||||
add_v3_v3(co, dco);
|
||||
}
|
||||
else {
|
||||
mul_v3m3_dq(co, (vert_deform_mats) ? summat : NULL, dq);
|
||||
}
|
||||
|
||||
smat = summat;
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, armature_weight / contrib);
|
||||
add_v3_v3v3(co, vec, co);
|
||||
}
|
||||
|
||||
if (vert_deform_mats) {
|
||||
float pre[3][3], post[3][3], tmpmat[3][3];
|
||||
|
||||
copy_m3_m4(pre, data->premat);
|
||||
copy_m3_m4(post, data->postmat);
|
||||
copy_m3_m3(tmpmat, vert_deform_mats[i]);
|
||||
|
||||
if (!use_quaternion) { /* quaternion already is scale corrected */
|
||||
mul_m3_fl(smat, armature_weight / contrib);
|
||||
}
|
||||
|
||||
mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat);
|
||||
}
|
||||
}
|
||||
|
||||
/* always, check above code */
|
||||
mul_m4_v3(data->postmat, co);
|
||||
|
||||
/* interpolate with previous modifier position using weight group */
|
||||
if (vert_coords_prev) {
|
||||
float mw = 1.0f - prevco_weight;
|
||||
vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0];
|
||||
vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1];
|
||||
vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void armature_deform_coords_impl(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
const int vert_coords_len,
|
||||
const int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const Mesh *me_target,
|
||||
bGPDstroke *gps_target)
|
||||
{
|
||||
bArmature *arm = ob_arm->data;
|
||||
bPoseChannel **pchan_from_defbase = NULL;
|
||||
const MDeformVert *dverts = NULL;
|
||||
bDeformGroup *dg;
|
||||
const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
|
||||
const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
|
||||
const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
|
||||
int defbase_len = 0; /* safety for vertexgroup index overflow */
|
||||
int i, dverts_len = 0; /* safety for vertexgroup overflow */
|
||||
bool use_dverts = false;
|
||||
int armature_def_nr;
|
||||
|
||||
/* in editmode, or not an armature */
|
||||
if (arm->edbo || (ob_arm->pose == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ob_arm->pose->flag & POSE_RECALC) != 0) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Trying to evaluate influence of armature '%s' which needs Pose recalc!",
|
||||
ob_arm->id.name);
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
/* get the def_nr for the overall armature vertex group if present */
|
||||
armature_def_nr = BKE_object_defgroup_name_index(ob_target, defgrp_name);
|
||||
|
||||
if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
|
||||
defbase_len = BLI_listbase_count(&ob_target->defbase);
|
||||
|
||||
if (ob_target->type == OB_MESH) {
|
||||
Mesh *me = ob_target->data;
|
||||
dverts = me->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = me->totvert;
|
||||
}
|
||||
}
|
||||
else if (ob_target->type == OB_LATTICE) {
|
||||
Lattice *lt = ob_target->data;
|
||||
dverts = lt->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = lt->pntsu * lt->pntsv * lt->pntsw;
|
||||
}
|
||||
}
|
||||
else if (ob_target->type == OB_GPENCIL) {
|
||||
dverts = gps_target->dvert;
|
||||
if (dverts) {
|
||||
dverts_len = gps_target->totpoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get a vertex-deform-index to posechannel array */
|
||||
if (deformflag & ARM_DEF_VGROUP) {
|
||||
if (ELEM(ob_target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
|
||||
/* if we have a Mesh, only use dverts if it has them */
|
||||
if (me_target) {
|
||||
use_dverts = (me_target->dvert != NULL);
|
||||
}
|
||||
else if (dverts) {
|
||||
use_dverts = true;
|
||||
}
|
||||
|
||||
if (use_dverts) {
|
||||
pchan_from_defbase = MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone");
|
||||
/* TODO(sergey): Some considerations here:
|
||||
*
|
||||
* - Check whether keeping this consistent across frames gives speedup.
|
||||
*/
|
||||
for (i = 0, dg = ob_target->defbase.first; dg; i++, dg = dg->next) {
|
||||
pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name);
|
||||
/* exclude non-deforming bones */
|
||||
if (pchan_from_defbase[i]) {
|
||||
if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) {
|
||||
pchan_from_defbase[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArmatureUserdata data = {
|
||||
.ob_arm = ob_arm,
|
||||
.ob_target = ob_target,
|
||||
.me_target = me_target,
|
||||
.vert_coords = vert_coords,
|
||||
.vert_deform_mats = vert_deform_mats,
|
||||
.vert_coords_prev = vert_coords_prev,
|
||||
.use_envelope = use_envelope,
|
||||
.use_quaternion = use_quaternion,
|
||||
.invert_vgroup = invert_vgroup,
|
||||
.use_dverts = use_dverts,
|
||||
.armature_def_nr = armature_def_nr,
|
||||
.dverts = dverts,
|
||||
.dverts_len = dverts_len,
|
||||
.pchan_from_defbase = pchan_from_defbase,
|
||||
.defbase_len = defbase_len,
|
||||
};
|
||||
|
||||
float obinv[4][4];
|
||||
invert_m4_m4(obinv, ob_target->obmat);
|
||||
|
||||
mul_m4_m4m4(data.postmat, obinv, ob_arm->obmat);
|
||||
invert_m4_m4(data.premat, data.postmat);
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings);
|
||||
|
||||
if (pchan_from_defbase) {
|
||||
MEM_freeN(pchan_from_defbase);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_armature_deform_coords_with_gpencil_stroke(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
bGPDstroke *gps_target)
|
||||
{
|
||||
armature_deform_coords_impl(ob_arm,
|
||||
ob_target,
|
||||
vert_coords,
|
||||
vert_deform_mats,
|
||||
vert_coords_len,
|
||||
deformflag,
|
||||
vert_coords_prev,
|
||||
defgrp_name,
|
||||
NULL,
|
||||
gps_target);
|
||||
}
|
||||
|
||||
void BKE_armature_deform_coords_with_mesh(Object *ob_arm,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
float (*vert_deform_mats)[3][3],
|
||||
int vert_coords_len,
|
||||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
const Mesh *me_target)
|
||||
{
|
||||
armature_deform_coords_impl(ob_arm,
|
||||
ob_target,
|
||||
vert_coords,
|
||||
vert_deform_mats,
|
||||
vert_coords_len,
|
||||
deformflag,
|
||||
vert_coords_prev,
|
||||
defgrp_name,
|
||||
me_target,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
@@ -43,7 +42,6 @@
|
||||
/* for dereferencing pointers */
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_vfont_types.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
@@ -54,7 +52,6 @@
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
398
source/blender/blenkernel/intern/curve_deform.c
Normal file
398
source/blender/blenkernel/intern/curve_deform.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* Deform coordinates by a curve object (used by modifier).
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_anim_path.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "BKE_deform.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Curve Deform Internal Utilities
|
||||
* \{ */
|
||||
|
||||
/* calculations is in local space of deformed object
|
||||
* so we store in latmat transform from path coord inside object
|
||||
*/
|
||||
typedef struct {
|
||||
float dmin[3], dmax[3];
|
||||
float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
|
||||
int no_rot_axis;
|
||||
} CurveDeform;
|
||||
|
||||
static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
|
||||
{
|
||||
invert_m4_m4(ob->imat, ob->obmat);
|
||||
mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat);
|
||||
invert_m4_m4(cd->curvespace, cd->objectspace);
|
||||
copy_m3_m4(cd->objectspace3, cd->objectspace);
|
||||
cd->no_rot_axis = 0;
|
||||
}
|
||||
|
||||
/* this makes sure we can extend for non-cyclic.
|
||||
*
|
||||
* returns OK: 1/0
|
||||
*/
|
||||
static bool where_on_path_deform(
|
||||
Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
|
||||
{
|
||||
BevList *bl;
|
||||
float ctime1;
|
||||
int cycl = 0;
|
||||
|
||||
/* test for cyclic */
|
||||
bl = ob->runtime.curve_cache->bev.first;
|
||||
if (!bl->nr) {
|
||||
return false;
|
||||
}
|
||||
if (bl->poly > -1) {
|
||||
cycl = 1;
|
||||
}
|
||||
|
||||
if (cycl == 0) {
|
||||
ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
ctime1 = ctime;
|
||||
}
|
||||
|
||||
/* vec needs 4 items */
|
||||
if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
|
||||
|
||||
if (cycl == 0) {
|
||||
Path *path = ob->runtime.curve_cache->path;
|
||||
float dvec[3];
|
||||
|
||||
if (ctime < 0.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
|
||||
mul_v3_fl(dvec, ctime * (float)path->len);
|
||||
add_v3_v3(vec, dvec);
|
||||
if (quat) {
|
||||
copy_qt_qt(quat, path->data[0].quat);
|
||||
}
|
||||
if (radius) {
|
||||
*radius = path->data[0].radius;
|
||||
}
|
||||
}
|
||||
else if (ctime > 1.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
|
||||
mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
|
||||
add_v3_v3(vec, dvec);
|
||||
if (quat) {
|
||||
copy_qt_qt(quat, path->data[path->len - 1].quat);
|
||||
}
|
||||
if (radius) {
|
||||
*radius = path->data[path->len - 1].radius;
|
||||
}
|
||||
/* weight - not used but could be added */
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* for each point, rotate & translate to curve */
|
||||
/* use path, since it has constant distances */
|
||||
/* co: local coord, result local too */
|
||||
/* returns quaternion for rotation, using cd->no_rot_axis */
|
||||
/* axis is using another define!!! */
|
||||
static bool calc_curve_deform(
|
||||
Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4])
|
||||
{
|
||||
Curve *cu = par->data;
|
||||
float fac, loc[4], dir[3], new_quat[4], radius;
|
||||
short index;
|
||||
const bool is_neg_axis = (axis > 2);
|
||||
|
||||
if (par->runtime.curve_cache == NULL) {
|
||||
/* Happens with a cyclic dependencies. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (par->runtime.curve_cache->path == NULL) {
|
||||
return false; /* happens on append, cyclic dependencies and empty curves */
|
||||
}
|
||||
|
||||
/* options */
|
||||
if (is_neg_axis) {
|
||||
index = axis - 3;
|
||||
if (cu->flag & CU_STRETCH) {
|
||||
fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
|
||||
}
|
||||
else {
|
||||
fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
|
||||
}
|
||||
}
|
||||
else {
|
||||
index = axis;
|
||||
if (cu->flag & CU_STRETCH) {
|
||||
fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
|
||||
}
|
||||
else {
|
||||
if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
|
||||
fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
|
||||
}
|
||||
else {
|
||||
fac = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */
|
||||
float quat[4], cent[3];
|
||||
|
||||
if (cd->no_rot_axis) { /* set by caller */
|
||||
|
||||
/* This is not exactly the same as 2.4x, since the axis is having rotation removed rather
|
||||
* than changing the axis before calculating the tilt but serves much the same purpose. */
|
||||
float dir_flat[3] = {0, 0, 0}, q[4];
|
||||
copy_v3_v3(dir_flat, dir);
|
||||
dir_flat[cd->no_rot_axis - 1] = 0.0f;
|
||||
|
||||
normalize_v3(dir);
|
||||
normalize_v3(dir_flat);
|
||||
|
||||
rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
|
||||
|
||||
mul_qt_qtqt(new_quat, q, new_quat);
|
||||
}
|
||||
|
||||
/* Logic for 'cent' orientation *
|
||||
*
|
||||
* The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
|
||||
*
|
||||
* Use a curve modifier to stretch a cube out, color each side RGB,
|
||||
* positive side light, negative dark.
|
||||
* view with X up (default), from the angle that you can see 3 faces RGB colors (light),
|
||||
* anti-clockwise
|
||||
* Notice X,Y,Z Up all have light colors and each ordered CCW.
|
||||
*
|
||||
* Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
|
||||
*
|
||||
* note: moved functions into quat_apply_track/vec_apply_track
|
||||
* */
|
||||
copy_qt_qt(quat, new_quat);
|
||||
copy_v3_v3(cent, co);
|
||||
|
||||
/* zero the axis which is not used,
|
||||
* the big block of text above now applies to these 3 lines */
|
||||
quat_apply_track(
|
||||
quat,
|
||||
axis,
|
||||
(axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
|
||||
vec_apply_track(cent, axis);
|
||||
cent[index] = 0.0f;
|
||||
|
||||
/* scale if enabled */
|
||||
if (cu->flag & CU_PATH_RADIUS) {
|
||||
mul_v3_fl(cent, radius);
|
||||
}
|
||||
|
||||
/* local rotation */
|
||||
normalize_qt(quat);
|
||||
mul_qt_v3(quat, cent);
|
||||
|
||||
/* translation */
|
||||
add_v3_v3v3(co, cent, loc);
|
||||
|
||||
if (r_quat) {
|
||||
copy_qt_qt(r_quat, quat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Curve Deform #BKE_curve_deform_coords API
|
||||
*
|
||||
* #BKE_curve_deform and related functions.
|
||||
* \{ */
|
||||
|
||||
void BKE_curve_deform_coords(Object *ob_curve,
|
||||
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)
|
||||
{
|
||||
Curve *cu;
|
||||
int a;
|
||||
CurveDeform cd;
|
||||
const bool is_neg_axis = (defaxis > 2);
|
||||
const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0;
|
||||
|
||||
if (ob_curve->type != OB_CURVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
cu = ob_curve->data;
|
||||
|
||||
init_curve_deform(ob_curve, ob_target, &cd);
|
||||
|
||||
/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
|
||||
if (is_neg_axis == false) {
|
||||
cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
|
||||
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
|
||||
}
|
||||
else {
|
||||
/* negative, these bounds give a good rest position */
|
||||
cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
|
||||
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
|
||||
}
|
||||
|
||||
if (dvert) {
|
||||
const MDeformVert *dvert_iter;
|
||||
float vec[3];
|
||||
|
||||
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
|
||||
if (weight > 0.0f) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
copy_v3_v3(vec, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL);
|
||||
interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* set mesh min/max bounds */
|
||||
INIT_MINMAX(cd.dmin, cd.dmax);
|
||||
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
|
||||
if (weight > 0.0f) {
|
||||
/* already in 'cd.curvespace', prev for loop */
|
||||
copy_v3_v3(vec, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL);
|
||||
interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* set mesh min max bounds */
|
||||
INIT_MINMAX(cd.dmin, cd.dmax);
|
||||
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
|
||||
}
|
||||
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
/* already in 'cd.curvespace', prev for loop */
|
||||
calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* input vec and orco = local coord in armature space */
|
||||
/* orco is original not-animated or deformed reference point */
|
||||
/* result written in vec and mat */
|
||||
void BKE_curve_deform_co(Object *ob_curve,
|
||||
Object *ob_target,
|
||||
const float orco[3],
|
||||
float vec[3],
|
||||
float mat[3][3],
|
||||
const int no_rot_axis)
|
||||
{
|
||||
CurveDeform cd;
|
||||
float quat[4];
|
||||
|
||||
if (ob_curve->type != OB_CURVE) {
|
||||
unit_m3(mat);
|
||||
return;
|
||||
}
|
||||
|
||||
init_curve_deform(ob_curve, ob_target, &cd);
|
||||
cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
|
||||
|
||||
copy_v3_v3(cd.dmin, orco);
|
||||
copy_v3_v3(cd.dmax, orco);
|
||||
|
||||
mul_m4_v3(cd.curvespace, vec);
|
||||
|
||||
if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) {
|
||||
float qmat[3][3];
|
||||
|
||||
quat_to_mat3(qmat, quat);
|
||||
mul_m3_m3m3(mat, qmat, cd.objectspace3);
|
||||
}
|
||||
else {
|
||||
unit_m3(mat);
|
||||
}
|
||||
|
||||
mul_m4_v3(cd.objectspace, vec);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -40,16 +39,13 @@
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_anim_path.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_displist.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
@@ -349,695 +345,6 @@ Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
|
||||
return lt_copy;
|
||||
}
|
||||
|
||||
typedef struct LatticeDeformData {
|
||||
Object *object;
|
||||
float *latticedata;
|
||||
float latmat[4][4];
|
||||
} LatticeDeformData;
|
||||
|
||||
LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
|
||||
{
|
||||
/* we make an array with all differences */
|
||||
Lattice *lt = oblatt->data;
|
||||
BPoint *bp;
|
||||
DispList *dl = oblatt->runtime.curve_cache ?
|
||||
BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
|
||||
NULL;
|
||||
const float *co = dl ? dl->verts : NULL;
|
||||
float *fp, imat[4][4];
|
||||
float fu, fv, fw;
|
||||
int u, v, w;
|
||||
float *latticedata;
|
||||
float latmat[4][4];
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
|
||||
if (lt->editlatt) {
|
||||
lt = lt->editlatt->latt;
|
||||
}
|
||||
bp = lt->def;
|
||||
|
||||
fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw,
|
||||
"latticedata");
|
||||
|
||||
/* for example with a particle system: (ob == NULL) */
|
||||
if (ob == NULL) {
|
||||
/* in deformspace, calc matrix */
|
||||
invert_m4_m4(latmat, oblatt->obmat);
|
||||
|
||||
/* back: put in deform array */
|
||||
invert_m4_m4(imat, latmat);
|
||||
}
|
||||
else {
|
||||
/* in deformspace, calc matrix */
|
||||
invert_m4_m4(imat, oblatt->obmat);
|
||||
mul_m4_m4m4(latmat, imat, ob->obmat);
|
||||
|
||||
/* back: put in deform array */
|
||||
invert_m4_m4(imat, latmat);
|
||||
}
|
||||
|
||||
for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
|
||||
for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
|
||||
for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
|
||||
if (dl) {
|
||||
fp[0] = co[0] - fu;
|
||||
fp[1] = co[1] - fv;
|
||||
fp[2] = co[2] - fw;
|
||||
}
|
||||
else {
|
||||
fp[0] = bp->vec[0] - fu;
|
||||
fp[1] = bp->vec[1] - fv;
|
||||
fp[2] = bp->vec[2] - fw;
|
||||
}
|
||||
|
||||
mul_mat3_m4_v3(imat, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
|
||||
lattice_deform_data->latticedata = latticedata;
|
||||
lattice_deform_data->object = oblatt;
|
||||
copy_m4_m4(lattice_deform_data->latmat, latmat);
|
||||
|
||||
return lattice_deform_data;
|
||||
}
|
||||
|
||||
void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight)
|
||||
{
|
||||
Object *ob = lattice_deform_data->object;
|
||||
Lattice *lt = ob->data;
|
||||
float u, v, w, tu[4], tv[4], tw[4];
|
||||
float vec[3];
|
||||
int idx_w, idx_v, idx_u;
|
||||
int ui, vi, wi, uu, vv, ww;
|
||||
|
||||
/* vgroup influence */
|
||||
int defgrp_index = -1;
|
||||
float co_prev[3], weight_blend = 0.0f;
|
||||
MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
|
||||
float *__restrict latticedata = lattice_deform_data->latticedata;
|
||||
|
||||
if (lt->editlatt) {
|
||||
lt = lt->editlatt->latt;
|
||||
}
|
||||
if (latticedata == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lt->vgroup[0] && dvert) {
|
||||
defgrp_index = BKE_object_defgroup_name_index(ob, lt->vgroup);
|
||||
copy_v3_v3(co_prev, co);
|
||||
}
|
||||
|
||||
/* co is in local coords, treat with latmat */
|
||||
mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
|
||||
|
||||
/* u v w coords */
|
||||
|
||||
if (lt->pntsu > 1) {
|
||||
u = (vec[0] - lt->fu) / lt->du;
|
||||
ui = (int)floor(u);
|
||||
u -= ui;
|
||||
key_curve_position_weights(u, tu, lt->typeu);
|
||||
}
|
||||
else {
|
||||
tu[0] = tu[2] = tu[3] = 0.0;
|
||||
tu[1] = 1.0;
|
||||
ui = 0;
|
||||
}
|
||||
|
||||
if (lt->pntsv > 1) {
|
||||
v = (vec[1] - lt->fv) / lt->dv;
|
||||
vi = (int)floor(v);
|
||||
v -= vi;
|
||||
key_curve_position_weights(v, tv, lt->typev);
|
||||
}
|
||||
else {
|
||||
tv[0] = tv[2] = tv[3] = 0.0;
|
||||
tv[1] = 1.0;
|
||||
vi = 0;
|
||||
}
|
||||
|
||||
if (lt->pntsw > 1) {
|
||||
w = (vec[2] - lt->fw) / lt->dw;
|
||||
wi = (int)floor(w);
|
||||
w -= wi;
|
||||
key_curve_position_weights(w, tw, lt->typew);
|
||||
}
|
||||
else {
|
||||
tw[0] = tw[2] = tw[3] = 0.0;
|
||||
tw[1] = 1.0;
|
||||
wi = 0;
|
||||
}
|
||||
|
||||
for (ww = wi - 1; ww <= wi + 2; ww++) {
|
||||
w = tw[ww - wi + 1];
|
||||
|
||||
if (w != 0.0f) {
|
||||
if (ww > 0) {
|
||||
if (ww < lt->pntsw) {
|
||||
idx_w = ww * lt->pntsu * lt->pntsv;
|
||||
}
|
||||
else {
|
||||
idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_w = 0;
|
||||
}
|
||||
|
||||
for (vv = vi - 1; vv <= vi + 2; vv++) {
|
||||
v = w * tv[vv - vi + 1];
|
||||
|
||||
if (v != 0.0f) {
|
||||
if (vv > 0) {
|
||||
if (vv < lt->pntsv) {
|
||||
idx_v = idx_w + vv * lt->pntsu;
|
||||
}
|
||||
else {
|
||||
idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_v = idx_w;
|
||||
}
|
||||
|
||||
for (uu = ui - 1; uu <= ui + 2; uu++) {
|
||||
u = weight * v * tu[uu - ui + 1];
|
||||
|
||||
if (u != 0.0f) {
|
||||
if (uu > 0) {
|
||||
if (uu < lt->pntsu) {
|
||||
idx_u = idx_v + uu;
|
||||
}
|
||||
else {
|
||||
idx_u = idx_v + (lt->pntsu - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_u = idx_v;
|
||||
}
|
||||
|
||||
madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
weight_blend += (u * BKE_defvert_find_weight(dvert + idx_u, defgrp_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
interp_v3_v3v3(co, co_prev, co, weight_blend);
|
||||
}
|
||||
}
|
||||
|
||||
void end_latt_deform(LatticeDeformData *lattice_deform_data)
|
||||
{
|
||||
if (lattice_deform_data->latticedata) {
|
||||
MEM_freeN(lattice_deform_data->latticedata);
|
||||
}
|
||||
|
||||
MEM_freeN(lattice_deform_data);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Curve Deform Internal Utilities
|
||||
* \{ */
|
||||
|
||||
/* calculations is in local space of deformed object
|
||||
* so we store in latmat transform from path coord inside object
|
||||
*/
|
||||
typedef struct {
|
||||
float dmin[3], dmax[3];
|
||||
float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
|
||||
int no_rot_axis;
|
||||
} CurveDeform;
|
||||
|
||||
static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
|
||||
{
|
||||
invert_m4_m4(ob->imat, ob->obmat);
|
||||
mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat);
|
||||
invert_m4_m4(cd->curvespace, cd->objectspace);
|
||||
copy_m3_m4(cd->objectspace3, cd->objectspace);
|
||||
cd->no_rot_axis = 0;
|
||||
}
|
||||
|
||||
/* this makes sure we can extend for non-cyclic.
|
||||
*
|
||||
* returns OK: 1/0
|
||||
*/
|
||||
static bool where_on_path_deform(
|
||||
Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
|
||||
{
|
||||
BevList *bl;
|
||||
float ctime1;
|
||||
int cycl = 0;
|
||||
|
||||
/* test for cyclic */
|
||||
bl = ob->runtime.curve_cache->bev.first;
|
||||
if (!bl->nr) {
|
||||
return false;
|
||||
}
|
||||
if (bl->poly > -1) {
|
||||
cycl = 1;
|
||||
}
|
||||
|
||||
if (cycl == 0) {
|
||||
ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
ctime1 = ctime;
|
||||
}
|
||||
|
||||
/* vec needs 4 items */
|
||||
if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
|
||||
|
||||
if (cycl == 0) {
|
||||
Path *path = ob->runtime.curve_cache->path;
|
||||
float dvec[3];
|
||||
|
||||
if (ctime < 0.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
|
||||
mul_v3_fl(dvec, ctime * (float)path->len);
|
||||
add_v3_v3(vec, dvec);
|
||||
if (quat) {
|
||||
copy_qt_qt(quat, path->data[0].quat);
|
||||
}
|
||||
if (radius) {
|
||||
*radius = path->data[0].radius;
|
||||
}
|
||||
}
|
||||
else if (ctime > 1.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
|
||||
mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
|
||||
add_v3_v3(vec, dvec);
|
||||
if (quat) {
|
||||
copy_qt_qt(quat, path->data[path->len - 1].quat);
|
||||
}
|
||||
if (radius) {
|
||||
*radius = path->data[path->len - 1].radius;
|
||||
}
|
||||
/* weight - not used but could be added */
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* for each point, rotate & translate to curve */
|
||||
/* use path, since it has constant distances */
|
||||
/* co: local coord, result local too */
|
||||
/* returns quaternion for rotation, using cd->no_rot_axis */
|
||||
/* axis is using another define!!! */
|
||||
static bool calc_curve_deform(
|
||||
Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4])
|
||||
{
|
||||
Curve *cu = par->data;
|
||||
float fac, loc[4], dir[3], new_quat[4], radius;
|
||||
short index;
|
||||
const bool is_neg_axis = (axis > 2);
|
||||
|
||||
if (par->runtime.curve_cache == NULL) {
|
||||
/* Happens with a cyclic dependencies. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (par->runtime.curve_cache->path == NULL) {
|
||||
return false; /* happens on append, cyclic dependencies and empty curves */
|
||||
}
|
||||
|
||||
/* options */
|
||||
if (is_neg_axis) {
|
||||
index = axis - 3;
|
||||
if (cu->flag & CU_STRETCH) {
|
||||
fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
|
||||
}
|
||||
else {
|
||||
fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
|
||||
}
|
||||
}
|
||||
else {
|
||||
index = axis;
|
||||
if (cu->flag & CU_STRETCH) {
|
||||
fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
|
||||
}
|
||||
else {
|
||||
if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
|
||||
fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
|
||||
}
|
||||
else {
|
||||
fac = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */
|
||||
float quat[4], cent[3];
|
||||
|
||||
if (cd->no_rot_axis) { /* set by caller */
|
||||
|
||||
/* This is not exactly the same as 2.4x, since the axis is having rotation removed rather
|
||||
* than changing the axis before calculating the tilt but serves much the same purpose. */
|
||||
float dir_flat[3] = {0, 0, 0}, q[4];
|
||||
copy_v3_v3(dir_flat, dir);
|
||||
dir_flat[cd->no_rot_axis - 1] = 0.0f;
|
||||
|
||||
normalize_v3(dir);
|
||||
normalize_v3(dir_flat);
|
||||
|
||||
rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
|
||||
|
||||
mul_qt_qtqt(new_quat, q, new_quat);
|
||||
}
|
||||
|
||||
/* Logic for 'cent' orientation *
|
||||
*
|
||||
* The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
|
||||
*
|
||||
* Use a curve modifier to stretch a cube out, color each side RGB,
|
||||
* positive side light, negative dark.
|
||||
* view with X up (default), from the angle that you can see 3 faces RGB colors (light),
|
||||
* anti-clockwise
|
||||
* Notice X,Y,Z Up all have light colors and each ordered CCW.
|
||||
*
|
||||
* Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
|
||||
*
|
||||
* note: moved functions into quat_apply_track/vec_apply_track
|
||||
* */
|
||||
copy_qt_qt(quat, new_quat);
|
||||
copy_v3_v3(cent, co);
|
||||
|
||||
/* zero the axis which is not used,
|
||||
* the big block of text above now applies to these 3 lines */
|
||||
quat_apply_track(
|
||||
quat,
|
||||
axis,
|
||||
(axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
|
||||
vec_apply_track(cent, axis);
|
||||
cent[index] = 0.0f;
|
||||
|
||||
/* scale if enabled */
|
||||
if (cu->flag & CU_PATH_RADIUS) {
|
||||
mul_v3_fl(cent, radius);
|
||||
}
|
||||
|
||||
/* local rotation */
|
||||
normalize_qt(quat);
|
||||
mul_qt_v3(quat, cent);
|
||||
|
||||
/* translation */
|
||||
add_v3_v3v3(co, cent, loc);
|
||||
|
||||
if (r_quat) {
|
||||
copy_qt_qt(r_quat, quat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Curve Deform #BKE_curve_deform_coords API
|
||||
*
|
||||
* #BKE_curve_deform and related functions.
|
||||
* \{ */
|
||||
|
||||
void BKE_curve_deform_coords(Object *ob_curve,
|
||||
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)
|
||||
{
|
||||
Curve *cu;
|
||||
int a;
|
||||
CurveDeform cd;
|
||||
const bool is_neg_axis = (defaxis > 2);
|
||||
const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0;
|
||||
|
||||
if (ob_curve->type != OB_CURVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
cu = ob_curve->data;
|
||||
|
||||
init_curve_deform(ob_curve, ob_target, &cd);
|
||||
|
||||
/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
|
||||
if (is_neg_axis == false) {
|
||||
cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
|
||||
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
|
||||
}
|
||||
else {
|
||||
/* negative, these bounds give a good rest position */
|
||||
cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
|
||||
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
|
||||
}
|
||||
|
||||
if (dvert) {
|
||||
const MDeformVert *dvert_iter;
|
||||
float vec[3];
|
||||
|
||||
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
|
||||
if (weight > 0.0f) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
copy_v3_v3(vec, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL);
|
||||
interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* set mesh min/max bounds */
|
||||
INIT_MINMAX(cd.dmin, cd.dmax);
|
||||
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0, dvert_iter = dvert; a < vert_coords_len; a++, dvert_iter++) {
|
||||
const float weight = invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(dvert_iter, defgrp_index) :
|
||||
BKE_defvert_find_weight(dvert_iter, defgrp_index);
|
||||
|
||||
if (weight > 0.0f) {
|
||||
/* already in 'cd.curvespace', prev for loop */
|
||||
copy_v3_v3(vec, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vec, defaxis, &cd, NULL);
|
||||
interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* set mesh min max bounds */
|
||||
INIT_MINMAX(cd.dmin, cd.dmax);
|
||||
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
mul_m4_v3(cd.curvespace, vert_coords[a]);
|
||||
minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
|
||||
}
|
||||
|
||||
for (a = 0; a < vert_coords_len; a++) {
|
||||
/* already in 'cd.curvespace', prev for loop */
|
||||
calc_curve_deform(ob_curve, vert_coords[a], defaxis, &cd, NULL);
|
||||
mul_m4_v3(cd.objectspace, vert_coords[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* input vec and orco = local coord in armature space */
|
||||
/* orco is original not-animated or deformed reference point */
|
||||
/* result written in vec and mat */
|
||||
void BKE_curve_deform_co(Object *ob_curve,
|
||||
Object *ob_target,
|
||||
const float orco[3],
|
||||
float vec[3],
|
||||
float mat[3][3],
|
||||
const int no_rot_axis)
|
||||
{
|
||||
CurveDeform cd;
|
||||
float quat[4];
|
||||
|
||||
if (ob_curve->type != OB_CURVE) {
|
||||
unit_m3(mat);
|
||||
return;
|
||||
}
|
||||
|
||||
init_curve_deform(ob_curve, ob_target, &cd);
|
||||
cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
|
||||
|
||||
copy_v3_v3(cd.dmin, orco);
|
||||
copy_v3_v3(cd.dmax, orco);
|
||||
|
||||
mul_m4_v3(cd.curvespace, vec);
|
||||
|
||||
if (calc_curve_deform(ob_curve, vec, ob_target->trackflag, &cd, quat)) {
|
||||
float qmat[3][3];
|
||||
|
||||
quat_to_mat3(qmat, quat);
|
||||
mul_m3_m3m3(mat, qmat, cd.objectspace3);
|
||||
}
|
||||
else {
|
||||
unit_m3(mat);
|
||||
}
|
||||
|
||||
mul_m4_v3(cd.objectspace, vec);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lattice Deform #BKE_lattice_deform_coords API
|
||||
*
|
||||
* #BKE_lattice_deform_coords and related functions.
|
||||
* \{ */
|
||||
|
||||
typedef struct LatticeDeformUserdata {
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
float (*vert_coords)[3];
|
||||
const MDeformVert *dvert;
|
||||
int defgrp_index;
|
||||
float fac;
|
||||
bool invert_vgroup;
|
||||
} LatticeDeformUserdata;
|
||||
|
||||
static void lattice_deform_vert_task(void *__restrict userdata,
|
||||
const int index,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const LatticeDeformUserdata *data = userdata;
|
||||
|
||||
if (data->dvert != NULL) {
|
||||
const float weight = data->invert_vgroup ?
|
||||
1.0f -
|
||||
BKE_defvert_find_weight(data->dvert + index, data->defgrp_index) :
|
||||
BKE_defvert_find_weight(data->dvert + index, data->defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
|
||||
}
|
||||
}
|
||||
else {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac);
|
||||
}
|
||||
}
|
||||
|
||||
static void lattice_deform_coords_impl(Object *ob_lattice,
|
||||
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)
|
||||
{
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
const MDeformVert *dvert = NULL;
|
||||
int defgrp_index = -1;
|
||||
|
||||
if (ob_lattice->type != OB_LATTICE) {
|
||||
return;
|
||||
}
|
||||
|
||||
lattice_deform_data = init_latt_deform(ob_lattice, ob_target);
|
||||
|
||||
/* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
|
||||
* We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
|
||||
*/
|
||||
if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
|
||||
defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name);
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
/* if there's derived data without deformverts, don't use vgroups */
|
||||
if (me_target) {
|
||||
dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT);
|
||||
}
|
||||
else if (ob_target->type == OB_LATTICE) {
|
||||
dvert = ((Lattice *)ob_target->data)->dvert;
|
||||
}
|
||||
else {
|
||||
dvert = ((Mesh *)ob_target->data)->dvert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LatticeDeformUserdata data = {
|
||||
.lattice_deform_data = lattice_deform_data,
|
||||
.vert_coords = vert_coords,
|
||||
.dvert = dvert,
|
||||
.defgrp_index = defgrp_index,
|
||||
.fac = fac,
|
||||
.invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
|
||||
};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
|
||||
|
||||
end_latt_deform(lattice_deform_data);
|
||||
}
|
||||
|
||||
void BKE_lattice_deform_coords(Object *ob_lattice,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
int vert_coords_len,
|
||||
short flag,
|
||||
const char *defgrp_name,
|
||||
float fac)
|
||||
{
|
||||
lattice_deform_coords_impl(
|
||||
ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL);
|
||||
}
|
||||
|
||||
void BKE_lattice_deform_coords_with_mesh(Object *ob_lattice,
|
||||
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)
|
||||
{
|
||||
lattice_deform_coords_impl(
|
||||
ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, me_target);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
bool object_deform_mball(Object *ob, ListBase *dispbase)
|
||||
{
|
||||
if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
|
||||
|
||||
389
source/blender/blenkernel/intern/lattice_deform.c
Normal file
389
source/blender/blenkernel/intern/lattice_deform.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* Deform coordinates by a lattice object (used by modifier).
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_displist.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "BKE_deform.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lattice Deform API
|
||||
* \{ */
|
||||
|
||||
typedef struct LatticeDeformData {
|
||||
Object *object;
|
||||
float *latticedata;
|
||||
float latmat[4][4];
|
||||
} LatticeDeformData;
|
||||
|
||||
LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
|
||||
{
|
||||
/* we make an array with all differences */
|
||||
Lattice *lt = oblatt->data;
|
||||
BPoint *bp;
|
||||
DispList *dl = oblatt->runtime.curve_cache ?
|
||||
BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
|
||||
NULL;
|
||||
const float *co = dl ? dl->verts : NULL;
|
||||
float *fp, imat[4][4];
|
||||
float fu, fv, fw;
|
||||
int u, v, w;
|
||||
float *latticedata;
|
||||
float latmat[4][4];
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
|
||||
if (lt->editlatt) {
|
||||
lt = lt->editlatt->latt;
|
||||
}
|
||||
bp = lt->def;
|
||||
|
||||
fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw,
|
||||
"latticedata");
|
||||
|
||||
/* for example with a particle system: (ob == NULL) */
|
||||
if (ob == NULL) {
|
||||
/* in deformspace, calc matrix */
|
||||
invert_m4_m4(latmat, oblatt->obmat);
|
||||
|
||||
/* back: put in deform array */
|
||||
invert_m4_m4(imat, latmat);
|
||||
}
|
||||
else {
|
||||
/* in deformspace, calc matrix */
|
||||
invert_m4_m4(imat, oblatt->obmat);
|
||||
mul_m4_m4m4(latmat, imat, ob->obmat);
|
||||
|
||||
/* back: put in deform array */
|
||||
invert_m4_m4(imat, latmat);
|
||||
}
|
||||
|
||||
for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
|
||||
for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
|
||||
for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
|
||||
if (dl) {
|
||||
fp[0] = co[0] - fu;
|
||||
fp[1] = co[1] - fv;
|
||||
fp[2] = co[2] - fw;
|
||||
}
|
||||
else {
|
||||
fp[0] = bp->vec[0] - fu;
|
||||
fp[1] = bp->vec[1] - fv;
|
||||
fp[2] = bp->vec[2] - fw;
|
||||
}
|
||||
|
||||
mul_mat3_m4_v3(imat, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
|
||||
lattice_deform_data->latticedata = latticedata;
|
||||
lattice_deform_data->object = oblatt;
|
||||
copy_m4_m4(lattice_deform_data->latmat, latmat);
|
||||
|
||||
return lattice_deform_data;
|
||||
}
|
||||
|
||||
void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight)
|
||||
{
|
||||
Object *ob = lattice_deform_data->object;
|
||||
Lattice *lt = ob->data;
|
||||
float u, v, w, tu[4], tv[4], tw[4];
|
||||
float vec[3];
|
||||
int idx_w, idx_v, idx_u;
|
||||
int ui, vi, wi, uu, vv, ww;
|
||||
|
||||
/* vgroup influence */
|
||||
int defgrp_index = -1;
|
||||
float co_prev[3], weight_blend = 0.0f;
|
||||
MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
|
||||
float *__restrict latticedata = lattice_deform_data->latticedata;
|
||||
|
||||
if (lt->editlatt) {
|
||||
lt = lt->editlatt->latt;
|
||||
}
|
||||
if (latticedata == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lt->vgroup[0] && dvert) {
|
||||
defgrp_index = BKE_object_defgroup_name_index(ob, lt->vgroup);
|
||||
copy_v3_v3(co_prev, co);
|
||||
}
|
||||
|
||||
/* co is in local coords, treat with latmat */
|
||||
mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
|
||||
|
||||
/* u v w coords */
|
||||
|
||||
if (lt->pntsu > 1) {
|
||||
u = (vec[0] - lt->fu) / lt->du;
|
||||
ui = (int)floor(u);
|
||||
u -= ui;
|
||||
key_curve_position_weights(u, tu, lt->typeu);
|
||||
}
|
||||
else {
|
||||
tu[0] = tu[2] = tu[3] = 0.0;
|
||||
tu[1] = 1.0;
|
||||
ui = 0;
|
||||
}
|
||||
|
||||
if (lt->pntsv > 1) {
|
||||
v = (vec[1] - lt->fv) / lt->dv;
|
||||
vi = (int)floor(v);
|
||||
v -= vi;
|
||||
key_curve_position_weights(v, tv, lt->typev);
|
||||
}
|
||||
else {
|
||||
tv[0] = tv[2] = tv[3] = 0.0;
|
||||
tv[1] = 1.0;
|
||||
vi = 0;
|
||||
}
|
||||
|
||||
if (lt->pntsw > 1) {
|
||||
w = (vec[2] - lt->fw) / lt->dw;
|
||||
wi = (int)floor(w);
|
||||
w -= wi;
|
||||
key_curve_position_weights(w, tw, lt->typew);
|
||||
}
|
||||
else {
|
||||
tw[0] = tw[2] = tw[3] = 0.0;
|
||||
tw[1] = 1.0;
|
||||
wi = 0;
|
||||
}
|
||||
|
||||
for (ww = wi - 1; ww <= wi + 2; ww++) {
|
||||
w = tw[ww - wi + 1];
|
||||
|
||||
if (w != 0.0f) {
|
||||
if (ww > 0) {
|
||||
if (ww < lt->pntsw) {
|
||||
idx_w = ww * lt->pntsu * lt->pntsv;
|
||||
}
|
||||
else {
|
||||
idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_w = 0;
|
||||
}
|
||||
|
||||
for (vv = vi - 1; vv <= vi + 2; vv++) {
|
||||
v = w * tv[vv - vi + 1];
|
||||
|
||||
if (v != 0.0f) {
|
||||
if (vv > 0) {
|
||||
if (vv < lt->pntsv) {
|
||||
idx_v = idx_w + vv * lt->pntsu;
|
||||
}
|
||||
else {
|
||||
idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_v = idx_w;
|
||||
}
|
||||
|
||||
for (uu = ui - 1; uu <= ui + 2; uu++) {
|
||||
u = weight * v * tu[uu - ui + 1];
|
||||
|
||||
if (u != 0.0f) {
|
||||
if (uu > 0) {
|
||||
if (uu < lt->pntsu) {
|
||||
idx_u = idx_v + uu;
|
||||
}
|
||||
else {
|
||||
idx_u = idx_v + (lt->pntsu - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx_u = idx_v;
|
||||
}
|
||||
|
||||
madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
weight_blend += (u * BKE_defvert_find_weight(dvert + idx_u, defgrp_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
interp_v3_v3v3(co, co_prev, co, weight_blend);
|
||||
}
|
||||
}
|
||||
|
||||
void end_latt_deform(LatticeDeformData *lattice_deform_data)
|
||||
{
|
||||
if (lattice_deform_data->latticedata) {
|
||||
MEM_freeN(lattice_deform_data->latticedata);
|
||||
}
|
||||
|
||||
MEM_freeN(lattice_deform_data);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Lattice Deform #BKE_lattice_deform_coords API
|
||||
*
|
||||
* #BKE_lattice_deform_coords and related functions.
|
||||
* \{ */
|
||||
|
||||
typedef struct LatticeDeformUserdata {
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
float (*vert_coords)[3];
|
||||
const MDeformVert *dvert;
|
||||
int defgrp_index;
|
||||
float fac;
|
||||
bool invert_vgroup;
|
||||
} LatticeDeformUserdata;
|
||||
|
||||
static void lattice_deform_vert_task(void *__restrict userdata,
|
||||
const int index,
|
||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const LatticeDeformUserdata *data = userdata;
|
||||
|
||||
if (data->dvert != NULL) {
|
||||
const float weight = data->invert_vgroup ?
|
||||
1.0f -
|
||||
BKE_defvert_find_weight(data->dvert + index, data->defgrp_index) :
|
||||
BKE_defvert_find_weight(data->dvert + index, data->defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
|
||||
}
|
||||
}
|
||||
else {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac);
|
||||
}
|
||||
}
|
||||
|
||||
static void lattice_deform_coords_impl(Object *ob_lattice,
|
||||
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)
|
||||
{
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
const MDeformVert *dvert = NULL;
|
||||
int defgrp_index = -1;
|
||||
|
||||
if (ob_lattice->type != OB_LATTICE) {
|
||||
return;
|
||||
}
|
||||
|
||||
lattice_deform_data = init_latt_deform(ob_lattice, ob_target);
|
||||
|
||||
/* Check whether to use vertex groups (only possible if ob_target is a Mesh or Lattice).
|
||||
* We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
|
||||
*/
|
||||
if (defgrp_name && defgrp_name[0] && ob_target && ELEM(ob_target->type, OB_MESH, OB_LATTICE)) {
|
||||
defgrp_index = BKE_object_defgroup_name_index(ob_target, defgrp_name);
|
||||
|
||||
if (defgrp_index != -1) {
|
||||
/* if there's derived data without deformverts, don't use vgroups */
|
||||
if (me_target) {
|
||||
dvert = CustomData_get_layer(&me_target->vdata, CD_MDEFORMVERT);
|
||||
}
|
||||
else if (ob_target->type == OB_LATTICE) {
|
||||
dvert = ((Lattice *)ob_target->data)->dvert;
|
||||
}
|
||||
else {
|
||||
dvert = ((Mesh *)ob_target->data)->dvert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LatticeDeformUserdata data = {
|
||||
.lattice_deform_data = lattice_deform_data,
|
||||
.vert_coords = vert_coords,
|
||||
.dvert = dvert,
|
||||
.defgrp_index = defgrp_index,
|
||||
.fac = fac,
|
||||
.invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
|
||||
};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, vert_coords_len, &data, lattice_deform_vert_task, &settings);
|
||||
|
||||
end_latt_deform(lattice_deform_data);
|
||||
}
|
||||
|
||||
void BKE_lattice_deform_coords(Object *ob_lattice,
|
||||
Object *ob_target,
|
||||
float (*vert_coords)[3],
|
||||
int vert_coords_len,
|
||||
short flag,
|
||||
const char *defgrp_name,
|
||||
float fac)
|
||||
{
|
||||
lattice_deform_coords_impl(
|
||||
ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, NULL);
|
||||
}
|
||||
|
||||
void BKE_lattice_deform_coords_with_mesh(Object *ob_lattice,
|
||||
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)
|
||||
{
|
||||
lattice_deform_coords_impl(
|
||||
ob_lattice, ob_target, vert_coords, vert_coords_len, flag, defgrp_name, fac, me_target);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -36,10 +36,10 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_geom.h"
|
||||
#include "BKE_gpencil_modifier.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
Reference in New Issue
Block a user