|
Blender
V2.59
|
00001 /* 00002 * $Id: meshlaplacian.c 36276 2011-04-21 15:53:30Z campbellbarton $ 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) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 * meshlaplacian.c: Algorithms using the mesh laplacian. 00029 */ 00030 00036 #include <math.h> 00037 #include <string.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_object_types.h" 00042 #include "DNA_mesh_types.h" 00043 #include "DNA_meshdata_types.h" 00044 #include "DNA_scene_types.h" 00045 00046 #include "BLI_math.h" 00047 #include "BLI_edgehash.h" 00048 #include "BLI_memarena.h" 00049 #include "BLI_utildefines.h" 00050 00051 #include "BKE_DerivedMesh.h" 00052 #include "BKE_modifier.h" 00053 00054 00055 #ifdef RIGID_DEFORM 00056 #include "BLI_editVert.h" 00057 #include "BLI_polardecomp.h" 00058 #endif 00059 00060 #include "ONL_opennl.h" 00061 00062 #include "BLO_sys_types.h" // for intptr_t support 00063 00064 #include "ED_mesh.h" 00065 #include "ED_armature.h" 00066 00067 #include "meshlaplacian.h" 00068 00069 00070 /* ************* XXX *************** */ 00071 static void waitcursor(int UNUSED(val)) {} 00072 static void progress_bar(int UNUSED(dummy_val), const char *UNUSED(dummy)) {} 00073 static void start_progress_bar(void) {} 00074 static void end_progress_bar(void) {} 00075 static void error(const char *str) { printf("error: %s\n", str); } 00076 /* ************* XXX *************** */ 00077 00078 00079 /************************** Laplacian System *****************************/ 00080 00081 struct LaplacianSystem { 00082 NLContext context; /* opennl context */ 00083 00084 int totvert, totface; 00085 00086 float **verts; /* vertex coordinates */ 00087 float *varea; /* vertex weights for laplacian computation */ 00088 char *vpinned; /* vertex pinning */ 00089 int (*faces)[3]; /* face vertex indices */ 00090 float (*fweights)[3]; /* cotangent weights per face */ 00091 00092 int areaweights; /* use area in cotangent weights? */ 00093 int storeweights; /* store cotangent weights in fweights */ 00094 int nlbegun; /* nlBegin(NL_SYSTEM/NL_MATRIX) done */ 00095 00096 EdgeHash *edgehash; /* edge hash for construction */ 00097 00098 struct HeatWeighting { 00099 MFace *mface; 00100 int totvert; 00101 int totface; 00102 float (*verts)[3]; /* vertex coordinates */ 00103 float (*vnors)[3]; /* vertex normals */ 00104 00105 float (*root)[3]; /* bone root */ 00106 float (*tip)[3]; /* bone tip */ 00107 float (*source)[3]; /* vertex source */ 00108 int numsource; 00109 00110 float *H; /* diagonal H matrix */ 00111 float *p; /* values from all p vectors */ 00112 float *mindist; /* minimum distance to a bone for all vertices */ 00113 00114 BVHTree *bvhtree; /* ray tracing acceleration structure */ 00115 MFace **vface; /* a face that the vertex belongs to */ 00116 } heat; 00117 00118 #ifdef RIGID_DEFORM 00119 struct RigidDeformation { 00120 EditMesh *mesh; 00121 00122 float (*R)[3][3]; 00123 float (*rhs)[3]; 00124 float (*origco)[3]; 00125 int thrownerror; 00126 } rigid; 00127 #endif 00128 }; 00129 00130 /* Laplacian matrix construction */ 00131 00132 /* Computation of these weights for the laplacian is based on: 00133 "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds", 00134 Meyer et al, 2002. Section 3.5, formula (8). 00135 00136 We do it a bit different by going over faces instead of going over each 00137 vertex and adjacent faces, since we don't store this adjacency. Also, the 00138 formulas are tweaked a bit to work for non-manifold meshes. */ 00139 00140 static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2) 00141 { 00142 void **p = BLI_edgehash_lookup_p(edgehash, v1, v2); 00143 00144 if(p) 00145 *p = (void*)((intptr_t)*p + (intptr_t)1); 00146 else 00147 BLI_edgehash_insert(edgehash, v1, v2, (void*)(intptr_t)1); 00148 } 00149 00150 static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2) 00151 { 00152 return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2); 00153 } 00154 00155 static float cotan_weight(float *v1, float *v2, float *v3) 00156 { 00157 float a[3], b[3], c[3], clen; 00158 00159 sub_v3_v3v3(a, v2, v1); 00160 sub_v3_v3v3(b, v3, v1); 00161 cross_v3_v3v3(c, a, b); 00162 00163 clen = len_v3(c); 00164 00165 if (clen == 0.0f) 00166 return 0.0f; 00167 00168 return dot_v3v3(a, b)/clen; 00169 } 00170 00171 static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3) 00172 { 00173 float t1, t2, t3, len1, len2, len3, area; 00174 float *varea= sys->varea, *v1, *v2, *v3; 00175 int obtuse = 0; 00176 00177 v1= sys->verts[i1]; 00178 v2= sys->verts[i2]; 00179 v3= sys->verts[i3]; 00180 00181 t1= cotan_weight(v1, v2, v3); 00182 t2= cotan_weight(v2, v3, v1); 00183 t3= cotan_weight(v3, v1, v2); 00184 00185 if(RAD2DEGF(angle_v3v3v3(v2, v1, v3)) > 90) obtuse= 1; 00186 else if(RAD2DEGF(angle_v3v3v3(v1, v2, v3)) > 90) obtuse= 2; 00187 else if(RAD2DEGF(angle_v3v3v3(v1, v3, v2)) > 90) obtuse= 3; 00188 00189 if (obtuse > 0) { 00190 area= area_tri_v3(v1, v2, v3); 00191 00192 varea[i1] += (obtuse == 1)? area: area*0.5f; 00193 varea[i2] += (obtuse == 2)? area: area*0.5f; 00194 varea[i3] += (obtuse == 3)? area: area*0.5f; 00195 } 00196 else { 00197 len1= len_v3v3(v2, v3); 00198 len2= len_v3v3(v1, v3); 00199 len3= len_v3v3(v1, v2); 00200 00201 t1 *= len1*len1; 00202 t2 *= len2*len2; 00203 t3 *= len3*len3; 00204 00205 varea[i1] += (t2 + t3)*0.25f; 00206 varea[i2] += (t1 + t3)*0.25f; 00207 varea[i3] += (t1 + t2)*0.25f; 00208 } 00209 } 00210 00211 static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3) 00212 { 00213 float t1, t2, t3; 00214 float *varea= sys->varea, *v1, *v2, *v3; 00215 00216 v1= sys->verts[i1]; 00217 v2= sys->verts[i2]; 00218 v3= sys->verts[i3]; 00219 00220 /* instead of *0.5 we divided by the number of faces of the edge, it still 00221 needs to be verified that this is indeed the correct thing to do! */ 00222 t1= cotan_weight(v1, v2, v3)/laplacian_edge_count(sys->edgehash, i2, i3); 00223 t2= cotan_weight(v2, v3, v1)/laplacian_edge_count(sys->edgehash, i3, i1); 00224 t3= cotan_weight(v3, v1, v2)/laplacian_edge_count(sys->edgehash, i1, i2); 00225 00226 nlMatrixAdd(i1, i1, (t2+t3)*varea[i1]); 00227 nlMatrixAdd(i2, i2, (t1+t3)*varea[i2]); 00228 nlMatrixAdd(i3, i3, (t1+t2)*varea[i3]); 00229 00230 nlMatrixAdd(i1, i2, -t3*varea[i1]); 00231 nlMatrixAdd(i2, i1, -t3*varea[i2]); 00232 00233 nlMatrixAdd(i2, i3, -t1*varea[i2]); 00234 nlMatrixAdd(i3, i2, -t1*varea[i3]); 00235 00236 nlMatrixAdd(i3, i1, -t2*varea[i3]); 00237 nlMatrixAdd(i1, i3, -t2*varea[i1]); 00238 00239 if(sys->storeweights) { 00240 sys->fweights[f][0]= t1*varea[i1]; 00241 sys->fweights[f][1]= t2*varea[i2]; 00242 sys->fweights[f][2]= t3*varea[i3]; 00243 } 00244 } 00245 00246 static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totface, int lsq) 00247 { 00248 LaplacianSystem *sys; 00249 00250 sys= MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem"); 00251 00252 sys->verts= MEM_callocN(sizeof(float*)*totvert, "LaplacianSystemVerts"); 00253 sys->vpinned= MEM_callocN(sizeof(char)*totvert, "LaplacianSystemVpinned"); 00254 sys->faces= MEM_callocN(sizeof(int)*3*totface, "LaplacianSystemFaces"); 00255 00256 sys->totvert= 0; 00257 sys->totface= 0; 00258 00259 sys->areaweights= 1; 00260 sys->storeweights= 0; 00261 00262 /* create opennl context */ 00263 nlNewContext(); 00264 nlSolverParameteri(NL_NB_VARIABLES, totvert); 00265 if(lsq) 00266 nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); 00267 00268 sys->context= nlGetCurrent(); 00269 00270 return sys; 00271 } 00272 00273 void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned) 00274 { 00275 sys->verts[sys->totvert]= co; 00276 sys->vpinned[sys->totvert]= pinned; 00277 sys->totvert++; 00278 } 00279 00280 void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3) 00281 { 00282 sys->faces[sys->totface][0]= v1; 00283 sys->faces[sys->totface][1]= v2; 00284 sys->faces[sys->totface][2]= v3; 00285 sys->totface++; 00286 } 00287 00288 static void laplacian_system_construct_end(LaplacianSystem *sys) 00289 { 00290 int (*face)[3]; 00291 int a, totvert=sys->totvert, totface=sys->totface; 00292 00293 laplacian_begin_solve(sys, 0); 00294 00295 sys->varea= MEM_callocN(sizeof(float)*totvert, "LaplacianSystemVarea"); 00296 00297 sys->edgehash= BLI_edgehash_new(); 00298 for(a=0, face=sys->faces; a<sys->totface; a++, face++) { 00299 laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]); 00300 laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]); 00301 laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]); 00302 } 00303 00304 if(sys->areaweights) 00305 for(a=0, face=sys->faces; a<sys->totface; a++, face++) 00306 laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]); 00307 00308 for(a=0; a<totvert; a++) { 00309 if(sys->areaweights) { 00310 if(sys->varea[a] != 0.0f) 00311 sys->varea[a]= 0.5f/sys->varea[a]; 00312 } 00313 else 00314 sys->varea[a]= 1.0f; 00315 00316 /* for heat weighting */ 00317 if(sys->heat.H) 00318 nlMatrixAdd(a, a, sys->heat.H[a]); 00319 } 00320 00321 if(sys->storeweights) 00322 sys->fweights= MEM_callocN(sizeof(float)*3*totface, "LaplacianFWeight"); 00323 00324 for(a=0, face=sys->faces; a<totface; a++, face++) 00325 laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]); 00326 00327 MEM_freeN(sys->faces); 00328 sys->faces= NULL; 00329 00330 if(sys->varea) { 00331 MEM_freeN(sys->varea); 00332 sys->varea= NULL; 00333 } 00334 00335 BLI_edgehash_free(sys->edgehash, NULL); 00336 sys->edgehash= NULL; 00337 } 00338 00339 static void laplacian_system_delete(LaplacianSystem *sys) 00340 { 00341 if(sys->verts) MEM_freeN(sys->verts); 00342 if(sys->varea) MEM_freeN(sys->varea); 00343 if(sys->vpinned) MEM_freeN(sys->vpinned); 00344 if(sys->faces) MEM_freeN(sys->faces); 00345 if(sys->fweights) MEM_freeN(sys->fweights); 00346 00347 nlDeleteContext(sys->context); 00348 MEM_freeN(sys); 00349 } 00350 00351 void laplacian_begin_solve(LaplacianSystem *sys, int index) 00352 { 00353 int a; 00354 00355 if (!sys->nlbegun) { 00356 nlBegin(NL_SYSTEM); 00357 00358 if(index >= 0) { 00359 for(a=0; a<sys->totvert; a++) { 00360 if(sys->vpinned[a]) { 00361 nlSetVariable(0, a, sys->verts[a][index]); 00362 nlLockVariable(a); 00363 } 00364 } 00365 } 00366 00367 nlBegin(NL_MATRIX); 00368 sys->nlbegun = 1; 00369 } 00370 } 00371 00372 void laplacian_add_right_hand_side(LaplacianSystem *UNUSED(sys), int v, float value) 00373 { 00374 nlRightHandSideAdd(0, v, value); 00375 } 00376 00377 int laplacian_system_solve(LaplacianSystem *sys) 00378 { 00379 nlEnd(NL_MATRIX); 00380 nlEnd(NL_SYSTEM); 00381 sys->nlbegun = 0; 00382 00383 //nlPrintMatrix(); 00384 00385 return nlSolveAdvanced(NULL, NL_TRUE); 00386 } 00387 00388 float laplacian_system_get_solution(int v) 00389 { 00390 return nlGetVariable(0, v); 00391 } 00392 00393 /************************* Heat Bone Weighting ******************************/ 00394 /* From "Automatic Rigging and Animation of 3D Characters" 00395 Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */ 00396 00397 #define C_WEIGHT 1.0f 00398 #define WEIGHT_LIMIT_START 0.05f 00399 #define WEIGHT_LIMIT_END 0.025f 00400 #define DISTANCE_EPSILON 1e-4f 00401 00402 typedef struct BVHCallbackUserData { 00403 float start[3]; 00404 float vec[3]; 00405 LaplacianSystem *sys; 00406 } BVHCallbackUserData; 00407 00408 static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit) 00409 { 00410 BVHCallbackUserData *data = (struct BVHCallbackUserData*)userdata; 00411 MFace *mf = data->sys->heat.mface + index; 00412 float (*verts)[3] = data->sys->heat.verts; 00413 float lambda, uv[2], n[3], dir[3]; 00414 00415 mul_v3_v3fl(dir, data->vec, hit->dist); 00416 00417 if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) { 00418 normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]); 00419 if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { 00420 hit->index = index; 00421 hit->dist *= lambda; 00422 } 00423 } 00424 00425 mul_v3_v3fl(dir, data->vec, hit->dist); 00426 00427 if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) { 00428 normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]); 00429 if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) { 00430 hit->index = index; 00431 hit->dist *= lambda; 00432 } 00433 } 00434 } 00435 00436 /* Raytracing for vertex to bone/vertex visibility */ 00437 static void heat_ray_tree_create(LaplacianSystem *sys) 00438 { 00439 MFace *mface = sys->heat.mface; 00440 float (*verts)[3] = sys->heat.verts; 00441 int totface = sys->heat.totface; 00442 int totvert = sys->heat.totvert; 00443 int a; 00444 00445 sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6); 00446 sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces"); 00447 00448 for(a=0; a<totface; a++) { 00449 MFace *mf = mface+a; 00450 float bb[6]; 00451 00452 INIT_MINMAX(bb, bb+3); 00453 DO_MINMAX(verts[mf->v1], bb, bb+3); 00454 DO_MINMAX(verts[mf->v2], bb, bb+3); 00455 DO_MINMAX(verts[mf->v3], bb, bb+3); 00456 if(mf->v4) { 00457 DO_MINMAX(verts[mf->v4], bb, bb+3); 00458 } 00459 00460 BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2); 00461 00462 //Setup inverse pointers to use on isect.orig 00463 sys->heat.vface[mf->v1]= mf; 00464 sys->heat.vface[mf->v2]= mf; 00465 sys->heat.vface[mf->v3]= mf; 00466 if(mf->v4) sys->heat.vface[mf->v4]= mf; 00467 } 00468 00469 BLI_bvhtree_balance(sys->heat.bvhtree); 00470 } 00471 00472 static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source) 00473 { 00474 BVHTreeRayHit hit; 00475 BVHCallbackUserData data; 00476 MFace *mface; 00477 float end[3]; 00478 int visible; 00479 00480 mface= sys->heat.vface[vertex]; 00481 if(!mface) 00482 return 1; 00483 00484 data.sys= sys; 00485 copy_v3_v3(data.start, sys->heat.verts[vertex]); 00486 00487 if(sys->heat.root) /* bone */ 00488 closest_to_line_segment_v3(end, data.start, 00489 sys->heat.root[source], sys->heat.tip[source]); 00490 else /* vertex */ 00491 copy_v3_v3(end, sys->heat.source[source]); 00492 00493 sub_v3_v3v3(data.vec, end, data.start); 00494 madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5); 00495 mul_v3_fl(data.vec, 1.0f - 2e-5f); 00496 00497 /* pass normalized vec + distance to bvh */ 00498 hit.index = -1; 00499 hit.dist = normalize_v3(data.vec); 00500 00501 visible= BLI_bvhtree_ray_cast(sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void*)&data) == -1; 00502 00503 return visible; 00504 } 00505 00506 static float heat_source_distance(LaplacianSystem *sys, int vertex, int source) 00507 { 00508 float closest[3], d[3], dist, cosine; 00509 00510 /* compute euclidian distance */ 00511 if(sys->heat.root) /* bone */ 00512 closest_to_line_segment_v3(closest, sys->heat.verts[vertex], 00513 sys->heat.root[source], sys->heat.tip[source]); 00514 else /* vertex */ 00515 copy_v3_v3(closest, sys->heat.source[source]); 00516 00517 sub_v3_v3v3(d, sys->heat.verts[vertex], closest); 00518 dist= normalize_v3(d); 00519 00520 /* if the vertex normal does not point along the bone, increase distance */ 00521 cosine= INPR(d, sys->heat.vnors[vertex]); 00522 00523 return dist/(0.5f*(cosine + 1.001f)); 00524 } 00525 00526 static int heat_source_closest(LaplacianSystem *sys, int vertex, int source) 00527 { 00528 float dist; 00529 00530 dist= heat_source_distance(sys, vertex, source); 00531 00532 if(dist <= sys->heat.mindist[vertex]*(1.0f + DISTANCE_EPSILON)) 00533 if(heat_ray_source_visible(sys, vertex, source)) 00534 return 1; 00535 00536 return 0; 00537 } 00538 00539 static void heat_set_H(LaplacianSystem *sys, int vertex) 00540 { 00541 float dist, mindist, h; 00542 int j, numclosest = 0; 00543 00544 mindist= 1e10; 00545 00546 /* compute minimum distance */ 00547 for(j=0; j<sys->heat.numsource; j++) { 00548 dist= heat_source_distance(sys, vertex, j); 00549 00550 if(dist < mindist) 00551 mindist= dist; 00552 } 00553 00554 sys->heat.mindist[vertex]= mindist; 00555 00556 /* count number of sources with approximately this minimum distance */ 00557 for(j=0; j<sys->heat.numsource; j++) 00558 if(heat_source_closest(sys, vertex, j)) 00559 numclosest++; 00560 00561 sys->heat.p[vertex]= (numclosest > 0)? 1.0f/numclosest: 0.0f; 00562 00563 /* compute H entry */ 00564 if(numclosest > 0) { 00565 mindist= maxf(mindist, 1e-4f); 00566 h= numclosest*C_WEIGHT/(mindist*mindist); 00567 } 00568 else 00569 h= 0.0f; 00570 00571 sys->heat.H[vertex]= h; 00572 } 00573 00574 static void heat_calc_vnormals(LaplacianSystem *sys) 00575 { 00576 float fnor[3]; 00577 int a, v1, v2, v3, (*face)[3]; 00578 00579 sys->heat.vnors= MEM_callocN(sizeof(float)*3*sys->totvert, "HeatVNors"); 00580 00581 for(a=0, face=sys->faces; a<sys->totface; a++, face++) { 00582 v1= (*face)[0]; 00583 v2= (*face)[1]; 00584 v3= (*face)[2]; 00585 00586 normal_tri_v3( fnor,sys->verts[v1], sys->verts[v2], sys->verts[v3]); 00587 00588 add_v3_v3(sys->heat.vnors[v1], fnor); 00589 add_v3_v3(sys->heat.vnors[v2], fnor); 00590 add_v3_v3(sys->heat.vnors[v3], fnor); 00591 } 00592 00593 for(a=0; a<sys->totvert; a++) 00594 normalize_v3(sys->heat.vnors[a]); 00595 } 00596 00597 static void heat_laplacian_create(LaplacianSystem *sys) 00598 { 00599 MFace *mface = sys->heat.mface, *mf; 00600 int totface= sys->heat.totface; 00601 int totvert= sys->heat.totvert; 00602 int a; 00603 00604 /* heat specific definitions */ 00605 sys->heat.mindist= MEM_callocN(sizeof(float)*totvert, "HeatMinDist"); 00606 sys->heat.H= MEM_callocN(sizeof(float)*totvert, "HeatH"); 00607 sys->heat.p= MEM_callocN(sizeof(float)*totvert, "HeatP"); 00608 00609 /* add verts and faces to laplacian */ 00610 for(a=0; a<totvert; a++) 00611 laplacian_add_vertex(sys, sys->heat.verts[a], 0); 00612 00613 for(a=0, mf=mface; a<totface; a++, mf++) { 00614 laplacian_add_triangle(sys, mf->v1, mf->v2, mf->v3); 00615 if(mf->v4) 00616 laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4); 00617 } 00618 00619 /* for distance computation in set_H */ 00620 heat_calc_vnormals(sys); 00621 00622 for(a=0; a<totvert; a++) 00623 heat_set_H(sys, a); 00624 } 00625 00626 static void heat_system_free(LaplacianSystem *sys) 00627 { 00628 BLI_bvhtree_free(sys->heat.bvhtree); 00629 MEM_freeN(sys->heat.vface); 00630 00631 MEM_freeN(sys->heat.mindist); 00632 MEM_freeN(sys->heat.H); 00633 MEM_freeN(sys->heat.p); 00634 MEM_freeN(sys->heat.vnors); 00635 } 00636 00637 static float heat_limit_weight(float weight) 00638 { 00639 float t; 00640 00641 if(weight < WEIGHT_LIMIT_END) { 00642 return 0.0f; 00643 } 00644 else if(weight < WEIGHT_LIMIT_START) { 00645 t= (weight - WEIGHT_LIMIT_END)/(WEIGHT_LIMIT_START - WEIGHT_LIMIT_END); 00646 return t*WEIGHT_LIMIT_START; 00647 } 00648 else 00649 return weight; 00650 } 00651 00652 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, const char **err_str) 00653 { 00654 LaplacianSystem *sys; 00655 MFace *mface; 00656 float solution, weight; 00657 int *vertsflipped = NULL, *mask= NULL; 00658 int a, totface, j, bbone, firstsegment, lastsegment; 00659 00660 *err_str= NULL; 00661 00662 /* count triangles and create mask */ 00663 if(me->editflag & ME_EDIT_PAINT_MASK) 00664 mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask"); 00665 00666 for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) { 00667 totface++; 00668 if(mface->v4) totface++; 00669 00670 if(mask && (mface->flag & ME_FACE_SEL)) { 00671 mask[mface->v1]= 1; 00672 mask[mface->v2]= 1; 00673 mask[mface->v3]= 1; 00674 if(mface->v4) 00675 mask[mface->v4]= 1; 00676 } 00677 } 00678 00679 /* create laplacian */ 00680 sys = laplacian_system_construct_begin(me->totvert, totface, 1); 00681 00682 sys->heat.mface= me->mface; 00683 sys->heat.totface= me->totface; 00684 sys->heat.totvert= me->totvert; 00685 sys->heat.verts= verts; 00686 sys->heat.root= root; 00687 sys->heat.tip= tip; 00688 sys->heat.numsource= numsource; 00689 00690 heat_ray_tree_create(sys); 00691 heat_laplacian_create(sys); 00692 00693 laplacian_system_construct_end(sys); 00694 00695 if(dgroupflip) { 00696 vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped"); 00697 for(a=0; a<me->totvert; a++) 00698 vertsflipped[a] = mesh_get_x_mirror_vert(ob, a); 00699 } 00700 00701 /* compute weights per bone */ 00702 for(j=0; j<numsource; j++) { 00703 if(!selected[j]) 00704 continue; 00705 00706 firstsegment= (j == 0 || dgrouplist[j-1] != dgrouplist[j]); 00707 lastsegment= (j == numsource-1 || dgrouplist[j] != dgrouplist[j+1]); 00708 bbone= !(firstsegment && lastsegment); 00709 00710 /* clear weights */ 00711 if(bbone && firstsegment) { 00712 for(a=0; a<me->totvert; a++) { 00713 if(mask && !mask[a]) 00714 continue; 00715 00716 ED_vgroup_vert_remove(ob, dgrouplist[j], a); 00717 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) 00718 ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); 00719 } 00720 } 00721 00722 /* fill right hand side */ 00723 laplacian_begin_solve(sys, -1); 00724 00725 for(a=0; a<me->totvert; a++) 00726 if(heat_source_closest(sys, a, j)) 00727 laplacian_add_right_hand_side(sys, a, 00728 sys->heat.H[a]*sys->heat.p[a]); 00729 00730 /* solve */ 00731 if(laplacian_system_solve(sys)) { 00732 /* load solution into vertex groups */ 00733 for(a=0; a<me->totvert; a++) { 00734 if(mask && !mask[a]) 00735 continue; 00736 00737 solution= laplacian_system_get_solution(a); 00738 00739 if(bbone) { 00740 if(solution > 0.0f) 00741 ED_vgroup_vert_add(ob, dgrouplist[j], a, solution, 00742 WEIGHT_ADD); 00743 } 00744 else { 00745 weight= heat_limit_weight(solution); 00746 if(weight > 0.0f) 00747 ED_vgroup_vert_add(ob, dgrouplist[j], a, weight, 00748 WEIGHT_REPLACE); 00749 else 00750 ED_vgroup_vert_remove(ob, dgrouplist[j], a); 00751 } 00752 00753 /* do same for mirror */ 00754 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { 00755 if(bbone) { 00756 if(solution > 0.0f) 00757 ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], 00758 solution, WEIGHT_ADD); 00759 } 00760 else { 00761 weight= heat_limit_weight(solution); 00762 if(weight > 0.0f) 00763 ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], 00764 weight, WEIGHT_REPLACE); 00765 else 00766 ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); 00767 } 00768 } 00769 } 00770 } 00771 else if(*err_str == NULL) { 00772 *err_str= "Bone Heat Weighting: failed to find solution for one or more bones"; 00773 break; 00774 } 00775 00776 /* remove too small vertex weights */ 00777 if(bbone && lastsegment) { 00778 for(a=0; a<me->totvert; a++) { 00779 if(mask && !mask[a]) 00780 continue; 00781 00782 weight= ED_vgroup_vert_weight(ob, dgrouplist[j], a); 00783 weight= heat_limit_weight(weight); 00784 if(weight <= 0.0f) 00785 ED_vgroup_vert_remove(ob, dgrouplist[j], a); 00786 00787 if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { 00788 weight= ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]); 00789 weight= heat_limit_weight(weight); 00790 if(weight <= 0.0f) 00791 ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); 00792 } 00793 } 00794 } 00795 } 00796 00797 /* free */ 00798 if(vertsflipped) MEM_freeN(vertsflipped); 00799 if(mask) MEM_freeN(mask); 00800 00801 heat_system_free(sys); 00802 00803 laplacian_system_delete(sys); 00804 } 00805 00806 #ifdef RIGID_DEFORM 00807 /********************** As-Rigid-As-Possible Deformation ******************/ 00808 /* From "As-Rigid-As-Possible Surface Modeling", 00809 Olga Sorkine and Marc Alexa, ESGP 2007. */ 00810 00811 /* investigate: 00812 - transpose R in orthogonal 00813 - flipped normals and per face adding 00814 - move cancelling to transform, make origco pointer 00815 */ 00816 00817 static LaplacianSystem *RigidDeformSystem = NULL; 00818 00819 static void rigid_add_half_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w) 00820 { 00821 float e[3], e_[3]; 00822 int i; 00823 00824 sub_v3_v3v3(e, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]); 00825 sub_v3_v3v3(e_, v1->co, v2->co); 00826 00827 /* formula (5) */ 00828 for (i=0; i<3; i++) { 00829 sys->rigid.R[v1->tmp.l][i][0] += w*e[0]*e_[i]; 00830 sys->rigid.R[v1->tmp.l][i][1] += w*e[1]*e_[i]; 00831 sys->rigid.R[v1->tmp.l][i][2] += w*e[2]*e_[i]; 00832 } 00833 } 00834 00835 static void rigid_add_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w) 00836 { 00837 rigid_add_half_edge_to_R(sys, v1, v2, w); 00838 rigid_add_half_edge_to_R(sys, v2, v1, w); 00839 } 00840 00841 static void rigid_orthogonalize_R(float R[][3]) 00842 { 00843 HMatrix M, Q, S; 00844 00845 copy_m4_m3(M, R); 00846 polar_decomp(M, Q, S); 00847 copy_m3_m4(R, Q); 00848 } 00849 00850 static void rigid_add_half_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w) 00851 { 00852 /* formula (8) */ 00853 float Rsum[3][3], rhs[3]; 00854 00855 if (sys->vpinned[v1->tmp.l]) 00856 return; 00857 00858 add_m3_m3m3(Rsum, sys->rigid.R[v1->tmp.l], sys->rigid.R[v2->tmp.l]); 00859 transpose_m3(Rsum); 00860 00861 sub_v3_v3v3(rhs, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]); 00862 mul_m3_v3(Rsum, rhs); 00863 mul_v3_fl(rhs, 0.5f); 00864 mul_v3_fl(rhs, w); 00865 00866 add_v3_v3(sys->rigid.rhs[v1->tmp.l], rhs); 00867 } 00868 00869 static void rigid_add_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w) 00870 { 00871 rigid_add_half_edge_to_rhs(sys, v1, v2, w); 00872 rigid_add_half_edge_to_rhs(sys, v2, v1, w); 00873 } 00874 00875 void rigid_deform_iteration() 00876 { 00877 LaplacianSystem *sys= RigidDeformSystem; 00878 EditMesh *em; 00879 EditVert *eve; 00880 EditFace *efa; 00881 int a, i; 00882 00883 if(!sys) 00884 return; 00885 00886 nlMakeCurrent(sys->context); 00887 em= sys->rigid.mesh; 00888 00889 /* compute R */ 00890 memset(sys->rigid.R, 0, sizeof(float)*3*3*sys->totvert); 00891 memset(sys->rigid.rhs, 0, sizeof(float)*3*sys->totvert); 00892 00893 for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) { 00894 rigid_add_edge_to_R(sys, efa->v1, efa->v2, sys->fweights[a][2]); 00895 rigid_add_edge_to_R(sys, efa->v2, efa->v3, sys->fweights[a][0]); 00896 rigid_add_edge_to_R(sys, efa->v3, efa->v1, sys->fweights[a][1]); 00897 00898 if(efa->v4) { 00899 a++; 00900 rigid_add_edge_to_R(sys, efa->v1, efa->v3, sys->fweights[a][2]); 00901 rigid_add_edge_to_R(sys, efa->v3, efa->v4, sys->fweights[a][0]); 00902 rigid_add_edge_to_R(sys, efa->v4, efa->v1, sys->fweights[a][1]); 00903 } 00904 } 00905 00906 for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) { 00907 rigid_orthogonalize_R(sys->rigid.R[a]); 00908 eve->tmp.l= a; 00909 } 00910 00911 /* compute right hand sides for solving */ 00912 for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) { 00913 rigid_add_edge_to_rhs(sys, efa->v1, efa->v2, sys->fweights[a][2]); 00914 rigid_add_edge_to_rhs(sys, efa->v2, efa->v3, sys->fweights[a][0]); 00915 rigid_add_edge_to_rhs(sys, efa->v3, efa->v1, sys->fweights[a][1]); 00916 00917 if(efa->v4) { 00918 a++; 00919 rigid_add_edge_to_rhs(sys, efa->v1, efa->v3, sys->fweights[a][2]); 00920 rigid_add_edge_to_rhs(sys, efa->v3, efa->v4, sys->fweights[a][0]); 00921 rigid_add_edge_to_rhs(sys, efa->v4, efa->v1, sys->fweights[a][1]); 00922 } 00923 } 00924 00925 /* solve for positions, for X,Y and Z separately */ 00926 for(i=0; i<3; i++) { 00927 laplacian_begin_solve(sys, i); 00928 00929 for(a=0; a<sys->totvert; a++) 00930 if(!sys->vpinned[a]) 00931 laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]); 00932 00933 if(laplacian_system_solve(sys)) { 00934 for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) 00935 eve->co[i]= laplacian_system_get_solution(a); 00936 } 00937 else { 00938 if(!sys->rigid.thrownerror) { 00939 error("RigidDeform: failed to find solution."); 00940 sys->rigid.thrownerror= 1; 00941 } 00942 break; 00943 } 00944 } 00945 } 00946 00947 static void rigid_laplacian_create(LaplacianSystem *sys) 00948 { 00949 EditMesh *em = sys->rigid.mesh; 00950 EditVert *eve; 00951 EditFace *efa; 00952 int a; 00953 00954 /* add verts and faces to laplacian */ 00955 for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) { 00956 laplacian_add_vertex(sys, eve->co, eve->pinned); 00957 eve->tmp.l= a; 00958 } 00959 00960 for(efa=em->faces.first; efa; efa=efa->next) { 00961 laplacian_add_triangle(sys, 00962 efa->v1->tmp.l, efa->v2->tmp.l, efa->v3->tmp.l); 00963 if(efa->v4) 00964 laplacian_add_triangle(sys, 00965 efa->v1->tmp.l, efa->v3->tmp.l, efa->v4->tmp.l); 00966 } 00967 } 00968 00969 void rigid_deform_begin(EditMesh *em) 00970 { 00971 LaplacianSystem *sys; 00972 EditVert *eve; 00973 EditFace *efa; 00974 int a, totvert, totface; 00975 00976 /* count vertices, triangles */ 00977 for(totvert=0, eve=em->verts.first; eve; eve=eve->next) 00978 totvert++; 00979 00980 for(totface=0, efa=em->faces.first; efa; efa=efa->next) { 00981 totface++; 00982 if(efa->v4) totface++; 00983 } 00984 00985 /* create laplacian */ 00986 sys = laplacian_system_construct_begin(totvert, totface, 0); 00987 00988 sys->rigid.mesh= em; 00989 sys->rigid.R = MEM_callocN(sizeof(float)*3*3*totvert, "RigidDeformR"); 00990 sys->rigid.rhs = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformRHS"); 00991 sys->rigid.origco = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformCo"); 00992 00993 for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) 00994 copy_v3_v3(sys->rigid.origco[a], eve->co); 00995 00996 sys->areaweights= 0; 00997 sys->storeweights= 1; 00998 00999 rigid_laplacian_create(sys); 01000 01001 laplacian_system_construct_end(sys); 01002 01003 RigidDeformSystem = sys; 01004 } 01005 01006 void rigid_deform_end(int cancel) 01007 { 01008 LaplacianSystem *sys = RigidDeformSystem; 01009 01010 if(sys) { 01011 EditMesh *em = sys->rigid.mesh; 01012 EditVert *eve; 01013 int a; 01014 01015 if(cancel) 01016 for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) 01017 if(!eve->pinned) 01018 copy_v3_v3(eve->co, sys->rigid.origco[a]); 01019 01020 if(sys->rigid.R) MEM_freeN(sys->rigid.R); 01021 if(sys->rigid.rhs) MEM_freeN(sys->rigid.rhs); 01022 if(sys->rigid.origco) MEM_freeN(sys->rigid.origco); 01023 01024 /* free */ 01025 laplacian_system_delete(sys); 01026 } 01027 01028 RigidDeformSystem = NULL; 01029 } 01030 #endif 01031 01032 /************************** Harmonic Coordinates ****************************/ 01033 /* From "Harmonic Coordinates for Character Articulation", 01034 Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki, 01035 SIGGRAPH 2007. */ 01036 01037 #define EPSILON 0.0001f 01038 01039 #define MESHDEFORM_TAG_UNTYPED 0 01040 #define MESHDEFORM_TAG_BOUNDARY 1 01041 #define MESHDEFORM_TAG_INTERIOR 2 01042 #define MESHDEFORM_TAG_EXTERIOR 3 01043 01044 #define MESHDEFORM_LEN_THRESHOLD 1e-6f 01045 01046 #define MESHDEFORM_MIN_INFLUENCE 0.0005f 01047 01048 static int MESHDEFORM_OFFSET[7][3] = 01049 {{0,0,0}, {1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}}; 01050 01051 typedef struct MDefBoundIsect { 01052 float co[3], uvw[4]; 01053 int nvert, v[4], facing; 01054 float len; 01055 } MDefBoundIsect; 01056 01057 typedef struct MDefBindInfluence { 01058 struct MDefBindInfluence *next; 01059 float weight; 01060 int vertex; 01061 } MDefBindInfluence; 01062 01063 typedef struct MeshDeformBind { 01064 /* grid dimensions */ 01065 float min[3], max[3]; 01066 float width[3], halfwidth[3]; 01067 int size, size3; 01068 01069 /* meshes */ 01070 DerivedMesh *cagedm; 01071 float (*cagecos)[3]; 01072 float (*vertexcos)[3]; 01073 int totvert, totcagevert; 01074 01075 /* grids */ 01076 MemArena *memarena; 01077 MDefBoundIsect *(*boundisect)[6]; 01078 int *semibound; 01079 int *tag; 01080 float *phi, *totalphi; 01081 01082 /* mesh stuff */ 01083 int *inside; 01084 float *weights; 01085 MDefBindInfluence **dyngrid; 01086 float cagemat[4][4]; 01087 01088 /* direct solver */ 01089 int *varidx; 01090 } MeshDeformBind; 01091 01092 typedef struct MeshDeformIsect { 01093 float start[3]; 01094 float vec[3]; 01095 float labda; 01096 01097 void *face; 01098 int isect; 01099 float u, v; 01100 01101 } MeshDeformIsect; 01102 01103 /* ray intersection */ 01104 01105 /* our own triangle intersection, so we can fully control the epsilons and 01106 * prevent corner case from going wrong*/ 01107 static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3], 01108 float vert1[3], float vert2[3], float *isectco, float *uvw) 01109 { 01110 float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; 01111 float det,inv_det, u, v, dir[3], isectdir[3]; 01112 01113 sub_v3_v3v3(dir, end, orig); 01114 01115 /* find vectors for two edges sharing vert0 */ 01116 sub_v3_v3v3(edge1, vert1, vert0); 01117 sub_v3_v3v3(edge2, vert2, vert0); 01118 01119 /* begin calculating determinant - also used to calculate U parameter */ 01120 cross_v3_v3v3(pvec, dir, edge2); 01121 01122 /* if determinant is near zero, ray lies in plane of triangle */ 01123 det = INPR(edge1, pvec); 01124 01125 if (det == 0.0f) 01126 return 0; 01127 inv_det = 1.0f / det; 01128 01129 /* calculate distance from vert0 to ray origin */ 01130 sub_v3_v3v3(tvec, orig, vert0); 01131 01132 /* calculate U parameter and test bounds */ 01133 u = INPR(tvec, pvec) * inv_det; 01134 if (u < -EPSILON || u > 1.0f+EPSILON) 01135 return 0; 01136 01137 /* prepare to test V parameter */ 01138 cross_v3_v3v3(qvec, tvec, edge1); 01139 01140 /* calculate V parameter and test bounds */ 01141 v = INPR(dir, qvec) * inv_det; 01142 if (v < -EPSILON || u + v > 1.0f+EPSILON) 01143 return 0; 01144 01145 isectco[0]= (1.0f - u - v)*vert0[0] + u*vert1[0] + v*vert2[0]; 01146 isectco[1]= (1.0f - u - v)*vert0[1] + u*vert1[1] + v*vert2[1]; 01147 isectco[2]= (1.0f - u - v)*vert0[2] + u*vert1[2] + v*vert2[2]; 01148 01149 uvw[0]= 1.0f - u - v; 01150 uvw[1]= u; 01151 uvw[2]= v; 01152 01153 /* check if it is within the length of the line segment */ 01154 sub_v3_v3v3(isectdir, isectco, orig); 01155 01156 if(INPR(dir, isectdir) < -EPSILON) 01157 return 0; 01158 01159 if(INPR(dir, dir) + EPSILON < INPR(isectdir, isectdir)) 01160 return 0; 01161 01162 return 1; 01163 } 01164 01165 static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec) 01166 { 01167 MFace *mface; 01168 float face[4][3], co[3], uvw[3], len, nor[3], end[3]; 01169 int f, hit, is= 0, totface; 01170 01171 isec->labda= 1e10; 01172 01173 mface= mdb->cagedm->getFaceArray(mdb->cagedm); 01174 totface= mdb->cagedm->getNumFaces(mdb->cagedm); 01175 01176 add_v3_v3v3(end, isec->start, isec->vec); 01177 01178 for(f=0; f<totface; f++, mface++) { 01179 copy_v3_v3(face[0], mdb->cagecos[mface->v1]); 01180 copy_v3_v3(face[1], mdb->cagecos[mface->v2]); 01181 copy_v3_v3(face[2], mdb->cagecos[mface->v3]); 01182 01183 if(mface->v4) { 01184 copy_v3_v3(face[3], mdb->cagecos[mface->v4]); 01185 hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); 01186 01187 if(hit) { 01188 normal_tri_v3( nor,face[0], face[1], face[2]); 01189 } 01190 else { 01191 hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw); 01192 normal_tri_v3( nor,face[0], face[2], face[3]); 01193 } 01194 } 01195 else { 01196 hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw); 01197 normal_tri_v3( nor,face[0], face[1], face[2]); 01198 } 01199 01200 if(hit) { 01201 len= len_v3v3(isec->start, co)/len_v3v3(isec->start, end); 01202 if(len < isec->labda) { 01203 isec->labda= len; 01204 isec->face = mface; 01205 isec->isect= (INPR(isec->vec, nor) <= 0.0f); 01206 is= 1; 01207 } 01208 } 01209 } 01210 01211 return is; 01212 } 01213 01214 static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2) 01215 { 01216 MDefBoundIsect *isect; 01217 MeshDeformIsect isec; 01218 float (*cagecos)[3]; 01219 MFace *mface; 01220 float vert[4][3], len, end[3]; 01221 static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4}; 01222 01223 /* setup isec */ 01224 memset(&isec, 0, sizeof(isec)); 01225 isec.labda= 1e10f; 01226 01227 VECADD(isec.start, co1, epsilon); 01228 VECADD(end, co2, epsilon); 01229 sub_v3_v3v3(isec.vec, end, isec.start); 01230 01231 if(meshdeform_intersect(mdb, &isec)) { 01232 len= isec.labda; 01233 mface=(MFace*)isec.face; 01234 01235 /* create MDefBoundIsect */ 01236 isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect)); 01237 01238 /* compute intersection coordinate */ 01239 isect->co[0]= co1[0] + isec.vec[0]*len; 01240 isect->co[1]= co1[1] + isec.vec[1]*len; 01241 isect->co[2]= co1[2] + isec.vec[2]*len; 01242 01243 isect->len= len_v3v3(co1, isect->co); 01244 if(isect->len < MESHDEFORM_LEN_THRESHOLD) 01245 isect->len= MESHDEFORM_LEN_THRESHOLD; 01246 01247 isect->v[0]= mface->v1; 01248 isect->v[1]= mface->v2; 01249 isect->v[2]= mface->v3; 01250 isect->v[3]= mface->v4; 01251 isect->nvert= (mface->v4)? 4: 3; 01252 01253 isect->facing= isec.isect; 01254 01255 /* compute mean value coordinates for interpolation */ 01256 cagecos= mdb->cagecos; 01257 copy_v3_v3(vert[0], cagecos[mface->v1]); 01258 copy_v3_v3(vert[1], cagecos[mface->v2]); 01259 copy_v3_v3(vert[2], cagecos[mface->v3]); 01260 if(mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]); 01261 interp_weights_poly_v3( isect->uvw,vert, isect->nvert, isect->co); 01262 01263 return isect; 01264 } 01265 01266 return NULL; 01267 } 01268 01269 static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co) 01270 { 01271 MDefBoundIsect *isect; 01272 float outside[3], start[3], dir[3]; 01273 int i; 01274 01275 for(i=1; i<=6; i++) { 01276 outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f)*MESHDEFORM_OFFSET[i][0]; 01277 outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1]; 01278 outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2]; 01279 01280 copy_v3_v3(start, co); 01281 sub_v3_v3v3(dir, outside, start); 01282 normalize_v3(dir); 01283 01284 isect = meshdeform_ray_tree_intersect(mdb, start, outside); 01285 if(isect && !isect->facing) 01286 return 1; 01287 } 01288 01289 return 0; 01290 } 01291 01292 /* solving */ 01293 01294 static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n) 01295 { 01296 int size= mdb->size; 01297 01298 x += MESHDEFORM_OFFSET[n][0]; 01299 y += MESHDEFORM_OFFSET[n][1]; 01300 z += MESHDEFORM_OFFSET[n][2]; 01301 01302 if(x < 0 || x >= mdb->size) 01303 return -1; 01304 if(y < 0 || y >= mdb->size) 01305 return -1; 01306 if(z < 0 || z >= mdb->size) 01307 return -1; 01308 01309 return x + y*size + z*size*size; 01310 } 01311 01312 static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center) 01313 { 01314 x += MESHDEFORM_OFFSET[n][0]; 01315 y += MESHDEFORM_OFFSET[n][1]; 01316 z += MESHDEFORM_OFFSET[n][2]; 01317 01318 center[0]= mdb->min[0] + x*mdb->width[0] + mdb->halfwidth[0]; 01319 center[1]= mdb->min[1] + y*mdb->width[1] + mdb->halfwidth[1]; 01320 center[2]= mdb->min[2] + z*mdb->width[2] + mdb->halfwidth[2]; 01321 } 01322 01323 static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z) 01324 { 01325 MDefBoundIsect *isect; 01326 float center[3], ncenter[3]; 01327 int i, a; 01328 01329 a= meshdeform_index(mdb, x, y, z, 0); 01330 meshdeform_cell_center(mdb, x, y, z, 0, center); 01331 01332 /* check each outgoing edge for intersection */ 01333 for(i=1; i<=6; i++) { 01334 if(meshdeform_index(mdb, x, y, z, i) == -1) 01335 continue; 01336 01337 meshdeform_cell_center(mdb, x, y, z, i, ncenter); 01338 01339 isect= meshdeform_ray_tree_intersect(mdb, center, ncenter); 01340 if(isect) { 01341 mdb->boundisect[a][i-1]= isect; 01342 mdb->tag[a]= MESHDEFORM_TAG_BOUNDARY; 01343 } 01344 } 01345 } 01346 01347 static void meshdeform_bind_floodfill(MeshDeformBind *mdb) 01348 { 01349 int *stack, *tag= mdb->tag; 01350 int a, b, i, xyz[3], stacksize, size= mdb->size; 01351 01352 stack= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindStack"); 01353 01354 /* we know lower left corner is EXTERIOR because of padding */ 01355 tag[0]= MESHDEFORM_TAG_EXTERIOR; 01356 stack[0]= 0; 01357 stacksize= 1; 01358 01359 /* floodfill exterior tag */ 01360 while(stacksize > 0) { 01361 a= stack[--stacksize]; 01362 01363 xyz[2]= a/(size*size); 01364 xyz[1]= (a - xyz[2]*size*size)/size; 01365 xyz[0]= a - xyz[1]*size - xyz[2]*size*size; 01366 01367 for(i=1; i<=6; i++) { 01368 b= meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i); 01369 01370 if(b != -1) { 01371 if(tag[b] == MESHDEFORM_TAG_UNTYPED || 01372 (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i-1])) { 01373 tag[b]= MESHDEFORM_TAG_EXTERIOR; 01374 stack[stacksize++]= b; 01375 } 01376 } 01377 } 01378 } 01379 01380 /* other cells are interior */ 01381 for(a=0; a<size*size*size; a++) 01382 if(tag[a]==MESHDEFORM_TAG_UNTYPED) 01383 tag[a]= MESHDEFORM_TAG_INTERIOR; 01384 01385 #if 0 01386 { 01387 int tb, ti, te, ts; 01388 tb= ti= te= ts= 0; 01389 for(a=0; a<size*size*size; a++) 01390 if(tag[a]==MESHDEFORM_TAG_BOUNDARY) 01391 tb++; 01392 else if(tag[a]==MESHDEFORM_TAG_INTERIOR) 01393 ti++; 01394 else if(tag[a]==MESHDEFORM_TAG_EXTERIOR) { 01395 te++; 01396 01397 if(mdb->semibound[a]) 01398 ts++; 01399 } 01400 01401 printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts); 01402 } 01403 #endif 01404 01405 MEM_freeN(stack); 01406 } 01407 01408 static float meshdeform_boundary_phi(MeshDeformBind *UNUSED(mdb), MDefBoundIsect *isect, int cagevert) 01409 { 01410 int a; 01411 01412 for(a=0; a<isect->nvert; a++) 01413 if(isect->v[a] == cagevert) 01414 return isect->uvw[a]; 01415 01416 return 0.0f; 01417 } 01418 01419 static float meshdeform_interp_w(MeshDeformBind *mdb, float *gridvec, float *UNUSED(vec), int UNUSED(cagevert)) 01420 { 01421 float dvec[3], ivec[3], wx, wy, wz, result=0.0f; 01422 float weight, totweight= 0.0f; 01423 int i, a, x, y, z; 01424 01425 for(i=0; i<3; i++) { 01426 ivec[i]= (int)gridvec[i]; 01427 dvec[i]= gridvec[i] - ivec[i]; 01428 } 01429 01430 for(i=0; i<8; i++) { 01431 if(i & 1) { x= ivec[0]+1; wx= dvec[0]; } 01432 else { x= ivec[0]; wx= 1.0f-dvec[0]; } 01433 01434 if(i & 2) { y= ivec[1]+1; wy= dvec[1]; } 01435 else { y= ivec[1]; wy= 1.0f-dvec[1]; } 01436 01437 if(i & 4) { z= ivec[2]+1; wz= dvec[2]; } 01438 else { z= ivec[2]; wz= 1.0f-dvec[2]; } 01439 01440 CLAMP(x, 0, mdb->size-1); 01441 CLAMP(y, 0, mdb->size-1); 01442 CLAMP(z, 0, mdb->size-1); 01443 01444 a= meshdeform_index(mdb, x, y, z, 0); 01445 weight= wx*wy*wz; 01446 result += weight*mdb->phi[a]; 01447 totweight += weight; 01448 } 01449 01450 if(totweight > 0.0f) 01451 result /= totweight; 01452 01453 return result; 01454 } 01455 01456 static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z) 01457 { 01458 int i, a; 01459 01460 a= meshdeform_index(mdb, x, y, z, 0); 01461 if(mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR) 01462 return; 01463 01464 for(i=1; i<=6; i++) 01465 if(mdb->boundisect[a][i-1]) 01466 mdb->semibound[a]= 1; 01467 } 01468 01469 static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z) 01470 { 01471 float weight, totweight= 0.0f; 01472 int i, a; 01473 01474 a= meshdeform_index(mdb, x, y, z, 0); 01475 01476 /* count weight for neighbour cells */ 01477 for(i=1; i<=6; i++) { 01478 if(meshdeform_index(mdb, x, y, z, i) == -1) 01479 continue; 01480 01481 if(mdb->boundisect[a][i-1]) 01482 weight= 1.0f/mdb->boundisect[a][i-1]->len; 01483 else if(!mdb->semibound[a]) 01484 weight= 1.0f/mdb->width[0]; 01485 else 01486 weight= 0.0f; 01487 01488 totweight += weight; 01489 } 01490 01491 return totweight; 01492 } 01493 01494 static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z) 01495 { 01496 MDefBoundIsect *isect; 01497 float weight, totweight; 01498 int i, a, acenter; 01499 01500 acenter= meshdeform_index(mdb, x, y, z, 0); 01501 if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR) 01502 return; 01503 01504 nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[acenter], 1.0f); 01505 01506 totweight= meshdeform_boundary_total_weight(mdb, x, y, z); 01507 for(i=1; i<=6; i++) { 01508 a= meshdeform_index(mdb, x, y, z, i); 01509 if(a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) 01510 continue; 01511 01512 isect= mdb->boundisect[acenter][i-1]; 01513 if (!isect) { 01514 weight= (1.0f/mdb->width[0])/totweight; 01515 nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[a], -weight); 01516 } 01517 } 01518 } 01519 01520 static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert) 01521 { 01522 MDefBoundIsect *isect; 01523 float rhs, weight, totweight; 01524 int i, a, acenter; 01525 01526 acenter= meshdeform_index(mdb, x, y, z, 0); 01527 if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR) 01528 return; 01529 01530 totweight= meshdeform_boundary_total_weight(mdb, x, y, z); 01531 for(i=1; i<=6; i++) { 01532 a= meshdeform_index(mdb, x, y, z, i); 01533 if(a == -1) 01534 continue; 01535 01536 isect= mdb->boundisect[acenter][i-1]; 01537 01538 if (isect) { 01539 weight= (1.0f/isect->len)/totweight; 01540 rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert); 01541 nlRightHandSideAdd(0, mdb->varidx[acenter], rhs); 01542 } 01543 } 01544 } 01545 01546 static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert) 01547 { 01548 MDefBoundIsect *isect; 01549 float rhs, weight, totweight; 01550 int i, a; 01551 01552 a= meshdeform_index(mdb, x, y, z, 0); 01553 if(!mdb->semibound[a]) 01554 return; 01555 01556 mdb->phi[a]= 0.0f; 01557 01558 totweight= meshdeform_boundary_total_weight(mdb, x, y, z); 01559 for(i=1; i<=6; i++) { 01560 isect= mdb->boundisect[a][i-1]; 01561 01562 if (isect) { 01563 weight= (1.0f/isect->len)/totweight; 01564 rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert); 01565 mdb->phi[a] += rhs; 01566 } 01567 } 01568 } 01569 01570 static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int UNUSED(cagevert)) 01571 { 01572 float phi, totweight; 01573 int i, a, acenter; 01574 01575 acenter= meshdeform_index(mdb, x, y, z, 0); 01576 if(mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter]) 01577 return; 01578 01579 phi= 0.0f; 01580 totweight= 0.0f; 01581 for(i=1; i<=6; i++) { 01582 a= meshdeform_index(mdb, x, y, z, i); 01583 01584 if(a != -1 && mdb->semibound[a]) { 01585 phi += mdb->phi[a]; 01586 totweight += 1.0f; 01587 } 01588 } 01589 01590 if(totweight != 0.0f) 01591 mdb->phi[acenter]= phi/totweight; 01592 } 01593 01594 static void meshdeform_matrix_solve(MeshDeformBind *mdb) 01595 { 01596 NLContext *context; 01597 float vec[3], gridvec[3]; 01598 int a, b, x, y, z, totvar; 01599 char message[1024]; 01600 01601 /* setup variable indices */ 01602 mdb->varidx= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformDSvaridx"); 01603 for(a=0, totvar=0; a<mdb->size3; a++) 01604 mdb->varidx[a]= (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)? -1: totvar++; 01605 01606 if(totvar == 0) { 01607 MEM_freeN(mdb->varidx); 01608 return; 01609 } 01610 01611 progress_bar(0, "Starting mesh deform solve"); 01612 01613 /* setup opennl solver */ 01614 nlNewContext(); 01615 context= nlGetCurrent(); 01616 01617 nlSolverParameteri(NL_NB_VARIABLES, totvar); 01618 nlSolverParameteri(NL_NB_ROWS, totvar); 01619 nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1); 01620 01621 nlBegin(NL_SYSTEM); 01622 nlBegin(NL_MATRIX); 01623 01624 /* build matrix */ 01625 for(z=0; z<mdb->size; z++) 01626 for(y=0; y<mdb->size; y++) 01627 for(x=0; x<mdb->size; x++) 01628 meshdeform_matrix_add_cell(mdb, x, y, z); 01629 01630 /* solve for each cage vert */ 01631 for(a=0; a<mdb->totcagevert; a++) { 01632 if(a != 0) { 01633 nlBegin(NL_SYSTEM); 01634 nlBegin(NL_MATRIX); 01635 } 01636 01637 /* fill in right hand side and solve */ 01638 for(z=0; z<mdb->size; z++) 01639 for(y=0; y<mdb->size; y++) 01640 for(x=0; x<mdb->size; x++) 01641 meshdeform_matrix_add_rhs(mdb, x, y, z, a); 01642 01643 nlEnd(NL_MATRIX); 01644 nlEnd(NL_SYSTEM); 01645 01646 #if 0 01647 nlPrintMatrix(); 01648 #endif 01649 01650 if(nlSolveAdvanced(NULL, NL_TRUE)) { 01651 for(z=0; z<mdb->size; z++) 01652 for(y=0; y<mdb->size; y++) 01653 for(x=0; x<mdb->size; x++) 01654 meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a); 01655 01656 for(z=0; z<mdb->size; z++) 01657 for(y=0; y<mdb->size; y++) 01658 for(x=0; x<mdb->size; x++) 01659 meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a); 01660 01661 for(b=0; b<mdb->size3; b++) { 01662 if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) 01663 mdb->phi[b]= nlGetVariable(0, mdb->varidx[b]); 01664 mdb->totalphi[b] += mdb->phi[b]; 01665 } 01666 01667 if(mdb->weights) { 01668 /* static bind : compute weights for each vertex */ 01669 for(b=0; b<mdb->totvert; b++) { 01670 if(mdb->inside[b]) { 01671 copy_v3_v3(vec, mdb->vertexcos[b]); 01672 gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0]; 01673 gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1]; 01674 gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2]; 01675 01676 mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a); 01677 } 01678 } 01679 } 01680 else { 01681 MDefBindInfluence *inf; 01682 01683 /* dynamic bind */ 01684 for(b=0; b<mdb->size3; b++) { 01685 if(mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) { 01686 inf= BLI_memarena_alloc(mdb->memarena, sizeof(*inf)); 01687 inf->vertex= a; 01688 inf->weight= mdb->phi[b]; 01689 inf->next= mdb->dyngrid[b]; 01690 mdb->dyngrid[b]= inf; 01691 } 01692 } 01693 } 01694 } 01695 else { 01696 error("Mesh Deform: failed to find solution."); 01697 break; 01698 } 01699 01700 sprintf(message, "Mesh deform solve %d / %d |||", a+1, mdb->totcagevert); 01701 progress_bar((float)(a+1)/(float)(mdb->totcagevert), message); 01702 } 01703 01704 #if 0 01705 /* sanity check */ 01706 for(b=0; b<mdb->size3; b++) 01707 if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) 01708 if(fabs(mdb->totalphi[b] - 1.0f) > 1e-4) 01709 printf("totalphi deficiency [%s|%d] %d: %.10f\n", 01710 (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR)? "interior": "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); 01711 #endif 01712 01713 /* free */ 01714 MEM_freeN(mdb->varidx); 01715 01716 nlDeleteContext(context); 01717 } 01718 01719 static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb) 01720 { 01721 MDefBindInfluence *inf; 01722 MDefInfluence *mdinf; 01723 MDefCell *cell; 01724 float center[3], vec[3], maxwidth, totweight; 01725 int a, b, x, y, z, totinside, offset; 01726 01727 /* compute bounding box of the cage mesh */ 01728 INIT_MINMAX(mdb->min, mdb->max); 01729 01730 for(a=0; a<mdb->totcagevert; a++) 01731 DO_MINMAX(mdb->cagecos[a], mdb->min, mdb->max); 01732 01733 /* allocate memory */ 01734 mdb->size= (2<<(mmd->gridsize-1)) + 2; 01735 mdb->size3= mdb->size*mdb->size*mdb->size; 01736 mdb->tag= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindTag"); 01737 mdb->phi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindPhi"); 01738 mdb->totalphi= MEM_callocN(sizeof(float)*mdb->size3, "MeshDeformBindTotalPhi"); 01739 mdb->boundisect= MEM_callocN(sizeof(*mdb->boundisect)*mdb->size3, "MDefBoundIsect"); 01740 mdb->semibound= MEM_callocN(sizeof(int)*mdb->size3, "MDefSemiBound"); 01741 01742 mdb->inside= MEM_callocN(sizeof(int)*mdb->totvert, "MDefInside"); 01743 01744 if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) 01745 mdb->dyngrid= MEM_callocN(sizeof(MDefBindInfluence*)*mdb->size3, "MDefDynGrid"); 01746 else 01747 mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights"); 01748 01749 mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena"); 01750 BLI_memarena_use_calloc(mdb->memarena); 01751 01752 /* make bounding box equal size in all directions, add padding, and compute 01753 * width of the cells */ 01754 maxwidth = -1.0f; 01755 for(a=0; a<3; a++) 01756 if(mdb->max[a]-mdb->min[a] > maxwidth) 01757 maxwidth= mdb->max[a]-mdb->min[a]; 01758 01759 for(a=0; a<3; a++) { 01760 center[a]= (mdb->min[a]+mdb->max[a])*0.5f; 01761 mdb->min[a]= center[a] - maxwidth*0.5f; 01762 mdb->max[a]= center[a] + maxwidth*0.5f; 01763 01764 mdb->width[a]= (mdb->max[a]-mdb->min[a])/(mdb->size-4); 01765 mdb->min[a] -= 2.1f*mdb->width[a]; 01766 mdb->max[a] += 2.1f*mdb->width[a]; 01767 01768 mdb->width[a]= (mdb->max[a]-mdb->min[a])/mdb->size; 01769 mdb->halfwidth[a]= mdb->width[a]*0.5f; 01770 } 01771 01772 progress_bar(0, "Setting up mesh deform system"); 01773 01774 totinside= 0; 01775 for(a=0; a<mdb->totvert; a++) { 01776 copy_v3_v3(vec, mdb->vertexcos[a]); 01777 mdb->inside[a]= meshdeform_inside_cage(mdb, vec); 01778 if(mdb->inside[a]) 01779 totinside++; 01780 } 01781 01782 /* free temporary MDefBoundIsects */ 01783 BLI_memarena_free(mdb->memarena); 01784 mdb->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena"); 01785 01786 /* start with all cells untyped */ 01787 for(a=0; a<mdb->size3; a++) 01788 mdb->tag[a]= MESHDEFORM_TAG_UNTYPED; 01789 01790 /* detect intersections and tag boundary cells */ 01791 for(z=0; z<mdb->size; z++) 01792 for(y=0; y<mdb->size; y++) 01793 for(x=0; x<mdb->size; x++) 01794 meshdeform_add_intersections(mdb, x, y, z); 01795 01796 /* compute exterior and interior tags */ 01797 meshdeform_bind_floodfill(mdb); 01798 01799 for(z=0; z<mdb->size; z++) 01800 for(y=0; y<mdb->size; y++) 01801 for(x=0; x<mdb->size; x++) 01802 meshdeform_check_semibound(mdb, x, y, z); 01803 01804 /* solve */ 01805 meshdeform_matrix_solve(mdb); 01806 01807 /* assign results */ 01808 if(mmd->flag & MOD_MDEF_DYNAMIC_BIND) { 01809 mmd->totinfluence= 0; 01810 for(a=0; a<mdb->size3; a++) 01811 for(inf=mdb->dyngrid[a]; inf; inf=inf->next) 01812 mmd->totinfluence++; 01813 01814 /* convert MDefBindInfluences to smaller MDefInfluences */ 01815 mmd->dyngrid= MEM_callocN(sizeof(MDefCell)*mdb->size3, "MDefDynGrid"); 01816 mmd->dyninfluences= MEM_callocN(sizeof(MDefInfluence)*mmd->totinfluence, "MDefInfluence"); 01817 offset= 0; 01818 for(a=0; a<mdb->size3; a++) { 01819 cell= &mmd->dyngrid[a]; 01820 cell->offset= offset; 01821 01822 totweight= 0.0f; 01823 mdinf= mmd->dyninfluences + cell->offset; 01824 for(inf=mdb->dyngrid[a]; inf; inf=inf->next, mdinf++) { 01825 mdinf->weight= inf->weight; 01826 mdinf->vertex= inf->vertex; 01827 totweight += mdinf->weight; 01828 cell->totinfluence++; 01829 } 01830 01831 if(totweight > 0.0f) { 01832 mdinf= mmd->dyninfluences + cell->offset; 01833 for(b=0; b<cell->totinfluence; b++, mdinf++) 01834 mdinf->weight /= totweight; 01835 } 01836 01837 offset += cell->totinfluence; 01838 } 01839 01840 mmd->dynverts= mdb->inside; 01841 mmd->dyngridsize= mdb->size; 01842 copy_v3_v3(mmd->dyncellmin, mdb->min); 01843 mmd->dyncellwidth= mdb->width[0]; 01844 MEM_freeN(mdb->dyngrid); 01845 } 01846 else { 01847 mmd->bindweights= mdb->weights; 01848 MEM_freeN(mdb->inside); 01849 } 01850 01851 MEM_freeN(mdb->tag); 01852 MEM_freeN(mdb->phi); 01853 MEM_freeN(mdb->totalphi); 01854 MEM_freeN(mdb->boundisect); 01855 MEM_freeN(mdb->semibound); 01856 BLI_memarena_free(mdb->memarena); 01857 } 01858 01859 #if 0 01860 static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb) 01861 { 01862 LaplacianSystem *sys; 01863 MFace *mface= dm->getFaceArray(dm), *mf; 01864 int totvert= dm->getNumVerts(dm); 01865 int totface= dm->getNumFaces(dm); 01866 float solution, weight; 01867 int a, tottri, j, thrownerror = 0; 01868 01869 mdb->weights= MEM_callocN(sizeof(float)*mdb->totvert*mdb->totcagevert, "MDefWeights"); 01870 01871 /* count triangles */ 01872 for(tottri=0, a=0, mf=mface; a<totface; a++, mf++) { 01873 tottri++; 01874 if(mf->v4) tottri++; 01875 } 01876 01877 /* create laplacian */ 01878 sys = laplacian_system_construct_begin(totvert, tottri, 1); 01879 01880 sys->heat.mface= mface; 01881 sys->heat.totface= totface; 01882 sys->heat.totvert= totvert; 01883 sys->heat.verts= mdb->vertexcos; 01884 sys->heat.source = mdb->cagecos; 01885 sys->heat.numsource= mdb->totcagevert; 01886 01887 heat_ray_tree_create(sys); 01888 heat_laplacian_create(sys); 01889 01890 laplacian_system_construct_end(sys); 01891 01892 /* compute weights per bone */ 01893 for(j=0; j<mdb->totcagevert; j++) { 01894 /* fill right hand side */ 01895 laplacian_begin_solve(sys, -1); 01896 01897 for(a=0; a<totvert; a++) 01898 if(heat_source_closest(sys, a, j)) 01899 laplacian_add_right_hand_side(sys, a, 01900 sys->heat.H[a]*sys->heat.p[a]); 01901 01902 /* solve */ 01903 if(laplacian_system_solve(sys)) { 01904 /* load solution into vertex groups */ 01905 for(a=0; a<totvert; a++) { 01906 solution= laplacian_system_get_solution(a); 01907 01908 weight= heat_limit_weight(solution); 01909 if(weight > 0.0f) 01910 mdb->weights[a*mdb->totcagevert + j] = weight; 01911 } 01912 } 01913 else if(!thrownerror) { 01914 error("Mesh Deform Heat Weighting:" 01915 " failed to find solution for one or more vertices"); 01916 thrownerror= 1; 01917 break; 01918 } 01919 } 01920 01921 /* free */ 01922 heat_system_free(sys); 01923 laplacian_system_delete(sys); 01924 01925 mmd->bindweights= mdb->weights; 01926 } 01927 #endif 01928 01929 void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[][4]) 01930 { 01931 MeshDeformBind mdb; 01932 MVert *mvert; 01933 int a; 01934 01935 waitcursor(1); 01936 start_progress_bar(); 01937 01938 memset(&mdb, 0, sizeof(MeshDeformBind)); 01939 01940 /* get mesh and cage mesh */ 01941 mdb.vertexcos= MEM_callocN(sizeof(float)*3*totvert, "MeshDeformCos"); 01942 mdb.totvert= totvert; 01943 01944 mdb.cagedm= mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH); 01945 mdb.totcagevert= mdb.cagedm->getNumVerts(mdb.cagedm); 01946 mdb.cagecos= MEM_callocN(sizeof(*mdb.cagecos)*mdb.totcagevert, "MeshDeformBindCos"); 01947 copy_m4_m4(mdb.cagemat, cagemat); 01948 01949 mvert= mdb.cagedm->getVertArray(mdb.cagedm); 01950 for(a=0; a<mdb.totcagevert; a++) 01951 copy_v3_v3(mdb.cagecos[a], mvert[a].co); 01952 for(a=0; a<mdb.totvert; a++) 01953 mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a*3); 01954 01955 /* solve */ 01956 #if 0 01957 if(mmd->mode == MOD_MDEF_VOLUME) 01958 harmonic_coordinates_bind(scene, mmd, &mdb); 01959 else 01960 heat_weighting_bind(scene, dm, mmd, &mdb); 01961 #else 01962 harmonic_coordinates_bind(scene, mmd, &mdb); 01963 #endif 01964 01965 /* assign bind variables */ 01966 mmd->bindcagecos= (float*)mdb.cagecos; 01967 mmd->totvert= mdb.totvert; 01968 mmd->totcagevert= mdb.totcagevert; 01969 copy_m4_m4(mmd->bindmat, mmd->object->obmat); 01970 01971 /* transform bindcagecos to world space */ 01972 for(a=0; a<mdb.totcagevert; a++) 01973 mul_m4_v3(mmd->object->obmat, mmd->bindcagecos+a*3); 01974 01975 /* free */ 01976 mdb.cagedm->release(mdb.cagedm); 01977 MEM_freeN(mdb.vertexcos); 01978 01979 /* compact weights */ 01980 modifier_mdef_compact_influences((ModifierData*)mmd); 01981 01982 end_progress_bar(); 01983 waitcursor(0); 01984 } 01985