707 lines
22 KiB
C++
707 lines
22 KiB
C++
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*
|
|
* Deform coordinates by a armature object (used by modifier).
|
|
*/
|
|
|
|
#include <cctype>
|
|
#include <cfloat>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math_matrix.h"
|
|
#include "BLI_math_rotation.h"
|
|
#include "BLI_math_vector.h"
|
|
#include "BLI_task.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_gpencil_legacy_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.hh"
|
|
#include "BKE_customdata.hh"
|
|
#include "BKE_deform.h"
|
|
#include "BKE_editmesh.hh"
|
|
#include "BKE_lattice.hh"
|
|
#include "BKE_mesh.hh"
|
|
|
|
#include "DEG_depsgraph_build.hh"
|
|
|
|
#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],
|
|
const float weight,
|
|
float co_accum[3],
|
|
DualQuat *dq_accum,
|
|
float mat_accum[3][3],
|
|
const bool full_deform)
|
|
{
|
|
if (weight == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
if (dq_accum) {
|
|
BLI_assert(!co_accum);
|
|
|
|
add_weighted_dq_dq_pivot(dq_accum, deform_dq, co_in, weight, full_deform);
|
|
}
|
|
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 (full_deform) {
|
|
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],
|
|
const float weight,
|
|
float vec[3],
|
|
DualQuat *dq,
|
|
float defmat[3][3],
|
|
const bool full_deform)
|
|
{
|
|
const DualQuat *quats = pchan->runtime.bbone_dual_quats;
|
|
const Mat4 *mats = pchan->runtime.bbone_deform_mats;
|
|
float blend;
|
|
int index;
|
|
|
|
/* Calculate the indices of the 2 affecting b_bone segments. */
|
|
BKE_pchan_bbone_deform_segment_index(pchan, co, &index, &blend);
|
|
|
|
pchan_deform_accumulate(&quats[index],
|
|
mats[index + 1].mat,
|
|
co,
|
|
weight * (1.0f - blend),
|
|
vec,
|
|
dq,
|
|
defmat,
|
|
full_deform);
|
|
pchan_deform_accumulate(
|
|
&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat, full_deform);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
l = rad + rdist;
|
|
l *= l;
|
|
if (rdist == 0.0f || dist_sq >= l) {
|
|
return 0.0f;
|
|
}
|
|
|
|
a = sqrtf(dist_sq) - rad;
|
|
return 1.0f - (a * a) / (rdist * rdist);
|
|
}
|
|
|
|
static float dist_bone_deform(const bPoseChannel *pchan,
|
|
float vec[3],
|
|
DualQuat *dq,
|
|
float mat[3][3],
|
|
const float co[3],
|
|
const bool full_deform)
|
|
{
|
|
const Bone *bone = pchan->bone;
|
|
float fac, contrib = 0.0;
|
|
|
|
if (bone == nullptr) {
|
|
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, full_deform);
|
|
}
|
|
else {
|
|
pchan_deform_accumulate(
|
|
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat, full_deform);
|
|
}
|
|
}
|
|
}
|
|
|
|
return contrib;
|
|
}
|
|
|
|
static void pchan_bone_deform(const bPoseChannel *pchan,
|
|
const float weight,
|
|
float vec[3],
|
|
DualQuat *dq,
|
|
float mat[3][3],
|
|
const float co[3],
|
|
const bool full_deform,
|
|
float *contrib)
|
|
{
|
|
const 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, full_deform);
|
|
}
|
|
else {
|
|
pchan_deform_accumulate(
|
|
&pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat, full_deform);
|
|
}
|
|
|
|
(*contrib) += weight;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Armature Deform #BKE_armature_deform_coords API
|
|
*
|
|
* #BKE_armature_deform_coords and related functions.
|
|
* \{ */
|
|
|
|
struct ArmatureUserdata {
|
|
const Object *ob_arm;
|
|
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];
|
|
|
|
/** Specific data types. */
|
|
struct {
|
|
int cd_dvert_offset;
|
|
} bmesh;
|
|
};
|
|
|
|
static void armature_vert_task_with_dvert(const ArmatureUserdata *data,
|
|
const int i,
|
|
const MDeformVert *dvert)
|
|
{
|
|
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;
|
|
|
|
DualQuat sumdq, *dq = nullptr;
|
|
const bPoseChannel *pchan;
|
|
float *co, dco[3];
|
|
float sumvec[3], summat[3][3];
|
|
float *vec = nullptr, (*smat)[3] = nullptr;
|
|
float contrib = 0.0f;
|
|
float armature_weight = 1.0f; /* default to 1 if no overall def group */
|
|
float prevco_weight = 0.0f; /* weight for optional cached vertexcos */
|
|
|
|
const bool full_deform = vert_deform_mats != nullptr;
|
|
|
|
if (use_quaternion) {
|
|
memset(&sumdq, 0, sizeof(DualQuat));
|
|
dq = &sumdq;
|
|
}
|
|
else {
|
|
zero_v3(sumvec);
|
|
vec = sumvec;
|
|
|
|
if (full_deform) {
|
|
zero_m3(summat);
|
|
smat = summat;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
/* This weight specifies the contribution from the coordinates at the start of this
|
|
* modifier evaluation, while armature_weight is normally the opposite of that. */
|
|
prevco_weight = 1.0f - armature_weight;
|
|
armature_weight = 1.0f;
|
|
}
|
|
}
|
|
|
|
/* check if there's any point in calculating for this vert */
|
|
if (vert_coords_prev) {
|
|
if (prevco_weight == 1.0f) {
|
|
return;
|
|
}
|
|
|
|
/* get the coord we work on */
|
|
co = vert_coords_prev[i];
|
|
}
|
|
else {
|
|
if (armature_weight == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
/* get the coord we work on */
|
|
co = 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;
|
|
uint 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;
|
|
const 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, full_deform, &contrib);
|
|
}
|
|
}
|
|
/* If there are vertex-groups but not groups with bones (like for soft-body groups). */
|
|
if (deformed == 0 && use_envelope) {
|
|
for (pchan = static_cast<const bPoseChannel *>(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, full_deform);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (use_envelope) {
|
|
for (pchan = static_cast<const bPoseChannel *>(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, full_deform);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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, full_deform ? summat : nullptr, dq);
|
|
sub_v3_v3(dco, co);
|
|
mul_v3_fl(dco, armature_weight);
|
|
add_v3_v3(co, dco);
|
|
}
|
|
else {
|
|
mul_v3m3_dq(co, full_deform ? summat : nullptr, dq);
|
|
}
|
|
|
|
smat = summat;
|
|
}
|
|
else {
|
|
mul_v3_fl(vec, armature_weight / contrib);
|
|
add_v3_v3v3(co, vec, co);
|
|
}
|
|
|
|
if (full_deform) {
|
|
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_vert_task(void *__restrict userdata,
|
|
const int i,
|
|
const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
|
|
const MDeformVert *dvert;
|
|
if (data->use_dverts || data->armature_def_nr != -1) {
|
|
if (data->me_target) {
|
|
BLI_assert(i < data->me_target->totvert);
|
|
if (data->dverts != nullptr) {
|
|
dvert = data->dverts + i;
|
|
}
|
|
else {
|
|
dvert = nullptr;
|
|
}
|
|
}
|
|
else if (data->dverts && i < data->dverts_len) {
|
|
dvert = data->dverts + i;
|
|
}
|
|
else {
|
|
dvert = nullptr;
|
|
}
|
|
}
|
|
else {
|
|
dvert = nullptr;
|
|
}
|
|
|
|
armature_vert_task_with_dvert(data, i, dvert);
|
|
}
|
|
|
|
static void armature_vert_task_editmesh(void *__restrict userdata,
|
|
MempoolIterData *iter,
|
|
const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
|
|
BMVert *v = (BMVert *)iter;
|
|
const MDeformVert *dvert = static_cast<const MDeformVert *>(
|
|
BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset));
|
|
armature_vert_task_with_dvert(data, BM_elem_index_get(v), dvert);
|
|
}
|
|
|
|
static void armature_vert_task_editmesh_no_dvert(void *__restrict userdata,
|
|
MempoolIterData *iter,
|
|
const TaskParallelTLS *__restrict /*tls*/)
|
|
{
|
|
const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
|
|
BMVert *v = (BMVert *)iter;
|
|
armature_vert_task_with_dvert(data, BM_elem_index_get(v), nullptr);
|
|
}
|
|
|
|
static void armature_deform_coords_impl(const Object *ob_arm,
|
|
const 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,
|
|
BMEditMesh *em_target,
|
|
bGPDstroke *gps_target)
|
|
{
|
|
const bArmature *arm = static_cast<const bArmature *>(ob_arm->data);
|
|
bPoseChannel **pchan_from_defbase = nullptr;
|
|
const MDeformVert *dverts = nullptr;
|
|
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 dverts_len = 0; /* safety for vertexgroup overflow */
|
|
bool use_dverts = false;
|
|
int armature_def_nr = -1;
|
|
int cd_dvert_offset = -1;
|
|
|
|
/* in editmode, or not an armature */
|
|
if (arm->edbo || (ob_arm->pose == nullptr)) {
|
|
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);
|
|
}
|
|
|
|
if (BKE_object_supports_vertex_groups(ob_target)) {
|
|
const ID *target_data_id = nullptr;
|
|
if (ob_target->type == OB_MESH) {
|
|
target_data_id = me_target == nullptr ? (const ID *)ob_target->data : &me_target->id;
|
|
if (em_target == nullptr) {
|
|
const Mesh *me = (const Mesh *)target_data_id;
|
|
dverts = BKE_mesh_deform_verts(me);
|
|
if (dverts) {
|
|
dverts_len = me->totvert;
|
|
}
|
|
}
|
|
}
|
|
else if (ob_target->type == OB_LATTICE) {
|
|
const Lattice *lt = static_cast<const Lattice *>(ob_target->data);
|
|
target_data_id = (const ID *)ob_target->data;
|
|
dverts = lt->dvert;
|
|
if (dverts) {
|
|
dverts_len = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
}
|
|
}
|
|
else if (ob_target->type == OB_GPENCIL_LEGACY) {
|
|
target_data_id = (const ID *)ob_target->data;
|
|
dverts = gps_target->dvert;
|
|
if (dverts) {
|
|
dverts_len = gps_target->totpoints;
|
|
}
|
|
}
|
|
|
|
/* Collect the vertex group names from the evaluated data. */
|
|
armature_def_nr = BKE_id_defgroup_name_index(target_data_id, defgrp_name);
|
|
const ListBase *defbase = BKE_id_defgroup_list_get(target_data_id);
|
|
defbase_len = BLI_listbase_count(defbase);
|
|
|
|
/* get a vertex-deform-index to posechannel array */
|
|
if (deformflag & ARM_DEF_VGROUP) {
|
|
/* if we have a Mesh, only use dverts if it has them */
|
|
if (em_target) {
|
|
cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
|
|
use_dverts = (cd_dvert_offset != -1);
|
|
}
|
|
else if (me_target) {
|
|
use_dverts = (BKE_mesh_deform_verts(me_target) != nullptr);
|
|
}
|
|
else if (dverts) {
|
|
use_dverts = true;
|
|
}
|
|
|
|
if (use_dverts) {
|
|
pchan_from_defbase = static_cast<bPoseChannel **>(
|
|
MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone"));
|
|
/* TODO(sergey): Some considerations here:
|
|
*
|
|
* - Check whether keeping this consistent across frames gives speedup.
|
|
*/
|
|
int i;
|
|
LISTBASE_FOREACH_INDEX (bDeformGroup *, dg, defbase, i) {
|
|
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] = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ArmatureUserdata data{};
|
|
data.ob_arm = ob_arm;
|
|
data.me_target = me_target;
|
|
data.vert_coords = vert_coords;
|
|
data.vert_deform_mats = vert_deform_mats;
|
|
data.vert_coords_prev = vert_coords_prev;
|
|
data.use_envelope = use_envelope;
|
|
data.use_quaternion = use_quaternion;
|
|
data.invert_vgroup = invert_vgroup;
|
|
data.use_dverts = use_dverts;
|
|
data.armature_def_nr = armature_def_nr;
|
|
data.dverts = dverts;
|
|
data.dverts_len = dverts_len;
|
|
data.pchan_from_defbase = pchan_from_defbase;
|
|
data.defbase_len = defbase_len;
|
|
data.bmesh.cd_dvert_offset = cd_dvert_offset;
|
|
|
|
float obinv[4][4];
|
|
invert_m4_m4(obinv, ob_target->object_to_world);
|
|
|
|
mul_m4_m4m4(data.postmat, obinv, ob_arm->object_to_world);
|
|
invert_m4_m4(data.premat, data.postmat);
|
|
|
|
if (em_target != nullptr) {
|
|
/* While this could cause an extra loop over mesh data, in most cases this will
|
|
* have already been properly set. */
|
|
BM_mesh_elem_index_ensure(em_target->bm, BM_VERT);
|
|
|
|
TaskParallelSettings settings;
|
|
BLI_parallel_mempool_settings_defaults(&settings);
|
|
|
|
if (use_dverts) {
|
|
BLI_task_parallel_mempool(
|
|
em_target->bm->vpool, &data, armature_vert_task_editmesh, &settings);
|
|
}
|
|
else {
|
|
BLI_task_parallel_mempool(
|
|
em_target->bm->vpool, &data, armature_vert_task_editmesh_no_dvert, &settings);
|
|
}
|
|
}
|
|
else {
|
|
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(const Object *ob_arm,
|
|
const 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,
|
|
nullptr,
|
|
nullptr,
|
|
gps_target);
|
|
}
|
|
|
|
void BKE_armature_deform_coords_with_mesh(const Object *ob_arm,
|
|
const 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,
|
|
nullptr,
|
|
nullptr);
|
|
}
|
|
|
|
void BKE_armature_deform_coords_with_editmesh(const Object *ob_arm,
|
|
const 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,
|
|
BMEditMesh *em_target)
|
|
{
|
|
armature_deform_coords_impl(ob_arm,
|
|
ob_target,
|
|
vert_coords,
|
|
vert_deform_mats,
|
|
vert_coords_len,
|
|
deformflag,
|
|
vert_coords_prev,
|
|
defgrp_name,
|
|
nullptr,
|
|
em_target,
|
|
nullptr);
|
|
}
|
|
|
|
/** \} */
|