From 8742899f5e3ef3b76c5fa2227ab3df3bdc0e1ef9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 28 Jul 2007 21:04:30 +0000 Subject: Armature CrazySpace Improvement =============================== An improved CrazySpace correction is now used for Armature modifiers that use vertex groups, and that are the first enabled modifiers in the stack. This is a a specific case, but also a common one. http://www.blender.org/development/current-projects/changes-since-244/skinning/ Implementation Notes: - The quaternion crazyspace correction is still used for modifiers other than the armature modifier. - Modifiers can now provide a deform matrix per vertex to be used for crazyspace correction, only the armature modifier implements this now. --- source/blender/blenkernel/BKE_DerivedMesh.h | 5 + source/blender/blenkernel/BKE_lattice.h | 4 +- source/blender/blenkernel/BKE_modifier.h | 6 ++ source/blender/blenkernel/intern/DerivedMesh.c | 82 ++++++++++++-- source/blender/blenkernel/intern/armature.c | 144 +++++++++++++++++-------- source/blender/blenkernel/intern/modifier.c | 46 ++++++-- 6 files changed, 221 insertions(+), 66 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 872717fdb9b..4a19bfb9249 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -425,6 +425,11 @@ DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask); DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r, CustomDataMask dataMask); +/* returns an array of deform matrices for crazyspace correction, and the + number of modifiers left */ +int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], + float (**deformcos)[3]); + void weight_to_rgb(float input, float *fr, float *fg, float *fb); /* determines required DerivedMesh data according to view and edit modes */ diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 55eb1d27cc0..3dc4b49b52b 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -64,8 +64,8 @@ void lattice_deform_verts(struct Object *laOb, struct Object *target, int numVerts, char *vgroup); void armature_deform_verts(struct Object *armOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], - int numVerts, int deformflag, - const char *defgrp_name); + float (*defMats)[3][3], int numVerts, + int deformflag, const char *defgrp_name); float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]; void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]); void lattice_calc_modifiers(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index ce3f33bd35c..297443b883d 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -125,6 +125,11 @@ typedef struct ModifierTypeInfo { struct EditMesh *editData, struct DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts); + /* Set deform matrix per vertex for crazyspace correction */ + void (*deformMatricesEM)( + struct ModifierData *md, struct Object *ob, + struct EditMesh *editData, struct DerivedMesh *derivedData, + float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); /********************* Non-deform modifier functions *********************/ @@ -257,6 +262,7 @@ void modifier_copyData(struct ModifierData *md, struct ModifierData *ta int modifier_dependsOnTime(struct ModifierData *md); int modifier_supportsMapping(struct ModifierData *md); int modifier_couldBeCage(struct ModifierData *md); +int modifier_isDeformer(struct ModifierData *md); void modifier_setError(struct ModifierData *md, char *format, ...); void modifiers_foreachObjectLink(struct Object *ob, diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 5f8e9c7b207..be1d39d6c8c 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1887,6 +1887,24 @@ static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3] return cos; } +static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) +{ + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; + + if((md->mode & required_mode) != required_mode) return 0; + if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + modifier_setError(md, "Internal error, modifier requires" + "original data (bad stack position)."); + return 0; + } + if(mti->isDisabled && mti->isDisabled(md)) return 0; + if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0; + if(md->mode & eModifierMode_DisableTemporary) return 0; + + return 1; +} + static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r, CustomDataMask dataMask) @@ -1897,7 +1915,6 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, float (*deformedVerts)[3] = NULL; DerivedMesh *dm; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL); - int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; LinkNode *datamasks, *curr; modifiers_clearErrors(ob); @@ -1918,14 +1935,8 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, for(i = 0; md; i++, md = md->next, curr = curr->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if((md->mode & required_mode) != required_mode) continue; - if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires" - "original data (bad stack position)."); + if(!editmesh_modifier_is_enabled(md, dm)) continue; - } - if(mti->isDisabled && mti->isDisabled(md)) continue; - if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; /* How to apply modifier depends on (a) what we already have as * a result of previous modifiers (could be a DerivedMesh or just @@ -2461,6 +2472,61 @@ float *mesh_get_mapped_verts_nors(Object *ob) return vertexcosnos; } +/* ********* crazyspace *************** */ + +int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**deformcos)[3]) +{ + Object *ob = G.obedit; + EditMesh *em = G.editMesh; + ModifierData *md; + DerivedMesh *dm; + int i, a, numleft = 0, numVerts = 0; + int cageIndex = modifiers_getCageIndex(ob, NULL); + float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; + + modifiers_clearErrors(ob); + + dm = NULL; + md = ob->modifiers.first; + + /* compute the deformation matrices and coordinates for the first + modifiers with on cage editing that are enabled and support computing + deform matrices */ + for(i = 0; md && i <= cageIndex; i++, md = md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if(!editmesh_modifier_is_enabled(md, dm)) + continue; + + if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { + if(!defmats) { + dm= getEditMeshDerivedMesh(em, ob, NULL); + deformedVerts= editmesh_getVertexCos(em, &numVerts); + defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats"); + + for(a=0; adeformMatricesEM(md, ob, em, dm, deformedVerts, defmats, + numVerts); + } + else + break; + } + + for(; md && i <= cageIndex; md = md->next, i++) + if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md)) + numleft++; + + if(dm) + dm->release(dm); + + *deformmats= defmats; + *deformcos= deformedVerts; + + return numleft; +} /* ************************* fluidsim bobj file handling **************************** */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b320a7e0106..db384181982 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -504,39 +504,54 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan) Bone *bone= pchan->bone; Mat4 *b_bone= b_bone_spline_setup(pchan); Mat4 *b_bone_mats; + float tmat[4][4]; int a; - pchan->b_bone_mats=b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats"); - - /* first matrix is the inverse arm_mat, to bring points in local bone space */ + /* allocate b_bone matrices and dual quats */ + b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats"); + pchan->b_bone_mats= b_bone_mats; + + /* first matrix is the inverse arm_mat, to bring points in local bone space + for finding out which segment it belongs to */ Mat4Invert(b_bone_mats[0].mat, bone->arm_mat); - - /* then we multiply the bbone_mats with arm_mat */ + + /* then we make the b_bone_mats: + - first transform to local bone space + - translate over the curve to the bbone mat space + - transform with b_bone matrix + - transform back into global space */ + Mat4One(tmat); + for(a=0; asegments; a++) { - Mat4MulMat4(b_bone_mats[a+1].mat, b_bone[a].mat, bone->arm_mat); + tmat[3][1] = -a*(bone->length/(float)bone->segments); + + Mat4MulSerie(b_bone_mats[a+1].mat, pchan->chan_mat, bone->arm_mat, + b_bone[a].mat, tmat, b_bone_mats[0].mat, NULL, NULL, NULL); } } -static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *defpos) +static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, float defmat[][3]) { Mat4 *b_bone= pchan->b_bone_mats; - float segment; + float (*mat)[4]= b_bone[0].mat; + float segment, y; int a; - /* need to transform defpos back to bonespace */ - Mat4MulVecfl(b_bone[0].mat, defpos); + /* need to transform co back to bonespace, only need y */ + y= mat[0][1]*co[0] + mat[1][1]*co[1] + mat[2][1]*co[2] + mat[3][1]; /* now calculate which of the b_bones are deforming this */ segment= bone->length/((float)bone->segments); - a= (int) (defpos[1]/segment); + a= (int)(y/segment); - /* note; by clamping it extends deform at endpoints, goes best with straight joints in restpos. */ + /* note; by clamping it extends deform at endpoints, goes best with + straight joints in restpos. */ CLAMP(a, 0, bone->segments-1); - /* since the bbone mats translate from (0.0.0) on the curve, we subtract */ - defpos[1] -= ((float)a)*segment; - - Mat4MulVecfl(b_bone[a+1].mat, defpos); + Mat4MulVecfl(b_bone[a+1].mat, co); + + if(defmat) + Mat3CpyMat4(defmat, b_bone[a+1].mat); } /* using vec with dist to bone b1 - b2 */ @@ -590,12 +605,24 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl } } -static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co) +static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3]) +{ + float wmat[3][3]; + + if(pchan->bone->segments>1) + Mat3CpyMat3(wmat, bbonemat); + else + Mat3CpyMat4(wmat, pchan->chan_mat); + + Mat3MulFloat((float*)wmat, weight); + Mat3AddMat3(mat, mat, wmat); +} + +static float dist_bone_deform(bPoseChannel *pchan, float *vec, float mat[][3], float *co) { Bone *bone= pchan->bone; - float fac; - float cop[3]; - float contrib=0.0; + float fac, contrib=0.0; + float cop[3], bbonemat[3][3]; if(bone==NULL) return 0.0f; @@ -603,52 +630,58 @@ static float dist_bone_deform(bPoseChannel *pchan, float *vec, float *co) fac= distfactor_to_bone(cop, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); - if (fac>0.0){ + if (fac>0.0) { fac*=bone->weight; contrib= fac; if(contrib>0.0) { - - VECCOPY (cop, co); - if(bone->segments>1) - b_bone_deform(pchan, bone, cop); // applies on cop - - Mat4MulVecfl(pchan->chan_mat, cop); - - VecSubf (cop, cop, co); // Make this a delta from the base position + // applies on cop and bbonemat + b_bone_deform(pchan, bone, cop, (mat)?bbonemat:NULL); + else + Mat4MulVecfl(pchan->chan_mat, cop); + + // Make this a delta from the base position + VecSubf (cop, cop, co); cop[0]*=fac; cop[1]*=fac; cop[2]*=fac; VecAddf (vec, vec, cop); + + if(mat) + pchan_deform_mat_add(pchan, fac, bbonemat, mat); } } return contrib; } -static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float *co, float *contrib) +static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float mat[][3], float *co, float *contrib) { - float cop[3]; + float cop[3], bbonemat[3][3]; if (!weight) return; - VECCOPY (cop, co); - + VECCOPY(cop, co); + if(pchan->bone->segments>1) - b_bone_deform(pchan, pchan->bone, cop); // applies on cop - - Mat4MulVecfl(pchan->chan_mat, cop); + // applies on cop and bbonemat + b_bone_deform(pchan, pchan->bone, cop, (mat)?bbonemat:NULL); + else + Mat4MulVecfl(pchan->chan_mat, cop); vec[0]+=(cop[0]-co[0])*weight; vec[1]+=(cop[1]-co[1])*weight; vec[2]+=(cop[2]-co[2])*weight; + if(mat) + pchan_deform_mat_add(pchan, weight, bbonemat, mat); + (*contrib)+=weight; } void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts, int deformflag, - const char *defgrp_name) + float (*vertexCos)[3], float (*defMats)[3][3], + int numVerts, int deformflag, const char *defgrp_name) { bPoseChannel *pchan, **defnrToPC = NULL; MDeformVert *dverts = NULL; @@ -669,12 +702,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, /* bone defmats are already in the channels, chan_mat */ - /* initialize B_bone matrices */ - for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { + /* initialize B_bone matrices and dual quaternions */ + for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) if(!(pchan->bone->flag & BONE_NO_DEFORM)) if(pchan->bone->segments > 1) pchan_b_bone_defmats(pchan); - } /* get the def_nr for the overall armature vertex group if present */ for(i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) @@ -723,6 +755,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, for(i = 0; i < numVerts; i++) { MDeformVert *dvert; float *co = vertexCos[i]; + float summat[3][3], (*smat)[3] = NULL; float vec[3]; float contrib = 0.0f; float armature_weight = 1.0f; /* default to 1 if no overall def group */ @@ -730,6 +763,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, vec[0] = vec[1] = vec[2] = 0.0f; + if(defMats) { + Mat3Clr((float*)summat); + smat = summat; + } + if(use_dverts || armature_def_nr >= 0) { if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); else if(dverts && i < target_totvert) dvert = dverts + i; @@ -772,7 +810,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, bone->rad_tail, bone->dist); } - pchan_bone_deform(pchan, weight, vec, co, &contrib); + pchan_bone_deform(pchan, weight, vec, smat, co, &contrib); } } /* if there are vertexgroups but not groups with bones @@ -782,7 +820,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { if(!(pchan->bone->flag & BONE_NO_DEFORM)) - contrib += dist_bone_deform(pchan, vec, co); + contrib += dist_bone_deform(pchan, vec, smat, co); } } } @@ -790,15 +828,31 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { if(!(pchan->bone->flag & BONE_NO_DEFORM)) - contrib += dist_bone_deform(pchan, vec, co); + contrib += dist_bone_deform(pchan, vec, smat, co); } } /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */ if(contrib > 0.0001f) { - VecMulf(vec, armature_weight / contrib); + float scale = armature_weight/contrib; + + VecMulf(vec, scale); VecAddf(co, vec, co); + + if(defMats) { + float pre[3][3], post[3][3], tmpmat[3][3]; + + Mat3CpyMat4(pre, premat); + Mat3CpyMat4(post, postmat); + Mat3CpyMat3(tmpmat, defMats[i]); + + Mat3MulFloat((float*)smat, scale); + Mat3MulSerie(defMats[i], tmpmat, pre, smat, post, + NULL, NULL, NULL, NULL); + } + } + /* always, check above code */ Mat4MulVecfl(postmat, co); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index dd65eba0df9..d6fa8d1d3d6 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -4577,8 +4577,8 @@ static void armatureModifier_deformVerts( { ArmatureModifierData *amd = (ArmatureModifierData*) md; - armature_deform_verts(amd->object, ob, derivedData, vertexCos, numVerts, - amd->deformflag, amd->defgrp_name); + armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL, + numVerts, amd->deformflag, amd->defgrp_name); } static void armatureModifier_deformVertsEM( @@ -4590,7 +4590,23 @@ static void armatureModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); - armature_deform_verts(amd->object, ob, dm, vertexCos, numVerts, + armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts, + amd->deformflag, amd->defgrp_name); + + if(!derivedData) dm->release(dm); +} + +static void armatureModifier_deformMatricesEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts) +{ + ArmatureModifierData *amd = (ArmatureModifierData*) md; + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts, amd->deformflag, amd->defgrp_name); if(!derivedData) dm->release(dm); @@ -5067,6 +5083,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->updateDepgraph = armatureModifier_updateDepgraph; mti->deformVerts = armatureModifier_deformVerts; mti->deformVertsEM = armatureModifier_deformVertsEM; + mti->deformMatricesEM = armatureModifier_deformMatricesEM; mti = INIT_TYPE(Hook); mti->type = eModifierTypeType_OnlyDeform; @@ -5268,6 +5285,7 @@ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r) if (!(md->mode & eModifierMode_Editmode)) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; + if (md->mode & eModifierMode_DisableTemporary) continue; if (!modifier_supportsMapping(md)) break; @@ -5447,20 +5465,26 @@ int modifiers_usesArmature(Object *ob, bArmature *arm) return 0; } +int modifier_isDeformer(ModifierData *md) +{ + if (md->type==eModifierType_Armature) + return 1; + if (md->type==eModifierType_Curve) + return 1; + if (md->type==eModifierType_Lattice) + return 1; + + return 0; +} + int modifiers_isDeformed(Object *ob) { ModifierData *md = modifiers_getVirtualModifierList(ob); for (; md; md=md->next) { if(ob==G.obedit && (md->mode & eModifierMode_Editmode)==0); - else { - if (md->type==eModifierType_Armature) - return 1; - if (md->type==eModifierType_Curve) - return 1; - if (md->type==eModifierType_Lattice) - return 1; - } + else if(modifier_isDeformer(md)) + return 1; } return 0; } -- cgit v1.2.3