[Bf-committers] [Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11450] trunk/blender/source/blender:

Emmanuel Stone emmanuel.stone at gmail.com
Wed Aug 1 19:32:59 CEST 2007


I know the team in TCD that wrote this paper, so I let them know
Blender is now using it.
They were pleased, and even put it on their website:

http://gv2.cs.tcd.ie/

-emmanuel

On 7/31/07, Brecht Van Lommel <brechtvanlommel at pandora.be> wrote:
> Revision: 11450
>           http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11450
> Author:   blendix
> Date:     2007-07-31 21:28:52 +0200 (Tue, 31 Jul 2007)
>
> Log Message:
> -----------
>
> Quaternion Deform Interpolation
> ===============================
>
> This is a new armature deform interpolation method using Dual Quaternions,
> which reduces the artifacts of linear blend skinning:
>
> http://www.blender.org/development/current-projects/changes-since-244/skinning/
>
> Based on the paper and provided code:
>
> Skinning with Dual Quaternions
> Ladislav Kavan, Steven Collins, Jiri Zara, Carol O'Sullivan.
> Symposium on Interactive 3D Graphics and Games, 2007.
>
> Modified Paths:
> --------------
>     trunk/blender/source/blender/blenkernel/intern/armature.c
>     trunk/blender/source/blender/blenlib/BLI_arithb.h
>     trunk/blender/source/blender/blenlib/intern/arithb.c
>     trunk/blender/source/blender/makesdna/DNA_action_types.h
>     trunk/blender/source/blender/makesdna/DNA_armature_types.h
>     trunk/blender/source/blender/src/buttons_editing.c
>
> Modified: trunk/blender/source/blender/blenkernel/intern/armature.c
> ===================================================================
> --- trunk/blender/source/blender/blenkernel/intern/armature.c   2007-07-31 17:45:26 UTC (rev 11449)
> +++ trunk/blender/source/blender/blenkernel/intern/armature.c   2007-07-31 19:28:52 UTC (rev 11450)
> @@ -499,11 +499,12 @@
>
>  /* ************ Armature Deform ******************* */
>
> -static void pchan_b_bone_defmats(bPoseChannel *pchan)
> +static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion)
>  {
>         Bone *bone= pchan->bone;
>         Mat4 *b_bone= b_bone_spline_setup(pchan);
>         Mat4 *b_bone_mats;
> +       DualQuat *b_bone_dual_quats= NULL;
>         float tmat[4][4];
>         int a;
>
> @@ -511,6 +512,11 @@
>         b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
>         pchan->b_bone_mats= b_bone_mats;
>
> +       if(use_quaternion) {
> +               b_bone_dual_quats= MEM_mallocN((bone->segments)*sizeof(DualQuat), "BBone dqs");
> +               pchan->b_bone_dual_quats= b_bone_dual_quats;
> +       }
> +
>         /* 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);
> @@ -527,10 +533,13 @@
>
>                 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);
> +
> +               if(use_quaternion)
> +                       Mat4ToDQuat(bone->arm_mat, b_bone_mats[a+1].mat, &b_bone_dual_quats[a]);
>         }
>  }
>
> -static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, float defmat[][3])
> +static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *dq, float defmat[][3])
>  {
>         Mat4 *b_bone= pchan->b_bone_mats;
>         float (*mat)[4]= b_bone[0].mat;
> @@ -548,10 +557,15 @@
>            straight joints in restpos. */
>         CLAMP(a, 0, bone->segments-1);
>
> -       Mat4MulVecfl(b_bone[a+1].mat, co);
> +       if(dq) {
> +               DQuatCpyDQuat(dq, &((DualQuat*)pchan->b_bone_dual_quats)[a]);
> +       }
> +       else {
> +               Mat4MulVecfl(b_bone[a+1].mat, co);
>
> -       if(defmat)
> -               Mat3CpyMat4(defmat, b_bone[a+1].mat);
> +               if(defmat)
> +                       Mat3CpyMat4(defmat, b_bone[a+1].mat);
> +       }
>  }
>
>  /* using vec with dist to bone b1 - b2 */
> @@ -618,11 +632,12 @@
>         Mat3AddMat3(mat, mat, wmat);
>  }
>
> -static float dist_bone_deform(bPoseChannel *pchan, float *vec, float mat[][3], float *co)
> +static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, float mat[][3], float *co)
>  {
>         Bone *bone= pchan->bone;
>         float fac, contrib=0.0;
>         float cop[3], bbonemat[3][3];
> +       DualQuat bbonedq;
>
>         if(bone==NULL) return 0.0f;
>
> @@ -635,46 +650,67 @@
>                 fac*=bone->weight;
>                 contrib= fac;
>                 if(contrib>0.0) {
> -                       if(bone->segments>1)
> -                               // applies on cop and bbonemat
> -                               b_bone_deform(pchan, bone, cop, (mat)?bbonemat:NULL);
> -                       else
> -                               Mat4MulVecfl(pchan->chan_mat, cop);
> +                       if(vec) {
> +                               if(bone->segments>1)
> +                                       // applies on cop and bbonemat
> +                                       b_bone_deform(pchan, bone, cop, NULL, (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);
> +                               //      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);
> +                               if(mat)
> +                                       pchan_deform_mat_add(pchan, fac, bbonemat, mat);
> +                       }
> +                       else {
> +                               if(bone->segments>1) {
> +                                       b_bone_deform(pchan, bone, cop, &bbonedq, NULL);
> +                                       DQuatAddWeighted(dq, &bbonedq, fac);
> +                               }
> +                               else
> +                                       DQuatAddWeighted(dq, pchan->dual_quat, fac);
> +                       }
>                 }
>         }
>
>         return contrib;
>  }
>
> -static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, float mat[][3], float *co, float *contrib)
> +static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib)
>  {
>         float cop[3], bbonemat[3][3];
> +       DualQuat bbonedq;
>
>         if (!weight)
>                 return;
>
>         VECCOPY(cop, co);
>
> -       if(pchan->bone->segments>1)
> -               // 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(vec) {
> +               if(pchan->bone->segments>1)
> +                       // applies on cop and bbonemat
> +                       b_bone_deform(pchan, pchan->bone, cop, NULL, (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);
> +               if(mat)
> +                       pchan_deform_mat_add(pchan, weight, bbonemat, mat);
> +       }
> +       else {
> +               if(pchan->bone->segments>1) {
> +                       b_bone_deform(pchan, pchan->bone, cop, &bbonedq, NULL);
> +                       DQuatAddWeighted(dq, &bbonedq, weight);
> +               }
> +               else
> +                       DQuatAddWeighted(dq, pchan->dual_quat, weight);
> +       }
>
>         (*contrib)+=weight;
>  }
> @@ -686,12 +722,15 @@
>         bPoseChannel *pchan, **defnrToPC = NULL;
>         MDeformVert *dverts = NULL;
>         bDeformGroup *dg;
> +       DualQuat *dualquats= NULL;
>         float obinv[4][4], premat[4][4], postmat[4][4];
>         int use_envelope = deformflag & ARM_DEF_ENVELOPE;
> +       int use_quaternion = deformflag & ARM_DEF_QUATERNION;
>         int numGroups = 0;              /* safety for vertexgroup index overflow */
>         int i, target_totvert = 0;      /* safety for vertexgroup overflow */
>         int use_dverts = 0;
>         int armature_def_nr = -1;
> +       int totchan;
>
>         if(armOb == G.obedit) return;
>
> @@ -703,11 +742,24 @@
>         /* bone defmats are already in the channels, chan_mat */
>
>         /* 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(use_quaternion) {
> +               totchan= BLI_countlist(&armOb->pose->chanbase);
> +               dualquats= MEM_callocN(sizeof(DualQuat)*totchan, "dualquats");
> +       }
> +
> +       totchan= 0;
> +       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);
> +                               pchan_b_bone_defmats(pchan, use_quaternion);
>
> +                       if(use_quaternion) {
> +                               pchan->dual_quat= &dualquats[totchan++];
> +                               Mat4ToDQuat(pchan->bone->arm_mat, pchan->chan_mat, pchan->dual_quat);
> +                       }
> +               }
> +       }
> +
>         /* get the def_nr for the overall armature vertex group if present */
>         for(i = 0, dg = target->defbase.first; dg; i++, dg = dg->next)
>                 if(defgrp_name && strcmp(defgrp_name, dg->name) == 0)
> @@ -754,18 +806,26 @@
>
>         for(i = 0; i < numVerts; i++) {
>                 MDeformVert *dvert;
> +               DualQuat sumdq, *dq = NULL;
>                 float *co = vertexCos[i];
> -               float summat[3][3], (*smat)[3] = NULL;
> -               float vec[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 */
>                 int       j;
>
> -               vec[0] = vec[1] = vec[2] = 0.0f;
> +               if(use_quaternion) {
> +                       memset(&sumdq, 0, sizeof(DualQuat));
> +                       dq= &sumdq;
> +               }
> +               else {
> +                       sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
> +                       vec= sumvec;
>
> -               if(defMats) {
> -                       Mat3Clr((float*)summat);
> -                       smat = summat;
> +                       if(defMats) {
> +                               Mat3Clr((float*)summat);
> +                               smat = summat;
> +                       }
>                 }
>
>                 if(use_dverts || armature_def_nr >= 0) {
> @@ -810,7 +870,7 @@
>                                                                              bone->rad_tail,
>                                                                              bone->dist);
>                                         }
> -                                       pchan_bone_deform(pchan, weight, vec, smat, co, &contrib);
> +                                       pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
>                                 }
>                         }
>                         /* if there are vertexgroups but not groups with bones
> @@ -820,7 +880,7 @@
>                                 for(pchan = armOb->pose->chanbase.first; pchan;
>                                     pchan = pchan->next) {
>                                         if(!(pchan->bone->flag & BONE_NO_DEFORM))
> -                                               contrib += dist_bone_deform(pchan, vec, smat, co);
> +                                               contrib += dist_bone_deform(pchan, vec, dq, smat, co);
>                                 }
>                         }
>                 }
> @@ -828,17 +888,22 @@
>                         for(pchan = armOb->pose->chanbase.first; pchan;
>                             pchan = pchan->next) {
>                                 if(!(pchan->bone->flag & BONE_NO_DEFORM))
> -                                       contrib += dist_bone_deform(pchan, vec, 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 */
>                 if(contrib > 0.0001f) {
> -                       float scale = armature_weight/contrib;
> +                       if(use_quaternion) {
> +                               DQuatNormalize(dq, contrib, armature_weight);
> +                               DQuatMulVecfl(dq, co, (defMats)? summat: NULL);
> +                               smat = summat;
> +                       }
> +                       else {
> +                               VecMulf(vec, armature_weight/contrib);
> +                               VecAddf(co, vec, co);
> +                       }
>
> -                       VecMulf(vec, scale);
> -                       VecAddf(co, vec, co);
> -
>                         if(defMats) {
>                                 float pre[3][3], post[3][3], tmpmat[3][3];
>
> @@ -846,17 +911,19 @@
>                                 Mat3CpyMat4(post, postmat);
>                                 Mat3CpyMat3(tmpmat, defMats[i]);
>
> -                               Mat3MulFloat((float*)smat, scale);
> +                               if(!use_quaternion) /* quaternion already is scale corrected */
> +                                       Mat3MulFloat((float*)smat, armature_weight/contrib);
> +
>                                 Mat3MulSerie(defMats[i], tmpmat, pre, smat, post,
>                                         NULL, NULL, NULL, NULL);
>                         }
> -
>                 }
>
>                 /* always, check above code */
>                 Mat4MulVecfl(postmat, co);
>         }
>
> +       if(dualquats) MEM_freeN(dualquats);
>         if(defnrToPC) MEM_freeN(defnrToPC);
>
>         /* free B_bone matrices */
> @@ -865,6 +932,12 @@
>                         MEM_freeN(pchan->b_bone_mats);
>                         pchan->b_bone_mats = NULL;
>                 }
> +               if(pchan->b_bone_dual_quats) {
> +                       MEM_freeN(pchan->b_bone_dual_quats);
> +                       pchan->b_bone_dual_quats = NULL;
> +               }
> +
> +               pchan->dual_quat = NULL;
>         }
>  }
>
>
> Modified: trunk/blender/source/blender/blenlib/BLI_arithb.h
> ===================================================================
> --- trunk/blender/source/blender/blenlib/BLI_arithb.h   2007-07-31 17:45:26 UTC (rev 11449)
> +++ trunk/blender/source/blender/blenlib/BLI_arithb.h   2007-07-31 19:28:52 UTC (rev 11450)
> @@ -128,6 +128,7 @@
>  void QuatInv(float *q);
>  void QuatMulf(float *q, float f);
>  float QuatDot(float *q1, float *q2);
> +void QuatCopy(float *q1, float *q2);
>
>  void printquat(char *str, float q[4]);
>
> @@ -353,6 +354,21 @@
>  int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda);
>  int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3]);
>
> +typedef struct DualQuat {
> +       float quat[4];
> +       float trans[4];
> +
> +       float scale[4][4];
> +       float scale_weight;
> +} DualQuat;
> +
> +void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq);
> +void DQuatToMat4(DualQuat *dq, float mat[][4]);
> +void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight);
>
> @@ Diff output truncated at 10240 characters. @@
>
> _______________________________________________
> Bf-blender-cvs mailing list
> Bf-blender-cvs at blender.org
> http://lists.blender.org/mailman/listinfo/bf-blender-cvs
>


More information about the Bf-committers mailing list