Modifiers: support parallelism in Armature and Lattice Deform.
This partially mitigates the performance drop in Spring 02_055_A.anim caused by dependency changes in D4715. Differential Revision: https://developer.blender.org/D4753
This commit is contained in:
parent
4d043b5c17
commit
df8e5d66e3
|
@ -1293,6 +1293,211 @@ static void pchan_bone_deform(bPoseChannel *pchan,
|
|||
(*contrib) += weight;
|
||||
}
|
||||
|
||||
typedef struct ArmatureUserdata {
|
||||
Object *armOb;
|
||||
Object *target;
|
||||
const Mesh *mesh;
|
||||
float (*vertexCos)[3];
|
||||
float (*defMats)[3][3];
|
||||
float (*prevCos)[3];
|
||||
|
||||
bool use_envelope;
|
||||
bool use_quaternion;
|
||||
bool invert_vgroup;
|
||||
bool use_dverts;
|
||||
|
||||
int armature_def_nr;
|
||||
|
||||
int target_totvert;
|
||||
MDeformVert *dverts;
|
||||
|
||||
int defbase_tot;
|
||||
bPoseChannel **defnrToPC;
|
||||
|
||||
float premat[4][4];
|
||||
float postmat[4][4];
|
||||
} ArmatureUserdata;
|
||||
|
||||
static void armature_vert_task(void *__restrict userdata,
|
||||
const int i,
|
||||
const ParallelRangeTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const ArmatureUserdata *data = userdata;
|
||||
float(*const vertexCos)[3] = data->vertexCos;
|
||||
float(*const defMats)[3][3] = data->defMats;
|
||||
float(*const prevCos)[3] = data->prevCos;
|
||||
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;
|
||||
|
||||
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 {
|
||||
sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
|
||||
vec = sumvec;
|
||||
|
||||
if (defMats) {
|
||||
zero_m3(summat);
|
||||
smat = summat;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_dverts || armature_def_nr != -1) {
|
||||
if (data->mesh) {
|
||||
BLI_assert(i < data->mesh->totvert);
|
||||
dvert = data->mesh->dvert + i;
|
||||
}
|
||||
else if (data->dverts && i < data->target_totvert) {
|
||||
dvert = data->dverts + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
|
||||
if (armature_def_nr != -1 && dvert) {
|
||||
armature_weight = 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 prevCos too */
|
||||
if (prevCos) {
|
||||
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 = prevCos ? prevCos[i] : vertexCos[i];
|
||||
|
||||
/* Apply the object's matrix */
|
||||
mul_m4_v3(data->premat, co);
|
||||
|
||||
if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
|
||||
MDeformWeight *dw = dvert->dw;
|
||||
int deformed = 0;
|
||||
unsigned int j;
|
||||
float acum_weight = 0;
|
||||
for (j = dvert->totweight; j != 0; j--, dw++) {
|
||||
const int index = dw->def_nr;
|
||||
if (index >= 0 && index < data->defbase_tot && (pchan = data->defnrToPC[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);
|
||||
}
|
||||
|
||||
/* check limit of weight */
|
||||
if (data->target->type == OB_GPENCIL) {
|
||||
if (acum_weight + weight >= 1.0f) {
|
||||
weight = 1.0f - acum_weight;
|
||||
}
|
||||
acum_weight += weight;
|
||||
}
|
||||
|
||||
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
|
||||
|
||||
/* if acumulated weight limit exceed, exit loop */
|
||||
if ((data->target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if there are vertexgroups but not groups with bones
|
||||
* (like for softbody groups) */
|
||||
if (deformed == 0 && use_envelope) {
|
||||
for (pchan = data->armOb->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->armOb->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, (defMats) ? summat : NULL, dq);
|
||||
sub_v3_v3(dco, co);
|
||||
mul_v3_fl(dco, armature_weight);
|
||||
add_v3_v3(co, dco);
|
||||
}
|
||||
else {
|
||||
mul_v3m3_dq(co, (defMats) ? summat : NULL, dq);
|
||||
}
|
||||
|
||||
smat = summat;
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, armature_weight / contrib);
|
||||
add_v3_v3v3(co, vec, co);
|
||||
}
|
||||
|
||||
if (defMats) {
|
||||
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, defMats[i]);
|
||||
|
||||
if (!use_quaternion) { /* quaternion already is scale corrected */
|
||||
mul_m3_fl(smat, armature_weight / contrib);
|
||||
}
|
||||
|
||||
mul_m3_series(defMats[i], post, smat, pre, tmpmat);
|
||||
}
|
||||
}
|
||||
|
||||
/* always, check above code */
|
||||
mul_m4_v3(data->postmat, co);
|
||||
|
||||
/* interpolate with previous modifier position using weight group */
|
||||
if (prevCos) {
|
||||
float mw = 1.0f - prevco_weight;
|
||||
vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0];
|
||||
vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1];
|
||||
vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2];
|
||||
}
|
||||
}
|
||||
|
||||
void armature_deform_verts(Object *armOb,
|
||||
Object *target,
|
||||
const Mesh *mesh,
|
||||
|
@ -1305,10 +1510,9 @@ void armature_deform_verts(Object *armOb,
|
|||
bGPDstroke *gps)
|
||||
{
|
||||
bArmature *arm = armOb->data;
|
||||
bPoseChannel *pchan, **defnrToPC = NULL;
|
||||
bPoseChannel **defnrToPC = NULL;
|
||||
MDeformVert *dverts = NULL;
|
||||
bDeformGroup *dg;
|
||||
float obinv[4][4], premat[4][4], postmat[4][4];
|
||||
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;
|
||||
|
@ -1329,11 +1533,6 @@ void armature_deform_verts(Object *armOb,
|
|||
BLI_assert(0);
|
||||
}
|
||||
|
||||
invert_m4_m4(obinv, target->obmat);
|
||||
copy_m4_m4(premat, target->obmat);
|
||||
mul_m4_m4m4(postmat, obinv, armOb->obmat);
|
||||
invert_m4_m4(premat, postmat);
|
||||
|
||||
/* get the def_nr for the overall armature vertex group if present */
|
||||
armature_def_nr = defgroup_name_index(target, defgrp_name);
|
||||
|
||||
|
@ -1392,172 +1591,32 @@ void armature_deform_verts(Object *armOb,
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
MDeformVert *dvert;
|
||||
DualQuat sumdq, *dq = NULL;
|
||||
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 */
|
||||
ArmatureUserdata data = {.armOb = armOb,
|
||||
.target = target,
|
||||
.mesh = mesh,
|
||||
.vertexCos = vertexCos,
|
||||
.defMats = defMats,
|
||||
.prevCos = prevCos,
|
||||
.use_envelope = use_envelope,
|
||||
.use_quaternion = use_quaternion,
|
||||
.invert_vgroup = invert_vgroup,
|
||||
.use_dverts = use_dverts,
|
||||
.armature_def_nr = armature_def_nr,
|
||||
.target_totvert = target_totvert,
|
||||
.dverts = dverts,
|
||||
.defbase_tot = defbase_tot,
|
||||
.defnrToPC = defnrToPC};
|
||||
|
||||
if (use_quaternion) {
|
||||
memset(&sumdq, 0, sizeof(DualQuat));
|
||||
dq = &sumdq;
|
||||
}
|
||||
else {
|
||||
sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
|
||||
vec = sumvec;
|
||||
float obinv[4][4];
|
||||
invert_m4_m4(obinv, target->obmat);
|
||||
|
||||
if (defMats) {
|
||||
zero_m3(summat);
|
||||
smat = summat;
|
||||
}
|
||||
}
|
||||
mul_m4_m4m4(data.postmat, obinv, armOb->obmat);
|
||||
invert_m4_m4(data.premat, data.postmat);
|
||||
|
||||
if (use_dverts || armature_def_nr != -1) {
|
||||
if (mesh) {
|
||||
BLI_assert(i < mesh->totvert);
|
||||
dvert = mesh->dvert + i;
|
||||
}
|
||||
else if (dverts && i < target_totvert) {
|
||||
dvert = dverts + i;
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dvert = NULL;
|
||||
}
|
||||
|
||||
if (armature_def_nr != -1 && dvert) {
|
||||
armature_weight = defvert_find_weight(dvert, armature_def_nr);
|
||||
|
||||
if (invert_vgroup) {
|
||||
armature_weight = 1.0f - armature_weight;
|
||||
}
|
||||
|
||||
/* hackish: the blending factor can be used for blending with prevCos too */
|
||||
if (prevCos) {
|
||||
prevco_weight = armature_weight;
|
||||
armature_weight = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if there's any point in calculating for this vert */
|
||||
if (armature_weight == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get the coord we work on */
|
||||
co = prevCos ? prevCos[i] : vertexCos[i];
|
||||
|
||||
/* Apply the object's matrix */
|
||||
mul_m4_v3(premat, co);
|
||||
|
||||
if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
|
||||
MDeformWeight *dw = dvert->dw;
|
||||
int deformed = 0;
|
||||
unsigned int j;
|
||||
float acum_weight = 0;
|
||||
for (j = dvert->totweight; j != 0; j--, dw++) {
|
||||
const int index = dw->def_nr;
|
||||
if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[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);
|
||||
}
|
||||
|
||||
/* check limit of weight */
|
||||
if (target->type == OB_GPENCIL) {
|
||||
if (acum_weight + weight >= 1.0f) {
|
||||
weight = 1.0f - acum_weight;
|
||||
}
|
||||
acum_weight += weight;
|
||||
}
|
||||
|
||||
pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
|
||||
|
||||
/* if acumulated weight limit exceed, exit loop */
|
||||
if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if there are vertexgroups but not groups with bones
|
||||
* (like for softbody groups) */
|
||||
if (deformed == 0 && use_envelope) {
|
||||
for (pchan = armOb->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 = armOb->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, (defMats) ? summat : NULL, dq);
|
||||
sub_v3_v3(dco, co);
|
||||
mul_v3_fl(dco, armature_weight);
|
||||
add_v3_v3(co, dco);
|
||||
}
|
||||
else {
|
||||
mul_v3m3_dq(co, (defMats) ? summat : NULL, dq);
|
||||
}
|
||||
|
||||
smat = summat;
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(vec, armature_weight / contrib);
|
||||
add_v3_v3v3(co, vec, co);
|
||||
}
|
||||
|
||||
if (defMats) {
|
||||
float pre[3][3], post[3][3], tmpmat[3][3];
|
||||
|
||||
copy_m3_m4(pre, premat);
|
||||
copy_m3_m4(post, postmat);
|
||||
copy_m3_m3(tmpmat, defMats[i]);
|
||||
|
||||
if (!use_quaternion) { /* quaternion already is scale corrected */
|
||||
mul_m3_fl(smat, armature_weight / contrib);
|
||||
}
|
||||
|
||||
mul_m3_series(defMats[i], post, smat, pre, tmpmat);
|
||||
}
|
||||
}
|
||||
|
||||
/* always, check above code */
|
||||
mul_m4_v3(postmat, co);
|
||||
|
||||
/* interpolate with previous modifier position using weight group */
|
||||
if (prevCos) {
|
||||
float mw = 1.0f - prevco_weight;
|
||||
vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0];
|
||||
vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1];
|
||||
vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2];
|
||||
}
|
||||
}
|
||||
ParallelRangeSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, numVerts, &data, armature_vert_task, &settings);
|
||||
|
||||
if (defnrToPC) {
|
||||
MEM_freeN(defnrToPC);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "BLI_listbase.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
@ -878,6 +879,31 @@ void curve_deform_vector(
|
|||
mul_m4_v3(cd.objectspace, vec);
|
||||
}
|
||||
|
||||
typedef struct LatticeDeformUserdata {
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
float (*vertexCos)[3];
|
||||
MDeformVert *dvert;
|
||||
int defgrp_index;
|
||||
float fac;
|
||||
} LatticeDeformUserdata;
|
||||
|
||||
static void lattice_deform_vert_task(void *__restrict userdata,
|
||||
const int index,
|
||||
const ParallelRangeTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
const LatticeDeformUserdata *data = userdata;
|
||||
|
||||
if (data->dvert != NULL) {
|
||||
const float weight = defvert_find_weight(data->dvert + index, data->defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vertexCos[index], weight * data->fac);
|
||||
}
|
||||
}
|
||||
else {
|
||||
calc_latt_deform(data->lattice_deform_data, data->vertexCos[index], data->fac);
|
||||
}
|
||||
}
|
||||
|
||||
void lattice_deform_verts(Object *laOb,
|
||||
Object *target,
|
||||
Mesh *mesh,
|
||||
|
@ -889,7 +915,6 @@ void lattice_deform_verts(Object *laOb,
|
|||
LatticeDeformData *lattice_deform_data;
|
||||
MDeformVert *dvert = NULL;
|
||||
int defgrp_index = -1;
|
||||
int a;
|
||||
|
||||
if (laOb->type != OB_LATTICE) {
|
||||
return;
|
||||
|
@ -916,20 +941,18 @@ void lattice_deform_verts(Object *laOb,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (dvert) {
|
||||
MDeformVert *dvert_iter;
|
||||
for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
|
||||
const float weight = defvert_find_weight(dvert_iter, defgrp_index);
|
||||
if (weight > 0.0f) {
|
||||
calc_latt_deform(lattice_deform_data, vertexCos[a], weight * fac);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (a = 0; a < numVerts; a++) {
|
||||
calc_latt_deform(lattice_deform_data, vertexCos[a], fac);
|
||||
}
|
||||
}
|
||||
|
||||
LatticeDeformUserdata data = {.lattice_deform_data = lattice_deform_data,
|
||||
.vertexCos = vertexCos,
|
||||
.dvert = dvert,
|
||||
.defgrp_index = defgrp_index,
|
||||
.fac = fac};
|
||||
|
||||
ParallelRangeSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.min_iter_per_thread = 32;
|
||||
BLI_task_parallel_range(0, numVerts, &data, lattice_deform_vert_task, &settings);
|
||||
|
||||
end_latt_deform(lattice_deform_data);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue