Blender V2.61 - r43446

MOD_meshdeform.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software  Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Daniel Dunbar
00022  *                 Ton Roosendaal,
00023  *                 Ben Batt,
00024  *                 Brecht Van Lommel,
00025  *                 Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  *
00029  */
00030 
00036 #include "DNA_meshdata_types.h"
00037 #include "DNA_object_types.h"
00038 
00039 #include "BLI_math.h"
00040 #include "BLI_utildefines.h"
00041 
00042 
00043 #include "BKE_cdderivedmesh.h"
00044 #include "BKE_global.h"
00045 #include "BKE_mesh.h"
00046 #include "BKE_modifier.h"
00047 #include "BKE_deform.h"
00048 
00049 #include "depsgraph_private.h"
00050 
00051 #include "MEM_guardedalloc.h"
00052 
00053 #include "MOD_util.h"
00054 
00055 
00056 static void initData(ModifierData *md)
00057 {
00058     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00059 
00060     mmd->gridsize= 5;
00061 }
00062 
00063 static void freeData(ModifierData *md)
00064 {
00065     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00066 
00067     if(mmd->bindinfluences) MEM_freeN(mmd->bindinfluences);
00068     if(mmd->bindoffsets) MEM_freeN(mmd->bindoffsets);
00069     if(mmd->bindcagecos) MEM_freeN(mmd->bindcagecos);
00070     if(mmd->dyngrid) MEM_freeN(mmd->dyngrid);
00071     if(mmd->dyninfluences) MEM_freeN(mmd->dyninfluences);
00072     if(mmd->dynverts) MEM_freeN(mmd->dynverts);
00073     if(mmd->bindweights) MEM_freeN(mmd->bindweights); /* deprecated */
00074     if(mmd->bindcos) MEM_freeN(mmd->bindcos); /* deprecated */
00075 }
00076 
00077 static void copyData(ModifierData *md, ModifierData *target)
00078 {
00079     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00080     MeshDeformModifierData *tmmd = (MeshDeformModifierData*) target;
00081 
00082     tmmd->gridsize = mmd->gridsize;
00083     tmmd->object = mmd->object;
00084 }
00085 
00086 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
00087 {   
00088     MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
00089     CustomDataMask dataMask = 0;
00090 
00091     /* ask for vertexgroups if we need them */
00092     if(mmd->defgrp_name[0]) dataMask |= CD_MASK_MDEFORMVERT;
00093 
00094     return dataMask;
00095 }
00096 
00097 static int isDisabled(ModifierData *md, int UNUSED(useRenderParams))
00098 {
00099     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00100 
00101     return !mmd->object;
00102 }
00103 
00104 static void foreachObjectLink(
00105         ModifierData *md, Object *ob,
00106   void (*walk)(void *userData, Object *ob, Object **obpoin),
00107      void *userData)
00108 {
00109     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00110 
00111     walk(userData, ob, &mmd->object);
00112 }
00113 
00114 static void updateDepgraph(ModifierData *md, DagForest *forest,
00115                         struct Scene *UNUSED(scene),
00116                         Object *UNUSED(ob),
00117                         DagNode *obNode)
00118 {
00119     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00120 
00121     if (mmd->object) {
00122         DagNode *curNode = dag_get_node(forest, mmd->object);
00123 
00124         dag_add_relation(forest, curNode, obNode,
00125                  DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB,
00126                  "Mesh Deform Modifier");
00127     }
00128 }
00129 
00130 static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float *vec)
00131 {
00132     MDefCell *cell;
00133     MDefInfluence *inf;
00134     float gridvec[3], dvec[3], ivec[3], co[3], wx, wy, wz;
00135     float weight, cageweight, totweight, *cageco;
00136     int i, j, a, x, y, z, size;
00137 
00138     zero_v3(co);
00139     totweight= 0.0f;
00140     size= mmd->dyngridsize;
00141 
00142     for(i=0; i<3; i++) {
00143         gridvec[i]= (vec[i] - mmd->dyncellmin[i] - mmd->dyncellwidth*0.5f)/mmd->dyncellwidth;
00144         ivec[i]= (int)gridvec[i];
00145         dvec[i]= gridvec[i] - ivec[i];
00146     }
00147 
00148     for(i=0; i<8; i++) {
00149         if(i & 1) { x= ivec[0]+1; wx= dvec[0]; }
00150         else { x= ivec[0]; wx= 1.0f-dvec[0]; } 
00151 
00152         if(i & 2) { y= ivec[1]+1; wy= dvec[1]; }
00153         else { y= ivec[1]; wy= 1.0f-dvec[1]; } 
00154 
00155         if(i & 4) { z= ivec[2]+1; wz= dvec[2]; }
00156         else { z= ivec[2]; wz= 1.0f-dvec[2]; } 
00157 
00158         CLAMP(x, 0, size-1);
00159         CLAMP(y, 0, size-1);
00160         CLAMP(z, 0, size-1);
00161 
00162         a= x + y*size + z*size*size;
00163         weight= wx*wy*wz;
00164 
00165         cell= &mmd->dyngrid[a];
00166         inf= mmd->dyninfluences + cell->offset;
00167         for(j=0; j<cell->totinfluence; j++, inf++) {
00168             cageco= dco[inf->vertex];
00169             cageweight= weight*inf->weight;
00170             co[0] += cageweight*cageco[0];
00171             co[1] += cageweight*cageco[1];
00172             co[2] += cageweight*cageco[2];
00173             totweight += cageweight;
00174         }
00175     }
00176 
00177     copy_v3_v3(vec, co);
00178 
00179     return totweight;
00180 }
00181 
00182 static void meshdeformModifier_do(
00183       ModifierData *md, Object *ob, DerivedMesh *dm,
00184       float (*vertexCos)[3], int numVerts)
00185 {
00186     MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
00187     struct Mesh *me= (mmd->object)? mmd->object->data: NULL;
00188     struct EditMesh *em = (me)? BKE_mesh_get_editmesh(me): NULL;
00189     DerivedMesh *tmpdm, *cagedm;
00190     MDeformVert *dvert = NULL;
00191     MDefInfluence *influences;
00192     int *offsets;
00193     float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
00194     float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3];
00195     int a, b, totvert, totcagevert, defgrp_index;
00196     float (*cagecos)[3];
00197 
00198     if(!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc))
00199         return;
00200     
00201     /* get cage derivedmesh */
00202     if(em) {
00203         tmpdm= editmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0);
00204         if(tmpdm)
00205             tmpdm->release(tmpdm);
00206         BKE_mesh_end_editmesh(me, em);
00207     }
00208     else
00209         cagedm= mmd->object->derivedFinal;
00210 
00211     /* if we don't have one computed, use derivedmesh from data
00212      * without any modifiers */
00213     if(!cagedm) {
00214         cagedm= get_dm(mmd->object, NULL, NULL, NULL, 0);
00215         if(cagedm)
00216             cagedm->needsFree= 1;
00217     }
00218     
00219     if(!cagedm) {
00220         modifier_setError(md, "Can't get mesh from cage object.");
00221         return;
00222     }
00223 
00224     /* compute matrices to go in and out of cage object space */
00225     invert_m4_m4(imat, mmd->object->obmat);
00226     mult_m4_m4m4(cagemat, imat, ob->obmat);
00227     mult_m4_m4m4(cmat, mmd->bindmat, cagemat);
00228     invert_m4_m4(iobmat, cmat);
00229     copy_m3_m4(icagemat, iobmat);
00230 
00231     /* bind weights if needed */
00232     if(!mmd->bindcagecos) {
00233         static int recursive = 0;
00234 
00235         /* progress bar redraw can make this recursive .. */
00236         if(!recursive) {
00237             recursive = 1;
00238             mmd->bindfunc(md->scene, mmd, (float*)vertexCos, numVerts, cagemat);
00239             recursive = 0;
00240         }
00241     }
00242 
00243     /* verify we have compatible weights */
00244     totvert= numVerts;
00245     totcagevert= cagedm->getNumVerts(cagedm);
00246 
00247     if(mmd->totvert != totvert) {
00248         modifier_setError(md, "Verts changed from %d to %d.", mmd->totvert, totvert);
00249         cagedm->release(cagedm);
00250         return;
00251     }
00252     else if (mmd->totcagevert != totcagevert) {
00253         modifier_setError(md, "Cage verts changed from %d to %d.", mmd->totcagevert, totcagevert);
00254         cagedm->release(cagedm);
00255         return;
00256     } else if (mmd->bindcagecos == NULL) {
00257         modifier_setError(md, "Bind data missing.");
00258         cagedm->release(cagedm);
00259         return;
00260     }
00261 
00262     cagecos= MEM_callocN(sizeof(*cagecos)*totcagevert, "meshdeformModifier vertCos");
00263 
00264     /* setup deformation data */
00265     cagedm->getVertCos(cagedm, cagecos);
00266     influences= mmd->bindinfluences;
00267     offsets= mmd->bindoffsets;
00268     bindcagecos= (float(*)[3])mmd->bindcagecos;
00269 
00270     dco= MEM_callocN(sizeof(*dco)*totcagevert, "MDefDco");
00271     for(a=0; a<totcagevert; a++) {
00272         /* get cage vertex in world space with binding transform */
00273         copy_v3_v3(co, cagecos[a]);
00274 
00275         if(G.rt != 527) {
00276             mul_m4_v3(mmd->bindmat, co);
00277             /* compute difference with world space bind coord */
00278             sub_v3_v3v3(dco[a], co, bindcagecos[a]);
00279         }
00280         else
00281             copy_v3_v3(dco[a], co);
00282     }
00283 
00284     modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index);
00285 
00286     /* do deformation */
00287     fac= 1.0f;
00288 
00289     for(b=0; b<totvert; b++) {
00290         if(mmd->flag & MOD_MDEF_DYNAMIC_BIND)
00291             if(!mmd->dynverts[b])
00292                 continue;
00293 
00294         if(dvert) {
00295             fac= defvert_find_weight(&dvert[b], defgrp_index);
00296 
00297             if (mmd->flag & MOD_MDEF_INVERT_VGROUP) {
00298                 fac= 1.0f - fac;
00299             }
00300 
00301             if (fac <= 0.0) {
00302                 continue;
00303             }
00304         }
00305 
00306         if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
00307             /* transform coordinate into cage's local space */
00308             mul_v3_m4v3(co, cagemat, vertexCos[b]);
00309             totweight= meshdeform_dynamic_bind(mmd, dco, co);
00310         }
00311         else {
00312             totweight= 0.0f;
00313             zero_v3(co);
00314 
00315             for(a=offsets[b]; a<offsets[b+1]; a++) {
00316                 weight= influences[a].weight;
00317                 madd_v3_v3fl(co, dco[influences[a].vertex], weight);
00318                 totweight += weight;
00319             }
00320         }
00321 
00322         if(totweight > 0.0f) {
00323             mul_v3_fl(co, fac/totweight);
00324             mul_m3_v3(icagemat, co);
00325             if(G.rt != 527)
00326                 add_v3_v3(vertexCos[b], co);
00327             else
00328                 copy_v3_v3(vertexCos[b], co);
00329         }
00330     }
00331 
00332     /* release cage derivedmesh */
00333     MEM_freeN(dco);
00334     MEM_freeN(cagecos);
00335     cagedm->release(cagedm);
00336 }
00337 
00338 static void deformVerts(ModifierData *md, Object *ob,
00339                         DerivedMesh *derivedData,
00340                         float (*vertexCos)[3],
00341                         int numVerts,
00342                         int UNUSED(useRenderParams),
00343                         int UNUSED(isFinalCalc))
00344 {
00345     DerivedMesh *dm= get_dm(ob, NULL, derivedData, NULL, 0);
00346 
00347     modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
00348     
00349     meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
00350 
00351     if(dm && dm != derivedData)
00352         dm->release(dm);
00353 }
00354 
00355 static void deformVertsEM(ModifierData *md, Object *ob,
00356                         struct EditMesh *UNUSED(editData),
00357                         DerivedMesh *derivedData,
00358                         float (*vertexCos)[3],
00359                         int numVerts)
00360 {
00361     DerivedMesh *dm= get_dm(ob, NULL, derivedData, NULL, 0);
00362 
00363     meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
00364 
00365     if(dm && dm != derivedData)
00366         dm->release(dm);
00367 }
00368 
00369 #define MESHDEFORM_MIN_INFLUENCE 0.00001f
00370 
00371 void modifier_mdef_compact_influences(ModifierData *md)
00372 {
00373     MeshDeformModifierData *mmd= (MeshDeformModifierData*)md;
00374     float weight, *weights, totweight;
00375     int totinfluence, totvert, totcagevert, a, b;
00376 
00377     weights= mmd->bindweights;
00378     if(!weights)
00379         return;
00380     
00381     totvert= mmd->totvert;
00382     totcagevert= mmd->totcagevert;
00383 
00384     /* count number of influences above threshold */
00385     for(b=0; b<totvert; b++) {
00386         for(a=0; a<totcagevert; a++) {
00387             weight= weights[a + b*totcagevert];
00388 
00389             if(weight > MESHDEFORM_MIN_INFLUENCE)
00390                 mmd->totinfluence++;
00391         }
00392     }
00393 
00394     /* allocate bind influences */
00395     mmd->bindinfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefBindInfluence");
00396     mmd->bindoffsets= MEM_callocN(sizeof(int)*(totvert+1), "MDefBindOffset");
00397 
00398     /* write influences */
00399     totinfluence= 0;
00400 
00401     for(b=0; b<totvert; b++) {
00402         mmd->bindoffsets[b]= totinfluence;
00403         totweight= 0.0f;
00404 
00405         /* sum total weight */
00406         for(a=0; a<totcagevert; a++) {
00407             weight= weights[a + b*totcagevert];
00408 
00409             if(weight > MESHDEFORM_MIN_INFLUENCE)
00410                 totweight += weight;
00411         }
00412 
00413         /* assign weights normalized */
00414         for(a=0; a<totcagevert; a++) {
00415             weight= weights[a + b*totcagevert];
00416 
00417             if(weight > MESHDEFORM_MIN_INFLUENCE) {
00418                 mmd->bindinfluences[totinfluence].weight= weight/totweight;
00419                 mmd->bindinfluences[totinfluence].vertex= a;
00420                 totinfluence++;
00421             }
00422         }
00423     }
00424 
00425     mmd->bindoffsets[b]= totinfluence;
00426     
00427     /* free */
00428     MEM_freeN(mmd->bindweights);
00429     mmd->bindweights= NULL;
00430 }
00431 
00432 ModifierTypeInfo modifierType_MeshDeform = {
00433     /* name */              "MeshDeform",
00434     /* structName */        "MeshDeformModifierData",
00435     /* structSize */        sizeof(MeshDeformModifierData),
00436     /* type */              eModifierTypeType_OnlyDeform,
00437     /* flags */             eModifierTypeFlag_AcceptsCVs
00438                             | eModifierTypeFlag_SupportsEditmode,
00439 
00440     /* copyData */          copyData,
00441     /* deformVerts */       deformVerts,
00442     /* deformMatrices */    NULL,
00443     /* deformVertsEM */     deformVertsEM,
00444     /* deformMatricesEM */  NULL,
00445     /* applyModifier */     NULL,
00446     /* applyModifierEM */   NULL,
00447     /* initData */          initData,
00448     /* requiredDataMask */  requiredDataMask,
00449     /* freeData */          freeData,
00450     /* isDisabled */        isDisabled,
00451     /* updateDepgraph */    updateDepgraph,
00452     /* dependsOnTime */     NULL,
00453     /* dependsOnNormals */  NULL,
00454     /* foreachObjectLink */ foreachObjectLink,
00455     /* foreachIDLink */     NULL,
00456     /* foreachTexLink */    NULL,
00457 };