static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb) { LinearSolver *context; float vec[3], gridvec[3]; int a, b, x, y, z, totvar; char message[256]; /* setup variable indices */ mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx"); for (a = 0, totvar = 0; a < mdb->size3; a++) mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++; if (totvar == 0) { MEM_freeN(mdb->varidx); return; } progress_bar(0, "Starting mesh deform solve"); /* setup linear solver */ context = EIG_linear_solver_new(totvar, totvar, 1); /* build matrix */ for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_cell(mdb, context, x, y, z); /* solve for each cage vert */ for (a = 0; a < mdb->totcagevert; a++) { /* fill in right hand side and solve */ for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_rhs(mdb, context, x, y, z, a); if (EIG_linear_solver_solve(context)) { for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a); for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a); for (b = 0; b < mdb->size3; b++) { if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]); mdb->totalphi[b] += mdb->phi[b]; } if (mdb->weights) { /* static bind : compute weights for each vertex */ for (b = 0; b < mdb->totvert; b++) { if (mdb->inside[b]) { copy_v3_v3(vec, mdb->vertexcos[b]); gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0]; gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1]; gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2]; mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a); } } } else { MDefBindInfluence *inf; /* dynamic bind */ for (b = 0; b < mdb->size3; b++) { if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) { inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf)); inf->vertex = a; inf->weight = mdb->phi[b]; inf->next = mdb->dyngrid[b]; mdb->dyngrid[b] = inf; } } } } else { modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)"); error("Mesh Deform: failed to find bind solution."); break; } BLI_snprintf(message, sizeof(message), "Mesh deform solve %d / %d |||", a + 1, mdb->totcagevert); progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message); } #if 0 /* sanity check */ for (b = 0; b < mdb->size3; b++) if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f) printf("totalphi deficiency [%s|%d] %d: %.10f\n", (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); #endif /* free */ MEM_freeN(mdb->varidx); EIG_linear_solver_delete(context); }
static void meshdeform_matrix_solve(MeshDeformBind *mdb) { NLContext *context; float vec[3], gridvec[3]; int a, b, x, y, z, totvar; char message[1024]; /* setup variable indices */ mdb->varidx= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformDSvaridx"); for(a=0, totvar=0; a<mdb->size3; a++) mdb->varidx[a]= (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)? -1: totvar++; if(totvar == 0) { MEM_freeN(mdb->varidx); return; } progress_bar(0, "Starting mesh deform solve"); /* setup opennl solver */ nlNewContext(); context= nlGetCurrent(); nlSolverParameteri(NL_NB_VARIABLES, totvar); nlSolverParameteri(NL_NB_ROWS, totvar); nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1); nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); /* build matrix */ for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_matrix_add_cell(mdb, x, y, z); /* solve for each cage vert */ for(a=0; a<mdb->totcagevert; a++) { if(a != 0) { nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); } /* fill in right hand side and solve */ for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_matrix_add_rhs(mdb, x, y, z, a); nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); #if 0 nlPrintMatrix(); #endif if(nlSolveAdvanced(NULL, NL_TRUE)) { for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a); for(z=0; z<mdb->size; z++) for(y=0; y<mdb->size; y++) for(x=0; x<mdb->size; x++) meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a); for(b=0; b<mdb->size3; b++) { if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) mdb->phi[b]= nlGetVariable(0, mdb->varidx[b]); mdb->totalphi[b] += mdb->phi[b]; } if(mdb->weights) { /* static bind : compute weights for each vertex */ for(b=0; b<mdb->totvert; b++) { if(mdb->inside[b]) { copy_v3_v3(vec, mdb->vertexcos[b]); gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0]; gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1]; gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2]; mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a); } } } else { MDefBindInfluence *inf; /* dynamic bind */ for(b=0; b<mdb->size3; b++) { if(mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) { inf= BLI_memarena_alloc(mdb->memarena, sizeof(*inf)); inf->vertex= a; inf->weight= mdb->phi[b]; inf->next= mdb->dyngrid[b]; mdb->dyngrid[b]= inf; } } } } else { error("Mesh Deform: failed to find solution."); break; } sprintf(message, "Mesh deform solve %d / %d |||", a+1, mdb->totcagevert); progress_bar((float)(a+1)/(float)(mdb->totcagevert), message); } #if 0 /* sanity check */ for(b=0; b<mdb->size3; b++) if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) if(fabs(mdb->totalphi[b] - 1.0f) > 1e-4) printf("totalphi deficiency [%s|%d] %d: %.10f\n", (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR)? "interior": "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]); #endif /* free */ MEM_freeN(mdb->varidx); nlDeleteContext(context); }