Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/armature.c
| Show First 20 Lines • Show All 1,287 Lines • ▼ Show 20 Lines | static void pchan_bone_deform(bPoseChannel *pchan, | ||||
| else { | else { | ||||
| pchan_deform_accumulate( | pchan_deform_accumulate( | ||||
| &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); | &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat); | ||||
| } | } | ||||
| (*contrib) += weight; | (*contrib) += weight; | ||||
| } | } | ||||
| void armature_deform_verts(Object *armOb, | typedef struct ArmatureUserdata { | ||||
| Object *target, | Object *armOb; | ||||
| const Mesh *mesh, | Object *target; | ||||
| float (*vertexCos)[3], | const Mesh *mesh; | ||||
| float (*defMats)[3][3], | float (*vertexCos)[3]; | ||||
| int numVerts, | float (*defMats)[3][3]; | ||||
| int deformflag, | float (*prevCos)[3]; | ||||
| float (*prevCos)[3], | |||||
| const char *defgrp_name, | bool use_envelope; | ||||
| bGPDstroke *gps) | bool use_quaternion; | ||||
| { | bool invert_vgroup; | ||||
| bArmature *arm = armOb->data; | bool use_dverts; | ||||
| bPoseChannel *pchan, **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; | |||||
| int defbase_tot = 0; /* safety for vertexgroup index overflow */ | |||||
| int i, target_totvert = 0; /* safety for vertexgroup overflow */ | |||||
| bool use_dverts = false; | |||||
| int armature_def_nr; | |||||
| /* in editmode, or not an armature */ | |||||
| if (arm->edbo || (armOb->pose == NULL)) { | |||||
| return; | |||||
| } | |||||
| if ((armOb->pose->flag & POSE_RECALC) != 0) { | int armature_def_nr; | ||||
| CLOG_ERROR(&LOG, | |||||
| "Trying to evaluate influence of armature '%s' which needs Pose recalc!", | |||||
| armOb->id.name); | |||||
| BLI_assert(0); | |||||
| } | |||||
| invert_m4_m4(obinv, target->obmat); | int target_totvert; | ||||
| copy_m4_m4(premat, target->obmat); | MDeformVert *dverts; | ||||
| mul_m4_m4m4(postmat, obinv, armOb->obmat); | |||||
| invert_m4_m4(premat, postmat); | |||||
| /* get the def_nr for the overall armature vertex group if present */ | int defbase_tot; | ||||
| armature_def_nr = defgroup_name_index(target, defgrp_name); | bPoseChannel **defnrToPC; | ||||
| if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { | float premat[4][4]; | ||||
| defbase_tot = BLI_listbase_count(&target->defbase); | 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; | |||||
| if (target->type == OB_MESH) { | |||||
| Mesh *me = target->data; | |||||
| dverts = me->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = me->totvert; | |||||
| } | |||||
| } | |||||
| else if (target->type == OB_LATTICE) { | |||||
| Lattice *lt = target->data; | |||||
| dverts = lt->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = lt->pntsu * lt->pntsv * lt->pntsw; | |||||
| } | |||||
| } | |||||
| else if (target->type == OB_GPENCIL) { | |||||
| dverts = gps->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = gps->totpoints; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* get a vertex-deform-index to posechannel array */ | |||||
| if (deformflag & ARM_DEF_VGROUP) { | |||||
| if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { | |||||
| /* if we have a Mesh, only use dverts if it has them */ | |||||
| if (mesh) { | |||||
| use_dverts = (mesh->dvert != NULL); | |||||
| } | |||||
| else if (dverts) { | |||||
| use_dverts = true; | |||||
| } | |||||
| if (use_dverts) { | |||||
| defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone"); | |||||
| /* TODO(sergey): Some considerations here: | |||||
| * | |||||
| * - Check whether keeping this consistent across frames gives speedup. | |||||
| */ | |||||
| for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) { | |||||
| defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name); | |||||
| /* exclude non-deforming bones */ | |||||
| if (defnrToPC[i]) { | |||||
| if (defnrToPC[i]->bone->flag & BONE_NO_DEFORM) { | |||||
| defnrToPC[i] = NULL; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| for (i = 0; i < numVerts; i++) { | |||||
| MDeformVert *dvert; | MDeformVert *dvert; | ||||
| DualQuat sumdq, *dq = NULL; | DualQuat sumdq, *dq = NULL; | ||||
| bPoseChannel *pchan; | |||||
| float *co, dco[3]; | float *co, dco[3]; | ||||
| float sumvec[3], summat[3][3]; | float sumvec[3], summat[3][3]; | ||||
| float *vec = NULL, (*smat)[3] = NULL; | float *vec = NULL, (*smat)[3] = NULL; | ||||
| float contrib = 0.0f; | float contrib = 0.0f; | ||||
| float armature_weight = 1.0f; /* default to 1 if no overall def group */ | float armature_weight = 1.0f; /* default to 1 if no overall def group */ | ||||
| float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ | float prevco_weight = 1.0f; /* weight for optional cached vertexcos */ | ||||
| if (use_quaternion) { | if (use_quaternion) { | ||||
| memset(&sumdq, 0, sizeof(DualQuat)); | memset(&sumdq, 0, sizeof(DualQuat)); | ||||
| dq = &sumdq; | dq = &sumdq; | ||||
| } | } | ||||
| else { | else { | ||||
| sumvec[0] = sumvec[1] = sumvec[2] = 0.0f; | sumvec[0] = sumvec[1] = sumvec[2] = 0.0f; | ||||
| vec = sumvec; | vec = sumvec; | ||||
| if (defMats) { | if (defMats) { | ||||
| zero_m3(summat); | zero_m3(summat); | ||||
| smat = summat; | smat = summat; | ||||
| } | } | ||||
| } | } | ||||
| if (use_dverts || armature_def_nr != -1) { | if (use_dverts || armature_def_nr != -1) { | ||||
| if (mesh) { | if (data->mesh) { | ||||
| BLI_assert(i < mesh->totvert); | BLI_assert(i < data->mesh->totvert); | ||||
| dvert = mesh->dvert + i; | dvert = data->mesh->dvert + i; | ||||
| } | } | ||||
| else if (dverts && i < target_totvert) { | else if (data->dverts && i < data->target_totvert) { | ||||
| dvert = dverts + i; | dvert = data->dverts + i; | ||||
| } | } | ||||
| else { | else { | ||||
| dvert = NULL; | dvert = NULL; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| dvert = NULL; | dvert = NULL; | ||||
| } | } | ||||
| if (armature_def_nr != -1 && dvert) { | if (armature_def_nr != -1 && dvert) { | ||||
| armature_weight = defvert_find_weight(dvert, armature_def_nr); | armature_weight = defvert_find_weight(dvert, armature_def_nr); | ||||
| if (invert_vgroup) { | if (data->invert_vgroup) { | ||||
| armature_weight = 1.0f - armature_weight; | armature_weight = 1.0f - armature_weight; | ||||
| } | } | ||||
| /* hackish: the blending factor can be used for blending with prevCos too */ | /* hackish: the blending factor can be used for blending with prevCos too */ | ||||
| if (prevCos) { | if (prevCos) { | ||||
| prevco_weight = armature_weight; | prevco_weight = armature_weight; | ||||
| armature_weight = 1.0f; | armature_weight = 1.0f; | ||||
| } | } | ||||
| } | } | ||||
| /* check if there's any point in calculating for this vert */ | /* check if there's any point in calculating for this vert */ | ||||
| if (armature_weight == 0.0f) { | if (armature_weight == 0.0f) { | ||||
| continue; | return; | ||||
| } | } | ||||
| /* get the coord we work on */ | /* get the coord we work on */ | ||||
| co = prevCos ? prevCos[i] : vertexCos[i]; | co = prevCos ? prevCos[i] : vertexCos[i]; | ||||
| /* Apply the object's matrix */ | /* Apply the object's matrix */ | ||||
| mul_m4_v3(premat, co); | mul_m4_v3(data->premat, co); | ||||
| if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ | if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */ | ||||
| MDeformWeight *dw = dvert->dw; | MDeformWeight *dw = dvert->dw; | ||||
| int deformed = 0; | int deformed = 0; | ||||
| unsigned int j; | unsigned int j; | ||||
| float acum_weight = 0; | float acum_weight = 0; | ||||
| for (j = dvert->totweight; j != 0; j--, dw++) { | for (j = dvert->totweight; j != 0; j--, dw++) { | ||||
| const int index = dw->def_nr; | const int index = dw->def_nr; | ||||
| if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) { | if (index >= 0 && index < data->defbase_tot && (pchan = data->defnrToPC[index])) { | ||||
| float weight = dw->weight; | float weight = dw->weight; | ||||
| Bone *bone = pchan->bone; | Bone *bone = pchan->bone; | ||||
| deformed = 1; | deformed = 1; | ||||
| if (bone && bone->flag & BONE_MULT_VG_ENV) { | if (bone && bone->flag & BONE_MULT_VG_ENV) { | ||||
| weight *= distfactor_to_bone( | weight *= distfactor_to_bone( | ||||
| co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); | co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); | ||||
| } | } | ||||
| /* check limit of weight */ | /* check limit of weight */ | ||||
| if (target->type == OB_GPENCIL) { | if (data->target->type == OB_GPENCIL) { | ||||
| if (acum_weight + weight >= 1.0f) { | if (acum_weight + weight >= 1.0f) { | ||||
| weight = 1.0f - acum_weight; | weight = 1.0f - acum_weight; | ||||
| } | } | ||||
| acum_weight += weight; | acum_weight += weight; | ||||
| } | } | ||||
| pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); | pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib); | ||||
| /* if acumulated weight limit exceed, exit loop */ | /* if acumulated weight limit exceed, exit loop */ | ||||
| if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) { | if ((data->target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* if there are vertexgroups but not groups with bones | /* if there are vertexgroups but not groups with bones | ||||
| * (like for softbody groups) */ | * (like for softbody groups) */ | ||||
| if (deformed == 0 && use_envelope) { | if (deformed == 0 && use_envelope) { | ||||
| for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { | for (pchan = data->armOb->pose->chanbase.first; pchan; pchan = pchan->next) { | ||||
| if (!(pchan->bone->flag & BONE_NO_DEFORM)) { | if (!(pchan->bone->flag & BONE_NO_DEFORM)) { | ||||
| contrib += dist_bone_deform(pchan, vec, dq, smat, co); | contrib += dist_bone_deform(pchan, vec, dq, smat, co); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (use_envelope) { | else if (use_envelope) { | ||||
| for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { | for (pchan = data->armOb->pose->chanbase.first; pchan; pchan = pchan->next) { | ||||
| if (!(pchan->bone->flag & BONE_NO_DEFORM)) { | if (!(pchan->bone->flag & BONE_NO_DEFORM)) { | ||||
| contrib += dist_bone_deform(pchan, vec, dq, smat, co); | contrib += dist_bone_deform(pchan, vec, dq, smat, co); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ | /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ | ||||
| if (contrib > 0.0001f) { | if (contrib > 0.0001f) { | ||||
| if (use_quaternion) { | if (use_quaternion) { | ||||
| normalize_dq(dq, contrib); | normalize_dq(dq, contrib); | ||||
| if (armature_weight != 1.0f) { | if (armature_weight != 1.0f) { | ||||
| copy_v3_v3(dco, co); | copy_v3_v3(dco, co); | ||||
| mul_v3m3_dq(dco, (defMats) ? summat : NULL, dq); | mul_v3m3_dq(dco, (defMats) ? summat : NULL, dq); | ||||
| sub_v3_v3(dco, co); | sub_v3_v3(dco, co); | ||||
| mul_v3_fl(dco, armature_weight); | mul_v3_fl(dco, armature_weight); | ||||
| add_v3_v3(co, dco); | add_v3_v3(co, dco); | ||||
| } | } | ||||
| else { | else { | ||||
| mul_v3m3_dq(co, (defMats) ? summat : NULL, dq); | mul_v3m3_dq(co, (defMats) ? summat : NULL, dq); | ||||
| } | } | ||||
| smat = summat; | smat = summat; | ||||
| } | } | ||||
| else { | else { | ||||
| mul_v3_fl(vec, armature_weight / contrib); | mul_v3_fl(vec, armature_weight / contrib); | ||||
| add_v3_v3v3(co, vec, co); | add_v3_v3v3(co, vec, co); | ||||
| } | } | ||||
| if (defMats) { | if (defMats) { | ||||
| float pre[3][3], post[3][3], tmpmat[3][3]; | float pre[3][3], post[3][3], tmpmat[3][3]; | ||||
| copy_m3_m4(pre, premat); | copy_m3_m4(pre, data->premat); | ||||
| copy_m3_m4(post, postmat); | copy_m3_m4(post, data->postmat); | ||||
| copy_m3_m3(tmpmat, defMats[i]); | copy_m3_m3(tmpmat, defMats[i]); | ||||
| if (!use_quaternion) { /* quaternion already is scale corrected */ | if (!use_quaternion) { /* quaternion already is scale corrected */ | ||||
| mul_m3_fl(smat, armature_weight / contrib); | mul_m3_fl(smat, armature_weight / contrib); | ||||
| } | } | ||||
| mul_m3_series(defMats[i], post, smat, pre, tmpmat); | mul_m3_series(defMats[i], post, smat, pre, tmpmat); | ||||
| } | } | ||||
| } | } | ||||
| /* always, check above code */ | /* always, check above code */ | ||||
| mul_m4_v3(postmat, co); | mul_m4_v3(data->postmat, co); | ||||
| /* interpolate with previous modifier position using weight group */ | /* interpolate with previous modifier position using weight group */ | ||||
| if (prevCos) { | if (prevCos) { | ||||
| float mw = 1.0f - prevco_weight; | float mw = 1.0f - prevco_weight; | ||||
| vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0]; | vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0]; | ||||
| vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1]; | vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1]; | ||||
| vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2]; | vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2]; | ||||
| } | } | ||||
| } | } | ||||
| void armature_deform_verts(Object *armOb, | |||||
| Object *target, | |||||
| const Mesh *mesh, | |||||
| float (*vertexCos)[3], | |||||
| float (*defMats)[3][3], | |||||
| int numVerts, | |||||
| int deformflag, | |||||
| float (*prevCos)[3], | |||||
| const char *defgrp_name, | |||||
| bGPDstroke *gps) | |||||
| { | |||||
| bArmature *arm = armOb->data; | |||||
| bPoseChannel **defnrToPC = NULL; | |||||
| 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_tot = 0; /* safety for vertexgroup index overflow */ | |||||
| int i, target_totvert = 0; /* safety for vertexgroup overflow */ | |||||
| bool use_dverts = false; | |||||
| int armature_def_nr; | |||||
| /* in editmode, or not an armature */ | |||||
| if (arm->edbo || (armOb->pose == NULL)) { | |||||
| return; | |||||
| } | |||||
| if ((armOb->pose->flag & POSE_RECALC) != 0) { | |||||
| CLOG_ERROR(&LOG, | |||||
| "Trying to evaluate influence of armature '%s' which needs Pose recalc!", | |||||
| armOb->id.name); | |||||
| BLI_assert(0); | |||||
| } | |||||
| /* get the def_nr for the overall armature vertex group if present */ | |||||
| armature_def_nr = defgroup_name_index(target, defgrp_name); | |||||
| if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { | |||||
| defbase_tot = BLI_listbase_count(&target->defbase); | |||||
| if (target->type == OB_MESH) { | |||||
| Mesh *me = target->data; | |||||
| dverts = me->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = me->totvert; | |||||
| } | |||||
| } | |||||
| else if (target->type == OB_LATTICE) { | |||||
| Lattice *lt = target->data; | |||||
| dverts = lt->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = lt->pntsu * lt->pntsv * lt->pntsw; | |||||
| } | |||||
| } | |||||
| else if (target->type == OB_GPENCIL) { | |||||
| dverts = gps->dvert; | |||||
| if (dverts) { | |||||
| target_totvert = gps->totpoints; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* get a vertex-deform-index to posechannel array */ | |||||
| if (deformflag & ARM_DEF_VGROUP) { | |||||
| if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { | |||||
| /* if we have a Mesh, only use dverts if it has them */ | |||||
| if (mesh) { | |||||
| use_dverts = (mesh->dvert != NULL); | |||||
| } | |||||
| else if (dverts) { | |||||
| use_dverts = true; | |||||
| } | |||||
| if (use_dverts) { | |||||
| defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone"); | |||||
| /* TODO(sergey): Some considerations here: | |||||
| * | |||||
| * - Check whether keeping this consistent across frames gives speedup. | |||||
| */ | |||||
| for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) { | |||||
| defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name); | |||||
| /* exclude non-deforming bones */ | |||||
| if (defnrToPC[i]) { | |||||
| if (defnrToPC[i]->bone->flag & BONE_NO_DEFORM) { | |||||
| defnrToPC[i] = NULL; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| 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); | |||||
| mul_m4_m4m4(data.postmat, obinv, armOb->obmat); | |||||
| invert_m4_m4(data.premat, data.postmat); | |||||
| 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) { | if (defnrToPC) { | ||||
| MEM_freeN(defnrToPC); | MEM_freeN(defnrToPC); | ||||
| } | } | ||||
| } | } | ||||
| /* ************ END Armature Deform ******************* */ | /* ************ END Armature Deform ******************* */ | ||||
| void get_objectspace_bone_matrix(struct Bone *bone, | void get_objectspace_bone_matrix(struct Bone *bone, | ||||
| ▲ Show 20 Lines • Show All 1,241 Lines • Show Last 20 Lines | |||||