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