Mesh Deform Modifier

====================

Dynamic binding support. This means that the mesh can move _within_
the cage and still deform correct. If the mesh goes out of the cage,
don't expect correct result. Must be enabled with the 'Dynamic'
option, because it is slower and consumes more memory.

This is useful to use e.g. the cage mesh for main deformations and
still have shape keys for facial deformation working.
This commit is contained in:
2007-11-11 22:54:14 +00:00
parent 828eba4842
commit 7f2e43968a
6 changed files with 222 additions and 55 deletions

View File

@@ -4935,8 +4935,11 @@ static void meshdeformModifier_freeData(ModifierData *md)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
if (mmd->bindweights) MEM_freeN(mmd->bindweights);
if (mmd->bindcos) MEM_freeN(mmd->bindcos);
if(mmd->bindweights) MEM_freeN(mmd->bindweights);
if(mmd->bindcos) MEM_freeN(mmd->bindcos);
if(mmd->dyngrid) MEM_freeN(mmd->dyngrid);
if(mmd->dyninfluences) MEM_freeN(mmd->dyninfluences);
if(mmd->dynverts) MEM_freeN(mmd->dynverts);
}
static void meshdeformModifier_copyData(ModifierData *md, ModifierData *target)
@@ -4990,12 +4993,64 @@ static void meshdeformModifier_updateDepgraph(
}
}
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float *vec)
{
MDefCell *cell;
MDefInfluence *inf;
float gridvec[3], dvec[3], ivec[3], co[3], wx, wy, wz;
float weight, cageweight, totweight, *cageco;
int i, j, a, x, y, z, size;
co[0]= co[1]= co[2]= 0.0f;
totweight= 0.0f;
size= mmd->dyngridsize;
for(i=0; i<3; i++) {
gridvec[i]= (vec[i] - mmd->dyncellmin[i] - mmd->dyncellwidth*0.5f)/mmd->dyncellwidth;
ivec[i]= (int)gridvec[i];
dvec[i]= gridvec[i] - ivec[i];
}
for(i=0; i<8; i++) {
if(i & 1) { x= ivec[0]+1; wx= dvec[0]; }
else { x= ivec[0]; wx= 1.0f-dvec[0]; }
if(i & 2) { y= ivec[1]+1; wy= dvec[1]; }
else { y= ivec[1]; wy= 1.0f-dvec[1]; }
if(i & 4) { z= ivec[2]+1; wz= dvec[2]; }
else { z= ivec[2]; wz= 1.0f-dvec[2]; }
CLAMP(x, 0, size-1);
CLAMP(y, 0, size-1);
CLAMP(z, 0, size-1);
a= x + y*size + z*size*size;
weight= wx*wy*wz;
cell= &mmd->dyngrid[a];
inf= mmd->dyninfluences + cell->offset;
for(j=0; j<cell->totinfluence; j++, inf++) {
cageco= dco[inf->vertex];
cageweight= weight*inf->weight;
co[0] += cageweight*cageco[0];
co[1] += cageweight*cageco[1];
co[2] += cageweight*cageco[2];
totweight += cageweight;
}
}
VECCOPY(vec, co);
return totweight;
}
static void meshdeformModifier_do(
ModifierData *md, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
float imat[4][4], cagemat[4][4], icagemat[4][4], icmat[3][3];
float imat[4][4], cagemat[4][4], icagemat[4][4], iobmat[3][3];
float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3];
int a, b, totvert, totcagevert, defgrp_index;
DerivedMesh *tmpdm, *cagedm;
@@ -5003,7 +5058,7 @@ static void meshdeformModifier_do(
MDeformWeight *dw;
MVert *cagemvert;
if(!mmd->object || (!mmd->bindweights && !mmd->needbind))
if(!mmd->object || (!mmd->bindcos && !mmd->needbind))
return;
/* get cage derivedmesh */
@@ -5020,20 +5075,21 @@ static void meshdeformModifier_do(
return;
/* compute matrices to go in and out of cage object space */
Mat4Invert(imat, mmd->object->obmat);
Mat4Invert(imat, (mmd->bindcos)? mmd->bindmat: mmd->object->obmat);
Mat4MulMat4(cagemat, ob->obmat, imat);
Mat4Invert(icagemat, cagemat);
Mat3CpyMat4(icmat, icagemat);
Mat4Invert(imat, ob->obmat);
Mat3CpyMat4(iobmat, imat);
/* bind weights if needed */
if(!mmd->bindweights)
if(!mmd->bindcos)
harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat);
/* verify we have compatible weights */
totvert= numVerts;
totcagevert= cagedm->getNumVerts(cagedm);
if(mmd->totvert!=totvert || mmd->totcagevert!=totcagevert || !mmd->bindweights) {
if(mmd->totvert!=totvert || mmd->totcagevert!=totcagevert || !mmd->bindcos) {
cagedm->release(cagedm);
return;
}
@@ -5070,6 +5126,10 @@ static void meshdeformModifier_do(
fac= 1.0f;
for(b=0; b<totvert; b++) {
if(mmd->flag & MOD_MDEF_DYNAMIC_BIND)
if(!mmd->dynverts[b])
continue;
if(dvert) {
for(dw=NULL, a=0; a<dvert[b].totweight; a++) {
if(dvert[b].dw[a].def_nr == defgrp_index) {
@@ -5089,20 +5149,27 @@ static void meshdeformModifier_do(
}
}
totweight= 0.0f;
co[0]= co[1]= co[2]= 0.0f;
if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
VECCOPY(co, vertexCos[b]);
Mat4MulVecfl(cagemat, co);
totweight= meshdeform_dynamic_bind(mmd, dco, co);
}
else {
totweight= 0.0f;
co[0]= co[1]= co[2]= 0.0f;
for(a=0; a<totcagevert; a++) {
weight= weights[a + b*totcagevert];
co[0]+= weight*dco[a][0];
co[1]+= weight*dco[a][1];
co[2]+= weight*dco[a][2];
totweight += weight;
for(a=0; a<totcagevert; a++) {
weight= weights[a + b*totcagevert];
co[0]+= weight*dco[a][0];
co[1]+= weight*dco[a][1];
co[2]+= weight*dco[a][2];
totweight += weight;
}
}
if(totweight > 0.0f) {
VecMulf(co, fac/totweight);
Mat3MulVecfl(icmat, co);
Mat3MulVecfl(iobmat, co);
VECADD(vertexCos[b], vertexCos[b], co);
}
}

View File

@@ -2894,6 +2894,9 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
mmd->bindweights= newdataadr(fd, mmd->bindweights);
mmd->bindcos= newdataadr(fd, mmd->bindcos);
mmd->dyngrid= newdataadr(fd, mmd->dyngrid);
mmd->dyninfluences= newdataadr(fd, mmd->dyninfluences);
mmd->dynverts= newdataadr(fd, mmd->dynverts);
if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
int a;
@@ -2902,6 +2905,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
SWITCH_INT(mmd->bindweights[a])
for(a=0; a<mmd->totcagevert*3; a++)
SWITCH_INT(mmd->bindcos[a])
for(a=0; a<mmd->totvert; a++)
SWITCH_INT(mmd->dynverts[a])
}
}
}

View File

@@ -787,11 +787,16 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
}
else if (md->type==eModifierType_MeshDeform) {
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
int size = mmd->dyngridsize;
writedata(wd, DATA, sizeof(float)*mmd->totvert*mmd->totcagevert,
mmd->bindweights);
writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert,
mmd->bindcos);
writedata(wd, DATA, sizeof(MDefCell)*size*size*size, mmd->dyngrid);
writedata(wd, DATA, sizeof(MDefInfluence)*mmd->totinfluence,
mmd->dyninfluences);
writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts);
}
}
}

View File

@@ -349,6 +349,17 @@ typedef struct BooleanModifierData {
} BooleanModifierData;
#define MOD_MDEF_INVERT_VGROUP (1<<0)
#define MOD_MDEF_DYNAMIC_BIND (1<<1)
typedef struct MDefInfluence {
int vertex;
float weight;
} MDefInfluence;
typedef struct MDefCell {
int offset;
int totinfluence;
} MDefCell;
typedef struct MeshDeformModifierData {
ModifierData modifier;
@@ -356,11 +367,20 @@ typedef struct MeshDeformModifierData {
struct Object *object; /* mesh object */
char defgrp_name[32]; /* optional vertexgroup name */
float *bindweights, *bindcos; /* computed binding weights */
short gridsize, needbind;
short flag, pad;
int totvert, totcagevert;
/* variables filled in when bound */
float *bindweights, *bindcos; /* computed binding weights */
int totvert, totcagevert; /* total vertices in mesh and cage */
MDefCell *dyngrid; /* grid with dynamic binding cell points */
MDefInfluence *dyninfluences; /* dynamic binding vertex influences */
int *dynverts, *pad2; /* is this vertex bound or not? */
int dyngridsize; /* size of the dynamic bind grid */
int totinfluence; /* total number of vertex influences */
float dyncellmin[3]; /* offset of the dynamic bind grid */
float dyncellwidth; /* width of dynamic bind cell */
float bindmat[4][4]; /* matrix of cage at binding time */
} MeshDeformModifierData;
#endif

View File

@@ -1470,13 +1470,20 @@ static void modifiers_bindMeshDeform(void *ob_v, void *md_v)
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md_v;
Object *ob = (Object*)ob_v;
if(mmd->bindweights) {
MEM_freeN(mmd->bindweights);
MEM_freeN(mmd->bindcos);
if(mmd->bindcos) {
if(mmd->bindweights) MEM_freeN(mmd->bindweights);
if(mmd->bindcos) MEM_freeN(mmd->bindcos);
if(mmd->dyngrid) MEM_freeN(mmd->dyngrid);
if(mmd->dyninfluences) MEM_freeN(mmd->dyninfluences);
if(mmd->dynverts) MEM_freeN(mmd->dynverts);
mmd->bindweights= NULL;
mmd->bindcos= NULL;
mmd->dyngrid= NULL;
mmd->dyninfluences= NULL;
mmd->dynverts= NULL;
mmd->totvert= 0;
mmd->totcagevert= 0;
mmd->totinfluence= 0;
}
else {
DerivedMesh *dm;
@@ -1640,7 +1647,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
} else if (md->type==eModifierType_Array) {
height = 211;
} else if (md->type==eModifierType_MeshDeform) {
height = 73;
MeshDeformModifierData *mmd= (MeshDeformModifierData*)md;
height = (mmd->bindcos)? 73: 93;
}
/* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
@@ -2130,14 +2138,15 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
uiDefButBitS(block, TOG, MOD_MDEF_INVERT_VGROUP, B_MODIFIER_RECALC, "Inv", lx+buttonWidth-40, (cy-=19), 40,19, &mmd->flag, 0.0, 31.0, 0, 0, "Invert vertex group influence");
uiBlockBeginAlign(block);
if(mmd->bindweights) {
but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Unbind", lx,(cy-24), buttonWidth,19, 0, 0, 0, 0, 0, "Unbind mesh from cage");
if(mmd->bindcos) {
but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Unbind", lx,(cy-=24), buttonWidth,19, 0, 0, 0, 0, 0, "Unbind mesh from cage");
uiButSetFunc(but,modifiers_bindMeshDeform,ob,md);
}
else {
but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Bind", lx,(cy-24), buttonWidth/2,19, 0, 0, 0, 0, 0, "Bind mesh to cage");
but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Bind", lx,(cy-=24), buttonWidth,19, 0, 0, 0, 0, 0, "Bind mesh to cage");
uiButSetFunc(but,modifiers_bindMeshDeform,ob,md);
uiDefButS(block, NUM, B_NOP, "Precision:", lx+(buttonWidth+1)/2,(cy-=24), buttonWidth/2,19, &mmd->gridsize, 2, 10, 0.5, 0, "The grid size for binding");
uiDefButS(block, NUM, B_NOP, "Precision:", lx,(cy-19), buttonWidth/2 + 20,19, &mmd->gridsize, 2, 10, 0.5, 0, "The grid size for binding");
uiDefButBitS(block, TOG, MOD_MDEF_DYNAMIC_BIND, B_MODIFIER_RECALC, "Dynamic", lx+(buttonWidth+1)/2 + 20, (cy-=19), buttonWidth/2 - 20,19, &mmd->flag, 0.0, 31.0, 0, 0, "Invert vertex group influence");
}
uiBlockEndAlign(block);
}

View File

@@ -805,11 +805,8 @@ void rigid_deform_iteration()
laplacian_begin_solve(sys, i);
for(a=0; a<sys->totvert; a++)
if(!sys->vpinned[a]) {
/*if (i==0)
printf("rhs %f\n", sys->rigid.rhs[a][0]);*/
if(!sys->vpinned[a])
laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]);
}
if(laplacian_system_solve(sys)) {
for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
@@ -823,8 +820,6 @@ void rigid_deform_iteration()
break;
}
}
/*printf("\n--------------------------------------------\n\n");*/
}
static void rigid_laplacian_create(LaplacianSystem *sys)
@@ -926,6 +921,8 @@ void rigid_deform_end(int cancel)
#define MESHDEFORM_LEN_THRESHOLD 1e-6
#define MESHDEFORM_MIN_INFLUENCE 0.005
static int MESHDEFORM_OFFSET[7][3] =
{{0,0,0}, {1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}};
@@ -935,6 +932,12 @@ typedef struct MDefBoundIsect {
float len;
} MDefBoundIsect;
typedef struct MDefBindInfluence {
struct MDefBindInfluence *next;
float weight;
int vertex;
} MDefBindInfluence;
typedef struct MeshDeformBind {
/* grid dimensions */
float min[3], max[3];
@@ -957,6 +960,7 @@ typedef struct MeshDeformBind {
/* mesh stuff */
int *inside;
float *weights;
MDefBindInfluence **dyngrid;
float cagemat[4][4];
/* direct solver */
@@ -1594,16 +1598,32 @@ static void meshdeform_matrix_solve(MeshDeformBind *mdb)
mdb->totalphi[b] += mdb->phi[b];
}
/* compute weights for each vertex */
for(b=0; b<mdb->totvert; b++) {
if(mdb->inside[b]) {
VECCOPY(vec, mdb->vertexcos[b]);
Mat4MulVecfl(mdb->cagemat, vec);
gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0];
gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1];
gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2];
if(mdb->weights) {
/* static bind : compute weights for each vertex */
for(b=0; b<mdb->totvert; b++) {
if(mdb->inside[b]) {
VECCOPY(vec, mdb->vertexcos[b]);
Mat4MulVecfl(mdb->cagemat, vec);
gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0];
gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1];
gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2];
mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a);
mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a);
}
}
}
else {
MDefBindInfluence *inf;
/* dynamic bind */
for(b=0; b<mdb->size3; b++) {
if(mdb->phi[b] >= 0.0f) { //MESHDEFORM_MIN_INFLUENCE) {
inf= BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
inf->vertex= a;
inf->weight= mdb->phi[b];
inf->next= mdb->dyngrid[b];
mdb->dyngrid[b]= inf;
}
}
}
}
@@ -1634,21 +1654,16 @@ static void meshdeform_matrix_solve(MeshDeformBind *mdb)
void harmonic_coordinates_bind(MeshDeformModifierData *mmd, float (*vertexcos)[3], int totvert, float cagemat[][4])
{
MeshDeformBind mdb;
MDefBindInfluence *inf;
MDefInfluence *mdinf;
MDefCell *cell;
MVert *mvert;
float center[3], vec[3], maxwidth;
int a, x, y, z, totinside;
float center[3], vec[3], maxwidth, totweight;
int a, b, x, y, z, totinside, offset;
waitcursor(1);
start_progress_bar();
/* free exisiting weights */
if(mmd->bindweights) {
MEM_freeN(mmd->bindweights);
MEM_freeN(mmd->bindcos);
mmd->bindweights= NULL;
mmd->bindcos= NULL;
}
memset(&mdb, 0, sizeof(MeshDeformBind));
/* get mesh and cage mesh */
@@ -1679,9 +1694,13 @@ void harmonic_coordinates_bind(MeshDeformModifierData *mmd, float (*vertexcos)[3
mdb.boundisect= MEM_callocN(sizeof(*mdb.boundisect)*mdb.size3, "MDefBoundIsect");
mdb.semibound= MEM_callocN(sizeof(int)*mdb.size3, "MDefSemiBound");
mdb.weights= MEM_callocN(sizeof(float)*mdb.totvert*mdb.totcagevert, "MDefWeights");
mdb.inside= MEM_callocN(sizeof(int)*mdb.totvert, "MDefInside");
if(mmd->flag & MOD_MDEF_DYNAMIC_BIND)
mdb.dyngrid= MEM_callocN(sizeof(MDefBindInfluence*)*mdb.size3, "MDefDynGrid");
else
mdb.weights= MEM_callocN(sizeof(float)*mdb.totvert*mdb.totcagevert, "MDefWeights");
mdb.memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
BLI_memarena_use_calloc(mdb.memarena);
@@ -1752,10 +1771,53 @@ void harmonic_coordinates_bind(MeshDeformModifierData *mmd, float (*vertexcos)[3
meshdeform_matrix_solve(&mdb);
/* assign results */
mmd->bindweights= mdb.weights;
mmd->bindcos= (float*)mdb.cagecos;
mmd->totvert= mdb.totvert;
mmd->totcagevert= mdb.totcagevert;
Mat4CpyMat4(mmd->bindmat, mmd->object->obmat);
if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
mmd->totinfluence= 0;
for(a=0; a<mdb.size3; a++)
for(inf=mdb.dyngrid[a]; inf; inf=inf->next)
mmd->totinfluence++;
/* convert MDefBindInfluences to smaller MDefInfluences */
mmd->dyngrid= MEM_callocN(sizeof(MDefCell)*mdb.size3, "MDefDynGrid");
mmd->dyninfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefInfluence");
offset= 0;
for(a=0; a<mdb.size3; a++) {
cell= &mmd->dyngrid[a];
cell->offset= offset;
totweight= 0.0f;
mdinf= mmd->dyninfluences + cell->offset;
for(inf=mdb.dyngrid[a]; inf; inf=inf->next, mdinf++) {
mdinf->weight= inf->weight;
mdinf->vertex= inf->vertex;
totweight += mdinf->weight;
cell->totinfluence++;
}
if(totweight > 0.0f) {
mdinf= mmd->dyninfluences + cell->offset;
for(b=0; b<cell->totinfluence; b++, mdinf++)
mdinf->weight /= totweight;
}
offset += cell->totinfluence;
}
mmd->dynverts= mdb.inside;
mmd->dyngridsize= mdb.size;
VECCOPY(mmd->dyncellmin, mdb.min);
mmd->dyncellwidth= mdb.width[0];
MEM_freeN(mdb.dyngrid);
}
else {
mmd->bindweights= mdb.weights;
MEM_freeN(mdb.inside);
}
/* transform bindcos to world space */
for(a=0; a<mdb.totcagevert; a++)
@@ -1768,7 +1830,6 @@ void harmonic_coordinates_bind(MeshDeformModifierData *mmd, float (*vertexcos)[3
MEM_freeN(mdb.totalphi);
MEM_freeN(mdb.boundisect);
MEM_freeN(mdb.semibound);
MEM_freeN(mdb.inside);
BLI_memarena_free(mdb.memarena);
end_progress_bar();