diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2019-04-28 15:05:13 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2019-05-01 16:34:54 +0300 |
commit | df8e5d66e3f7678af70f5c007bc2b4884978b341 (patch) | |
tree | fd4136e34051b138f0b870d8b01e231d6f12ee95 /source/blender/blenkernel/intern/armature.c | |
parent | 4d043b5c17fbdf9c68600f15745f687d6d6b57ef (diff) |
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
Diffstat (limited to 'source/blender/blenkernel/intern/armature.c')
-rw-r--r-- | source/blender/blenkernel/intern/armature.c | 401 |
1 files changed, 230 insertions, 171 deletions
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 9645721d29b..60446bf60b6 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -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 */ - - 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 (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); - } - } + 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}; + + float obinv[4][4]; + invert_m4_m4(obinv, target->obmat); - /* always, check above code */ - mul_m4_v3(postmat, co); + mul_m4_m4m4(data.postmat, obinv, armOb->obmat); + invert_m4_m4(data.premat, data.postmat); - /* 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); |