[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