static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3]) { int vid, i, j, n, na; n = sys->total_verts; na = sys->total_anchors; #ifdef OPENNL_THREADING_HACK modifier_opennl_lock(); #endif if (!sys->is_matrix_computed) { nlNewContext(); sys->context = nlGetCurrent(); nlSolverParameteri(NL_NB_VARIABLES, n); nlSolverParameteri(NL_SYMMETRIC, NL_FALSE); nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); nlSolverParameteri(NL_NB_ROWS, n + na); nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3); nlBegin(NL_SYSTEM); for (i = 0; i < n; i++) { nlSetVariable(0, i, sys->co[i][0]); nlSetVariable(1, i, sys->co[i][1]); nlSetVariable(2, i, sys->co[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; nlSetVariable(0, vid, vertexCos[vid][0]); nlSetVariable(1, vid, vertexCos[vid][1]); nlSetVariable(2, vid, vertexCos[vid][2]); } nlBegin(NL_MATRIX); initLaplacianMatrix(sys); computeImplictRotations(sys); for (i = 0; i < n; i++) { nlRightHandSideSet(0, i, sys->delta[i][0]); nlRightHandSideSet(1, i, sys->delta[i][1]); nlRightHandSideSet(2, i, sys->delta[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; nlRightHandSideSet(0, n + i, vertexCos[vid][0]); nlRightHandSideSet(1, n + i, vertexCos[vid][1]); nlRightHandSideSet(2, n + i, vertexCos[vid][2]); nlMatrixAdd(n + i, vid, 1.0f); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (nlSolveAdvanced(NULL, NL_TRUE)) { sys->has_solution = true; for (j = 1; j <= sys->repeat; j++) { nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); rotateDifferentialCoordinates(sys); for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; nlRightHandSideSet(0, n + i, vertexCos[vid][0]); nlRightHandSideSet(1, n + i, vertexCos[vid][1]); nlRightHandSideSet(2, n + i, vertexCos[vid][2]); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (!nlSolveAdvanced(NULL, NL_FALSE)) { sys->has_solution = false; break; } } if (sys->has_solution) { for (vid = 0; vid < sys->total_verts; vid++) { vertexCos[vid][0] = nlGetVariable(0, vid); vertexCos[vid][1] = nlGetVariable(1, vid); vertexCos[vid][2] = nlGetVariable(2, vid); } } else { sys->has_solution = false; } } else { sys->has_solution = false; } sys->is_matrix_computed = true; } else if (sys->has_solution) { nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); for (i = 0; i < n; i++) { nlRightHandSideSet(0, i, sys->delta[i][0]); nlRightHandSideSet(1, i, sys->delta[i][1]); nlRightHandSideSet(2, i, sys->delta[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; nlRightHandSideSet(0, n + i, vertexCos[vid][0]); nlRightHandSideSet(1, n + i, vertexCos[vid][1]); nlRightHandSideSet(2, n + i, vertexCos[vid][2]); nlMatrixAdd(n + i, vid, 1.0f); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (nlSolveAdvanced(NULL, NL_FALSE)) { sys->has_solution = true; for (j = 1; j <= sys->repeat; j++) { nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); rotateDifferentialCoordinates(sys); for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; nlRightHandSideSet(0, n + i, vertexCos[vid][0]); nlRightHandSideSet(1, n + i, vertexCos[vid][1]); nlRightHandSideSet(2, n + i, vertexCos[vid][2]); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (!nlSolveAdvanced(NULL, NL_FALSE)) { sys->has_solution = false; break; } } if (sys->has_solution) { for (vid = 0; vid < sys->total_verts; vid++) { vertexCos[vid][0] = nlGetVariable(0, vid); vertexCos[vid][1] = nlGetVariable(1, vid); vertexCos[vid][2] = nlGetVariable(2, vid); } } else { sys->has_solution = false; } } else { sys->has_solution = false; } } #ifdef OPENNL_THREADING_HACK modifier_opennl_unlock(); #endif }
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; DM_ensure_tessface(dm); sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumTessFaces(dm), numVerts); if (!sys) { return; } sys->mfaces = dm->getTessFaceArray(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); #ifdef OPENNL_THREADING_HACK modifier_opennl_lock(); #endif nlNewContext(); sys->context = nlGetCurrent(); nlSolverParameteri(NL_NB_VARIABLES, numVerts); nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); nlSolverParameteri(NL_NB_ROWS, numVerts); nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3); init_laplacian_matrix(sys); for (iter = 0; iter < smd->repeat; iter++) { nlBegin(NL_SYSTEM); for (i = 0; i < numVerts; i++) { nlSetVariable(0, i, vertexCos[i][0]); nlSetVariable(1, i, vertexCos[i][1]); nlSetVariable(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); } nlBegin(NL_MATRIX); dv = dvert; for (i = 0; i < numVerts; i++) { nlRightHandSideSet(0, i, vertexCos[i][0]); nlRightHandSideSet(1, i, vertexCos[i][1]); nlRightHandSideSet(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]) { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint); } else { nlMatrixAdd(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]) { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); } else { nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } } else { nlMatrixAdd(i, i, 1.0f); } } } if (iter == 0) { fill_laplacian_matrix(sys); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (nlSolveAdvanced(NULL, NL_TRUE)) { validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } } nlDeleteContext(sys->context); sys->context = NULL; #ifdef OPENNL_THREADING_HACK modifier_opennl_unlock(); #endif delete_laplacian_system(sys); }
static void rotateDifferentialCoordinates(LaplacianSystem *sys) { float alpha, beta, gamma; float pj[3], ni[3], di[3]; float uij[3], dun[3], e2[3], pi[3], fni[3], vn[4][3]; int i, j, lvin, num_fni, k, fi; int *fidn; for (i = 0; i < sys->total_verts; i++) { copy_v3_v3(pi, sys->co[i]); copy_v3_v3(ni, sys->no[i]); k = sys->unit_verts[i]; copy_v3_v3(pj, sys->co[k]); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); copy_v3_v3(di, sys->delta[i]); alpha = dot_v3v3(ni, di); beta = dot_v3v3(uij, di); gamma = dot_v3v3(e2, di); pi[0] = nlGetVariable(0, i); pi[1] = nlGetVariable(1, i); pi[2] = nlGetVariable(2, i); zero_v3(ni); num_fni = 0; num_fni = sys->ringf_map[i].count; for (fi = 0; fi < num_fni; fi++) { const unsigned int *vin; fidn = sys->ringf_map[i].indices; vin = sys->faces[fidn[fi]]; lvin = vin[3] ? 4 : 3; for (j = 0; j < lvin; j++) { vn[j][0] = nlGetVariable(0, vin[j]); vn[j][1] = nlGetVariable(1, vin[j]); vn[j][2] = nlGetVariable(2, vin[j]); if (vin[j] == sys->unit_verts[i]) { copy_v3_v3(pj, vn[j]); } } if (lvin == 3) { normal_tri_v3(fni, vn[0], vn[1], vn[2]); } else if (lvin == 4) { normal_quad_v3(fni, vn[0], vn[1], vn[2], vn[3]); } add_v3_v3(ni, fni); } normalize_v3(ni); sub_v3_v3v3(uij, pj, pi); mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni)); sub_v3_v3(uij, dun); normalize_v3(uij); cross_v3_v3v3(e2, ni, uij); fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0]; fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1]; fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; if (len_squared_v3(fni) > FLT_EPSILON) { nlRightHandSideSet(0, i, fni[0]); nlRightHandSideSet(1, i, fni[1]); nlRightHandSideSet(2, i, fni[2]); } else { nlRightHandSideSet(0, i, sys->delta[i][0]); nlRightHandSideSet(1, i, sys->delta[i][1]); nlRightHandSideSet(2, i, sys->delta[i][2]); } } }