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