static void laplacian_system_delete(LaplacianSystem *sys) { if (sys->verts) MEM_freeN(sys->verts); if (sys->varea) MEM_freeN(sys->varea); if (sys->vpinned) MEM_freeN(sys->vpinned); if (sys->faces) MEM_freeN(sys->faces); if (sys->fweights) MEM_freeN(sys->fweights); EIG_linear_solver_delete(sys->context); MEM_freeN(sys); }
static void deleteLaplacianSystem(LaplacianSystem *sys) { MEM_SAFE_FREE(sys->co); MEM_SAFE_FREE(sys->no); MEM_SAFE_FREE(sys->delta); MEM_SAFE_FREE(sys->tris); MEM_SAFE_FREE(sys->index_anchors); MEM_SAFE_FREE(sys->unit_verts); MEM_SAFE_FREE(sys->ringf_indices); MEM_SAFE_FREE(sys->ringv_indices); MEM_SAFE_FREE(sys->ringf_map); MEM_SAFE_FREE(sys->ringv_map); if (sys->context) { EIG_linear_solver_delete(sys->context); } MEM_SAFE_FREE(sys); }
static void delete_laplacian_system(LaplacianSystem *sys) { MEM_SAFE_FREE(sys->eweights); MEM_SAFE_FREE(sys->fweights); MEM_SAFE_FREE(sys->numNeEd); MEM_SAFE_FREE(sys->numNeFa); MEM_SAFE_FREE(sys->ring_areas); MEM_SAFE_FREE(sys->vlengths); MEM_SAFE_FREE(sys->vweights); MEM_SAFE_FREE(sys->zerola); if (sys->context) { EIG_linear_solver_delete(sys->context); } sys->vertexCos = NULL; sys->mpoly = NULL; sys->mloop = NULL; sys->medges = NULL; MEM_freeN(sys); }
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 laplaciansmoothModifier_do( LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { LaplacianSystem *sys; MDeformVert *dvert = NULL; MDeformVert *dv = NULL; float w, wpaint; int i, iter; int defgrp_index; sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm), numVerts); if (!sys) { return; } sys->mpoly = dm->getPolyArray(dm); sys->mloop = dm->getLoopArray(dm); sys->medges = dm->getEdgeArray(dm); sys->vertexCos = vertexCos; sys->min_area = 0.00001f; modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); sys->vert_centroid[0] = 0.0f; sys->vert_centroid[1] = 0.0f; sys->vert_centroid[2] = 0.0f; memset_laplacian_system(sys, 0); sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3); init_laplacian_matrix(sys); for (iter = 0; iter < smd->repeat; iter++) { for (i = 0; i < numVerts; i++) { EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]); EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]); EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { add_v3_v3(sys->vert_centroid, vertexCos[i]); } } if (iter == 0 && numVerts > 0) { mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); } dv = dvert; for (i = 0; i < numVerts; i++) { EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]); EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]); EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { if (dv) { wpaint = defvert_find_weight(dv, defgrp_index); dv++; } else { wpaint = 1.0f; } if (sys->zerola[i] == 0) { if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) { w = sys->vweights[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w; w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } else { w = sys->vweights[i] * sys->ring_areas[i]; sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w); w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } } else { EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); } } } if (iter == 0) { fill_laplacian_matrix(sys); } if (EIG_linear_solver_solve(sys->context)) { validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } } EIG_linear_solver_delete(sys->context); sys->context = NULL; delete_laplacian_system(sys); }