diff --git a/release/scripts/ui/properties_data_modifier.py b/release/scripts/ui/properties_data_modifier.py index 26b2c2a34f2..c43dbd9c90a 100644 --- a/release/scripts/ui/properties_data_modifier.py +++ b/release/scripts/ui/properties_data_modifier.py @@ -365,11 +365,11 @@ class DATA_PT_modifiers(DataButtonsPanel): def MESH_DEFORM(self, layout, ob, md, wide_ui): split = layout.split() col = split.column() - col.label(text="Object:") - col.prop(md, "object", text="") - if md.object and md.object.type == 'ARMATURE': - col.label(text="Bone:") - col.prop_object(md, "subtarget", md.object.data, "bones", text="") + sub = col.column() + sub.label(text="Object:") + sub.prop(md, "object", text="") + sub.prop(md, "mode", text="") + sub.active = not md.is_bound if wide_ui: col = split.column() col.label(text="Vertex Group:") @@ -385,14 +385,16 @@ class DATA_PT_modifiers(DataButtonsPanel): layout.operator("object.meshdeform_bind", text="Unbind") else: layout.operator("object.meshdeform_bind", text="Bind") - split = layout.split() - col = split.column() - col.prop(md, "precision") + if md.mode == 'VOLUME': + split = layout.split() - if wide_ui: col = split.column() - col.prop(md, "dynamic") + col.prop(md, "precision") + + if wide_ui: + col = split.column() + col.prop(md, "dynamic") def MIRROR(self, layout, ob, md, wide_ui): layout.prop(md, "merge_limit") diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index b5e0ca9ea5c..56aab7d2ba9 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -7894,7 +7894,7 @@ static void meshdeformModifier_do( /* progress bar redraw can make this recursive .. */ if(!recursive) { recursive = 1; - mmd->bindfunc(md->scene, mmd, (float*)vertexCos, numVerts, cagemat); + mmd->bindfunc(md->scene, dm, mmd, (float*)vertexCos, numVerts, cagemat); recursive = 0; } } diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index b9019410348..2ad71881f47 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -93,13 +93,16 @@ struct LaplacianSystem { EdgeHash *edgehash; /* edge hash for construction */ struct HeatWeighting { - Mesh *mesh; + MFace *mface; + int totvert; + int totface; float (*verts)[3]; /* vertex coordinates */ float (*vnors)[3]; /* vertex normals */ float (*root)[3]; /* bone root */ float (*tip)[3]; /* bone tip */ - int numbones; + float (*source)[3]; /* vertex source */ + int numsource; float *H; /* diagonal H matrix */ float *p; /* values from all p vectors */ @@ -394,38 +397,40 @@ float laplacian_system_get_solution(int v) #define WEIGHT_LIMIT_END 0.025f #define DISTANCE_EPSILON 1e-4f -/* Raytracing for vertex to bone visibility */ +/* Raytracing for vertex to bone/vertex visibility */ static void heat_ray_tree_create(LaplacianSystem *sys) { - Mesh *me = sys->heat.mesh; + MFace *mface = sys->heat.mface; + int totface = sys->heat.totface; + int totvert = sys->heat.totvert; int a; - sys->heat.raytree = RE_rayobject_vbvh_create(me->totface); - sys->heat.faces = MEM_callocN(sizeof(RayFace)*me->totface, "Heat RayFaces"); - sys->heat.vface = MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces"); + sys->heat.raytree = RE_rayobject_vbvh_create(totface); + sys->heat.faces = MEM_callocN(sizeof(RayFace)*totface, "Heat RayFaces"); + sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces"); - for(a=0; atotface; a++) { + for(a=0; amface+a; + MFace *mf = mface+a; RayFace *rayface = sys->heat.faces+a; RayObject *obj = RE_rayface_from_coords( - rayface, me, mface, - sys->heat.verts[mface->v1], sys->heat.verts[mface->v2], - sys->heat.verts[mface->v3], mface->v4 ? sys->heat.verts[mface->v4] : 0 + rayface, &sys->heat, mf, + sys->heat.verts[mf->v1], sys->heat.verts[mf->v2], + sys->heat.verts[mf->v3], mf->v4 ? sys->heat.verts[mf->v4] : 0 ); RE_rayobject_add(sys->heat.raytree, obj); //Setup inverse pointers to use on isect.orig - sys->heat.vface[mface->v1]= mface; - sys->heat.vface[mface->v2]= mface; - sys->heat.vface[mface->v3]= mface; - if(mface->v4) sys->heat.vface[mface->v4]= mface; + sys->heat.vface[mf->v1]= mf; + sys->heat.vface[mf->v2]= mf; + sys->heat.vface[mf->v3]= mf; + if(mf->v4) sys->heat.vface[mf->v4]= mf; } RE_rayobject_done(sys->heat.raytree); } -static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone) +static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source) { Isect isec; MFace *mface; @@ -440,30 +445,37 @@ static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone) memset(&isec, 0, sizeof(isec)); isec.mode= RE_RAY_SHADOW; isec.lay= -1; - isec.orig.ob = sys->heat.mesh; + isec.orig.ob = &sys->heat; isec.orig.face = mface; isec.skip = RE_SKIP_CULLFACE; + copy_v3_v3(isec.start, sys->heat.verts[vertex]); - VECCOPY(isec.start, sys->heat.verts[vertex]); - closest_to_line_segment_v3(end, isec.start, sys->heat.root[bone], sys->heat.tip[bone]); + if(sys->heat.root) /* bone */ + closest_to_line_segment_v3(end, isec.start, + sys->heat.root[source], sys->heat.tip[source]); + else /* vertex */ + copy_v3_v3(end, sys->heat.source[source]); - VECSUB(isec.vec, end, isec.start); + sub_v3_v3v3(isec.vec, end, isec.start); isec.labda = 1.0f - 1e-5; - VECADDFAC( isec.start, isec.start, isec.vec, 1e-5); + madd_v3_v3v3fl(isec.start, isec.start, isec.vec, 1e-5); visible= !RE_rayobject_raycast(sys->heat.raytree, &isec); return visible; } -static float heat_bone_distance(LaplacianSystem *sys, int vertex, int bone) +static float heat_source_distance(LaplacianSystem *sys, int vertex, int source) { float closest[3], d[3], dist, cosine; /* compute euclidian distance */ - closest_to_line_segment_v3(closest, sys->heat.verts[vertex], - sys->heat.root[bone], sys->heat.tip[bone]); + if(sys->heat.root) /* bone */ + closest_to_line_segment_v3(closest, sys->heat.verts[vertex], + sys->heat.root[source], sys->heat.tip[source]); + else /* vertex */ + copy_v3_v3(closest, sys->heat.source[source]); sub_v3_v3v3(d, sys->heat.verts[vertex], closest); dist= normalize_v3(d); @@ -474,16 +486,16 @@ static float heat_bone_distance(LaplacianSystem *sys, int vertex, int bone) return dist/(0.5f*(cosine + 1.001f)); } -static int heat_bone_closest(LaplacianSystem *sys, int vertex, int bone) +static int heat_source_closest(LaplacianSystem *sys, int vertex, int source) { float dist; - - dist= heat_bone_distance(sys, vertex, bone); + + dist= heat_source_distance(sys, vertex, source); if(dist <= sys->heat.mindist[vertex]*(1.0f + DISTANCE_EPSILON)) - if(heat_ray_bone_visible(sys, vertex, bone)) + if(heat_ray_source_visible(sys, vertex, source)) return 1; - + return 0; } @@ -495,8 +507,8 @@ static void heat_set_H(LaplacianSystem *sys, int vertex) mindist= 1e10; /* compute minimum distance */ - for(j=0; jheat.numbones; j++) { - dist= heat_bone_distance(sys, vertex, j); + for(j=0; jheat.numsource; j++) { + dist= heat_source_distance(sys, vertex, j); if(dist < mindist) mindist= dist; @@ -504,9 +516,9 @@ static void heat_set_H(LaplacianSystem *sys, int vertex) sys->heat.mindist[vertex]= mindist; - /* count number of bones with approximately this minimum distance */ - for(j=0; jheat.numbones; j++) - if(heat_bone_closest(sys, vertex, j)) + /* count number of sources with approximately this minimum distance */ + for(j=0; jheat.numsource; j++) + if(heat_source_closest(sys, vertex, j)) numclosest++; sys->heat.p[vertex]= (numclosest > 0)? 1.0f/numclosest: 0.0f; @@ -549,32 +561,45 @@ void heat_calc_vnormals(LaplacianSystem *sys) static void heat_laplacian_create(LaplacianSystem *sys) { - Mesh *me = sys->heat.mesh; - MFace *mface; + MFace *mface = sys->heat.mface, *mf; + int totface= sys->heat.totface; + int totvert= sys->heat.totvert; int a; /* heat specific definitions */ - sys->heat.mindist= MEM_callocN(sizeof(float)*me->totvert, "HeatMinDist"); - sys->heat.H= MEM_callocN(sizeof(float)*me->totvert, "HeatH"); - sys->heat.p= MEM_callocN(sizeof(float)*me->totvert, "HeatP"); + sys->heat.mindist= MEM_callocN(sizeof(float)*totvert, "HeatMinDist"); + sys->heat.H= MEM_callocN(sizeof(float)*totvert, "HeatH"); + sys->heat.p= MEM_callocN(sizeof(float)*totvert, "HeatP"); /* add verts and faces to laplacian */ - for(a=0; atotvert; a++) + for(a=0; aheat.verts[a], 0); - for(a=0, mface=me->mface; atotface; a++, mface++) { - laplacian_add_triangle(sys, mface->v1, mface->v2, mface->v3); - if(mface->v4) - laplacian_add_triangle(sys, mface->v1, mface->v3, mface->v4); + for(a=0, mf=mface; av1, mf->v2, mf->v3); + if(mf->v4) + laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4); } /* for distance computation in set_H */ heat_calc_vnormals(sys); - for(a=0; atotvert; a++) + for(a=0; aheat.raytree); + MEM_freeN(sys->heat.vface); + MEM_freeN(sys->heat.faces); + + MEM_freeN(sys->heat.mindist); + MEM_freeN(sys->heat.H); + MEM_freeN(sys->heat.p); + MEM_freeN(sys->heat.vnors); +} + static float heat_limit_weight(float weight) { float t; @@ -590,7 +615,7 @@ static float heat_limit_weight(float weight) return weight; } -void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected) +void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected) { LaplacianSystem *sys; MFace *mface; @@ -607,11 +632,13 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, /* create laplacian */ sys = laplacian_system_construct_begin(me->totvert, totface, 1); - sys->heat.mesh= me; + sys->heat.mface= me->mface; + sys->heat.totface= me->totface; + sys->heat.totvert= me->totvert; sys->heat.verts= verts; sys->heat.root= root; sys->heat.tip= tip; - sys->heat.numbones= numbones; + sys->heat.numsource= numsource; heat_ray_tree_create(sys); heat_laplacian_create(sys); @@ -625,12 +652,12 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, } /* compute weights per bone */ - for(j=0; jtotvert; a++) - if(heat_bone_closest(sys, a, j)) + if(heat_source_closest(sys, a, j)) laplacian_add_right_hand_side(sys, a, sys->heat.H[a]*sys->heat.p[a]); @@ -716,14 +743,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, /* free */ if(vertsflipped) MEM_freeN(vertsflipped); - RE_rayobject_free(sys->heat.raytree); - MEM_freeN(sys->heat.vface); - MEM_freeN(sys->heat.faces); - - MEM_freeN(sys->heat.mindist); - MEM_freeN(sys->heat.H); - MEM_freeN(sys->heat.p); - MEM_freeN(sys->heat.vnors); + heat_system_free(sys); laplacian_system_delete(sys); } @@ -1027,11 +1047,11 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; float det,inv_det, u, v, dir[3], isectdir[3]; - VECSUB(dir, end, orig); + sub_v3_v3v3(dir, end, orig); /* find vectors for two edges sharing vert0 */ - VECSUB(edge1, vert1, vert0); - VECSUB(edge2, vert2, vert0); + sub_v3_v3v3(edge1, vert1, vert0); + sub_v3_v3v3(edge2, vert2, vert0); /* begin calculating determinant - also used to calculate U parameter */ cross_v3_v3v3(pvec, dir, edge2); @@ -1044,7 +1064,7 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], inv_det = 1.0f / det; /* calculate distance from vert0 to ray origin */ - VECSUB(tvec, orig, vert0); + sub_v3_v3v3(tvec, orig, vert0); /* calculate U parameter and test bounds */ u = INPR(tvec, pvec) * inv_det; @@ -1068,7 +1088,7 @@ static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], uvw[2]= v; /* check if it is within the length of the line segment */ - VECSUB(isectdir, isectco, orig); + sub_v3_v3v3(isectdir, isectco, orig); if(INPR(dir, isectdir) < -EPSILON) return 0; @@ -1149,12 +1169,12 @@ static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec) VECADDFAC( end, isec->start, isec->vec, isec->labda ); for(f=0; fcagecos[mface->v1]); - VECCOPY(face[1], mdb->cagecos[mface->v2]); - VECCOPY(face[2], mdb->cagecos[mface->v3]); + copy_v3_v3(face[0], mdb->cagecos[mface->v1]); + copy_v3_v3(face[1], mdb->cagecos[mface->v2]); + copy_v3_v3(face[2], mdb->cagecos[mface->v3]); if(mface->v4) { - VECCOPY(face[3], mdb->cagecos[mface->v4]); + copy_v3_v3(face[3], mdb->cagecos[mface->v4]); hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); if(hit) { @@ -1201,7 +1221,7 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float VECADD(isec.start, co1, epsilon); VECADD(end, co2, epsilon); - VECSUB(isec.vec, end, isec.start); + sub_v3_v3v3(isec.vec, end, isec.start); #if 0 /*if(RE_ray_tree_intersect(mdb->raytree, &isec)) {*/ @@ -1233,10 +1253,10 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float /* compute mean value coordinates for interpolation */ cagecos= mdb->cagecos; - VECCOPY(vert[0], cagecos[mface->v1]); - VECCOPY(vert[1], cagecos[mface->v2]); - VECCOPY(vert[2], cagecos[mface->v3]); - if(mface->v4) VECCOPY(vert[3], cagecos[mface->v4]); + copy_v3_v3(vert[0], cagecos[mface->v1]); + copy_v3_v3(vert[1], cagecos[mface->v2]); + copy_v3_v3(vert[2], cagecos[mface->v3]); + if(mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]); interp_weights_poly_v3( isect->uvw,vert, isect->nvert, isect->co); return isect; @@ -1258,8 +1278,8 @@ static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co) outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1]; outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2]; - VECCOPY(start, co); - VECSUB(dir, outside, start); + copy_v3_v3(start, co); + sub_v3_v3v3(dir, outside, start); normalize_v3(dir); isect = meshdeform_ray_tree_intersect(mdb, start, outside); @@ -1649,7 +1669,7 @@ static void meshdeform_matrix_solve(MeshDeformBind *mdb) /* static bind : compute weights for each vertex */ for(b=0; btotvert; b++) { if(mdb->inside[b]) { - VECCOPY(vec, mdb->vertexcos[b]); + copy_v3_v3(vec, mdb->vertexcos[b]); mul_m4_v3(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]; @@ -1698,148 +1718,123 @@ static void meshdeform_matrix_solve(MeshDeformBind *mdb) nlDeleteContext(context); } -void harmonic_coordinates_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]) +static void harmonic_coordinates_bind(Scene *scene, MeshDeformModifierData *mmd, MeshDeformBind *mdb) { - MeshDeformBind mdb; MDefBindInfluence *inf; MDefInfluence *mdinf; MDefCell *cell; - MVert *mvert; float center[3], vec[3], maxwidth, totweight; int a, b, x, y, z, totinside, offset; - waitcursor(1); - start_progress_bar(); - - memset(&mdb, 0, sizeof(MeshDeformBind)); - - /* get mesh and cage mesh */ - mdb.vertexcos= (float(*)[3])vertexcos; - mdb.totvert= totvert; - - mdb.cagedm= mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH); - mdb.totcagevert= mdb.cagedm->getNumVerts(mdb.cagedm); - mdb.cagecos= MEM_callocN(sizeof(*mdb.cagecos)*mdb.totcagevert, "MeshDeformBindCos"); - copy_m4_m4(mdb.cagemat, cagemat); - - mvert= mdb.cagedm->getVertArray(mdb.cagedm); - for(a=0; amin, mdb->max); - for(a=0; atotcagevert; a++) + DO_MINMAX(mdb->cagecos[a], mdb->min, mdb->max); /* allocate memory */ - mdb.size= (2<<(mmd->gridsize-1)) + 2; - mdb.size3= mdb.size*mdb.size*mdb.size; - mdb.tag= MEM_callocN(sizeof(int)*mdb.size3, "MeshDeformBindTag"); - mdb.phi= MEM_callocN(sizeof(float)*mdb.size3, "MeshDeformBindPhi"); - mdb.totalphi= MEM_callocN(sizeof(float)*mdb.size3, "MeshDeformBindTotalPhi"); - mdb.boundisect= MEM_callocN(sizeof(*mdb.boundisect)*mdb.size3, "MDefBoundIsect"); - mdb.semibound= MEM_callocN(sizeof(int)*mdb.size3, "MDefSemiBound"); + mdb->size= (2<<(mmd->gridsize-1)) + 2; + mdb->size3= mdb->size*mdb->size*mdb->size; + mdb->tag= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindTag"); + mdb->phi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindPhi"); + mdb->totalphi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindTotalPhi"); + mdb->boundisect= MEM_callocN(sizeof(*mdb->boundisect)*mdb->size3, "MDefBoundIsect"); + mdb->semibound= MEM_callocN(sizeof(int)*mdb->size3, "MDefSemiBound"); - mdb.inside= MEM_callocN(sizeof(int)*mdb.totvert, "MDefInside"); + 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"); + mdb->dyngrid= MEM_callocN(sizeof(MDefBindInfluence*)*mdb->size3, "MDefDynGrid"); else - mdb.weights= MEM_callocN(sizeof(float)*mdb.totvert*mdb.totcagevert, "MDefWeights"); + 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); + mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_calloc(mdb->memarena); /* make bounding box equal size in all directions, add padding, and compute * width of the cells */ maxwidth = -1.0f; for(a=0; a<3; a++) - if(mdb.max[a]-mdb.min[a] > maxwidth) - maxwidth= mdb.max[a]-mdb.min[a]; + if(mdb->max[a]-mdb->min[a] > maxwidth) + maxwidth= mdb->max[a]-mdb->min[a]; for(a=0; a<3; a++) { - center[a]= (mdb.min[a]+mdb.max[a])*0.5f; - mdb.min[a]= center[a] - maxwidth*0.5f; - mdb.max[a]= center[a] + maxwidth*0.5f; + center[a]= (mdb->min[a]+mdb->max[a])*0.5f; + mdb->min[a]= center[a] - maxwidth*0.5f; + mdb->max[a]= center[a] + maxwidth*0.5f; - mdb.width[a]= (mdb.max[a]-mdb.min[a])/(mdb.size-4); - mdb.min[a] -= 2.1f*mdb.width[a]; - mdb.max[a] += 2.1f*mdb.width[a]; + mdb->width[a]= (mdb->max[a]-mdb->min[a])/(mdb->size-4); + mdb->min[a] -= 2.1f*mdb->width[a]; + mdb->max[a] += 2.1f*mdb->width[a]; - mdb.width[a]= (mdb.max[a]-mdb.min[a])/mdb.size; - mdb.halfwidth[a]= mdb.width[a]*0.5f; + mdb->width[a]= (mdb->max[a]-mdb->min[a])/mdb->size; + mdb->halfwidth[a]= mdb->width[a]*0.5f; } progress_bar(0, "Setting up mesh deform system"); #if 0 /* create ray tree */ - meshdeform_ray_tree_create(&mdb); + meshdeform_ray_tree_create(mdb); #endif totinside= 0; - for(a=0; atotvert; a++) { + copy_v3_v3(vec, mdb->vertexcos[a]); + mul_m4_v3(mdb->cagemat, vec); + mdb->inside[a]= meshdeform_inside_cage(mdb, vec); + if(mdb->inside[a]) totinside++; } /* free temporary MDefBoundIsects */ - BLI_memarena_free(mdb.memarena); - mdb.memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_free(mdb->memarena); + mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); /* start with all cells untyped */ - for(a=0; asize3; a++) + mdb->tag[a]= MESHDEFORM_TAG_UNTYPED; /* detect intersections and tag boundary cells */ - for(z=0; zsize; z++) + for(y=0; ysize; y++) + for(x=0; xsize; x++) + meshdeform_add_intersections(mdb, x, y, z); #if 0 /* free ray tree */ - meshdeform_ray_tree_free(&mdb); + meshdeform_ray_tree_free(mdb); #endif /* compute exterior and interior tags */ - meshdeform_bind_floodfill(&mdb); + meshdeform_bind_floodfill(mdb); - for(z=0; zsize; z++) + for(y=0; ysize; y++) + for(x=0; xsize; x++) + meshdeform_check_semibound(mdb, x, y, z); /* solve */ - meshdeform_matrix_solve(&mdb); + meshdeform_matrix_solve(mdb); /* assign results */ - mmd->bindcos= (float*)mdb.cagecos; - mmd->totvert= mdb.totvert; - mmd->totcagevert= mdb.totcagevert; - copy_m4_m4(mmd->bindmat, mmd->object->obmat); - if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) { mmd->totinfluence= 0; - for(a=0; anext) + for(a=0; asize3; 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->dyngrid= MEM_callocN(sizeof(MDefCell)*mdb->size3, "MDefDynGrid"); mmd->dyninfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefInfluence"); offset= 0; - for(a=0; asize3; 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++) { + for(inf=mdb->dyngrid[a]; inf; inf=inf->next, mdinf++) { mdinf->weight= inf->weight; mdinf->vertex= inf->vertex; totweight += mdinf->weight; @@ -1855,29 +1850,138 @@ void harmonic_coordinates_bind(Scene *scene, MeshDeformModifierData *mmd, float 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); + mmd->dynverts= mdb->inside; + mmd->dyngridsize= mdb->size; + copy_v3_v3(mmd->dyncellmin, mdb->min); + mmd->dyncellwidth= mdb->width[0]; + MEM_freeN(mdb->dyngrid); } else { - mmd->bindweights= mdb.weights; - MEM_freeN(mdb.inside); + mmd->bindweights= mdb->weights; + MEM_freeN(mdb->inside); } + MEM_freeN(mdb->tag); + MEM_freeN(mdb->phi); + MEM_freeN(mdb->totalphi); + MEM_freeN(mdb->boundisect); + MEM_freeN(mdb->semibound); + BLI_memarena_free(mdb->memarena); +} + +static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb) +{ + LaplacianSystem *sys; + MFace *mface= dm->getFaceArray(dm), *mf; + int totvert= dm->getNumVerts(dm); + int totface= dm->getNumFaces(dm); + float solution, weight; + int a, tottri, j, thrownerror = 0; + + mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights"); + + /* count triangles */ + for(tottri=0, a=0, mf=mface; av4) tottri++; + } + + /* create laplacian */ + sys = laplacian_system_construct_begin(totvert, tottri, 1); + + sys->heat.mface= mface; + sys->heat.totface= totface; + sys->heat.totvert= totvert; + sys->heat.verts= mdb->vertexcos; + sys->heat.source = mdb->cagecos; + sys->heat.numsource= mdb->totcagevert; + + heat_ray_tree_create(sys); + heat_laplacian_create(sys); + + laplacian_system_construct_end(sys); + + /* compute weights per bone */ + for(j=0; jtotcagevert; j++) { + /* fill right hand side */ + laplacian_begin_solve(sys, -1); + + for(a=0; aheat.H[a]*sys->heat.p[a]); + + /* solve */ + if(laplacian_system_solve(sys)) { + /* load solution into vertex groups */ + for(a=0; a 0.0f) + mdb->weights[a*mdb->totcagevert + j] = weight; + } + } + else if(!thrownerror) { + error("Mesh Deform Heat Weighting:" + " failed to find solution for one or more vertices"); + thrownerror= 1; + break; + } + } + + /* free */ + heat_system_free(sys); + laplacian_system_delete(sys); + + mmd->bindweights= mdb->weights; +} + +void mesh_deform_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]) +{ + MeshDeformBind mdb; + MVert *mvert; + int a; + + waitcursor(1); + start_progress_bar(); + + memset(&mdb, 0, sizeof(MeshDeformBind)); + + /* get mesh and cage mesh */ + mdb.vertexcos= MEM_callocN(sizeof(float)*3*totvert, "MeshDeformCos"); + mdb.totvert= totvert; + + mdb.cagedm= mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH); + mdb.totcagevert= mdb.cagedm->getNumVerts(mdb.cagedm); + mdb.cagecos= MEM_callocN(sizeof(*mdb.cagecos)*mdb.totcagevert, "MeshDeformBindCos"); + copy_m4_m4(mdb.cagemat, cagemat); + + mvert= mdb.cagedm->getVertArray(mdb.cagedm); + for(a=0; amode == MOD_MDEF_VOLUME) + harmonic_coordinates_bind(scene, mmd, &mdb); + else + heat_weighting_bind(scene, dm, mmd, &mdb); + + /* assign bind variables */ + mmd->bindcos= (float*)mdb.cagecos; + mmd->totvert= mdb.totvert; + mmd->totcagevert= mdb.totcagevert; + copy_m4_m4(mmd->bindmat, mmd->object->obmat); + /* transform bindcos to world space */ for(a=0; aobject->obmat, mmd->bindcos+a*3); /* free */ mdb.cagedm->release(mdb.cagedm); - MEM_freeN(mdb.tag); - MEM_freeN(mdb.phi); - MEM_freeN(mdb.totalphi); - MEM_freeN(mdb.boundisect); - MEM_freeN(mdb.semibound); - BLI_memarena_free(mdb.memarena); + MEM_freeN(mdb.vertexcos); end_progress_bar(); waitcursor(0); diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h index 1ee01561cd4..215a3579cab 100644 --- a/source/blender/editors/armature/meshlaplacian.h +++ b/source/blender/editors/armature/meshlaplacian.h @@ -78,7 +78,8 @@ void rigid_deform_end(int cancel); /* Harmonic Coordinates */ -void harmonic_coordinates_bind(struct Scene *scene, struct MeshDeformModifierData *mmd, +void mesh_deform_bind(struct Scene *scene, struct DerivedMesh *dm, + struct MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]); #endif diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 083884336d2..74f1f7e3b83 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -165,7 +165,8 @@ void BDR_drawSketch(const struct bContext *vc); int BDR_drawSketchNames(struct ViewContext *vc); /* meshlaplacian.c */ -void harmonic_coordinates_bind(struct Scene *scene, struct MeshDeformModifierData *mmd, +void mesh_deform_bind(struct Scene *scene, struct DerivedMesh *dm, + struct MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]); #endif /* ED_ARMATURE_H */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 7bb5eb6f63b..7ab49f5c838 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -840,7 +840,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) int mode= mmd->modifier.mode; /* force modifier to run, it will call binding routine */ - mmd->bindfunc= harmonic_coordinates_bind; + mmd->bindfunc= mesh_deform_bind; mmd->modifier.mode |= eModifierMode_Realtime; if(ob->type == OB_MESH) { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index fe6a5b050e3..040dc4dbd78 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -492,6 +492,9 @@ typedef struct BooleanModifierData { #define MOD_MDEF_INVERT_VGROUP (1<<0) #define MOD_MDEF_DYNAMIC_BIND (1<<1) +#define MOD_MDEF_VOLUME 0 +#define MOD_MDEF_SURFACE 1 + typedef struct MDefInfluence { int vertex; float weight; @@ -508,7 +511,7 @@ typedef struct MeshDeformModifierData { struct Object *object; /* mesh object */ char defgrp_name[32]; /* optional vertexgroup name */ - short gridsize, flag, pad[2]; + short gridsize, flag, mode, pad; /* variables filled in when bound */ float *bindweights, *bindcos; /* computed binding weights */ @@ -523,7 +526,8 @@ typedef struct MeshDeformModifierData { float bindmat[4][4]; /* matrix of cage at binding time */ /* runtime */ - void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, + void (*bindfunc)(struct Scene *scene, struct DerivedMesh *dm, + struct MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]); } MeshDeformModifierData; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5b619e702a0..a86d889d6cf 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1397,6 +1397,10 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + static EnumPropertyItem prop_mode_items[] = { + {0, "VOLUME", 0, "Volume", "Bind to volume inside cage mesh."}, + {1, "SURFACE", 0, "Surface", "Bind to surface of cage mesh."}, + {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "MeshDeformModifier", "Modifier"); RNA_def_struct_ui_text(srna, "MeshDeform Modifier", "Mesh deformation modifier to deform with other meshes."); @@ -1436,6 +1440,10 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Dynamic", "Recompute binding dynamically on top of other deformers (slower and more memory consuming.)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_mode_items); + RNA_def_property_ui_text(prop, "Mode", "Method of binding vertices are bound to cage mesh."); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_particlesystem(BlenderRNA *brna)