diff options
Diffstat (limited to 'source/blender/modifiers/intern/MOD_laplaciansmooth.c')
-rw-r--r-- | source/blender/modifiers/intern/MOD_laplaciansmooth.c | 158 |
1 files changed, 87 insertions, 71 deletions
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 266226040a3..62da82a2af1 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -82,6 +82,7 @@ typedef struct BLaplacianSystem LaplacianSystem; static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md); static int is_disabled(ModifierData *md, int UNUSED(useRenderParams)); +static float average_area_quad_v3(float *v1, float *v2, float *v3, float *v4); static float compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces); static float cotan_weight(float *v1, float *v2, float *v3); static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, int a_numVerts); @@ -93,7 +94,7 @@ static void init_data(ModifierData *md); static void init_laplacian_matrix(LaplacianSystem *sys); static void memset_laplacian_system(LaplacianSystem *sys, int val); static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag); -static void validate_solution(LaplacianSystem *sys, short flag); +static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border); static void delete_void_pointer(void *data) { @@ -196,10 +197,10 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, in static void init_data(ModifierData *md) { LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md; - smd->lambda = 0.00001f; - smd->lambda_border = 0.00005f; + smd->lambda = 0.01f; + smd->lambda_border = 0.01f; smd->repeat = 1; - smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME; + smd->flag = MOD_LAPLACIANSMOOTH_X | MOD_LAPLACIANSMOOTH_Y | MOD_LAPLACIANSMOOTH_Z | MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME | MOD_LAPLACIANSMOOTH_NORMALIZED; smd->defgrp_name[0] = '\0'; } @@ -239,6 +240,13 @@ static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md) return dataMask; } +static float average_area_quad_v3(float *v1, float *v2, float *v3, float *v4) +{ + float areaq = 0.0f; + areaq = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v2, v4) + area_tri_v3(v1, v3, v4); + return areaq / 2.0f; +} + static float cotan_weight(float *v1, float *v2, float *v3) { float a[3], b[3], c[3], clen; @@ -372,10 +380,17 @@ static void init_laplacian_matrix(LaplacianSystem *sys) if (has_4_vert) sys->zerola[idv4] = 1; } - sys->ring_areas[idv1] += areaf; - sys->ring_areas[idv2] += areaf; - sys->ring_areas[idv3] += areaf; - if (has_4_vert) sys->ring_areas[idv4] += areaf; + if (has_4_vert) { + sys->ring_areas[idv1] += average_area_quad_v3(v1, v2, v3, v4); + sys->ring_areas[idv2] += average_area_quad_v3(v2, v3, v4, v1); + sys->ring_areas[idv3] += average_area_quad_v3(v3, v4, v1, v2); + sys->ring_areas[idv4] += average_area_quad_v3(v4, v1, v2, v3); + } + else { + sys->ring_areas[idv1] += areaf; + sys->ring_areas[idv2] += areaf; + sys->ring_areas[idv3] += areaf; + } if (has_4_vert) { @@ -403,9 +418,9 @@ static void init_laplacian_matrix(LaplacianSystem *sys) } } else { - w1 = cotan_weight(v1, v2, v3); - w2 = cotan_weight(v2, v3, v1); - w3 = cotan_weight(v3, v1, v2); + w1 = cotan_weight(v1, v2, v3) / 2.0f; + w2 = cotan_weight(v2, v3, v1) / 2.0f; + w3 = cotan_weight(v3, v1, v2) / 2.0f; sys->fweights[i][0] = sys->fweights[i][0] + w1; sys->fweights[i][1] = sys->fweights[i][1] + w2; @@ -505,43 +520,26 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) } } -static void validate_solution(LaplacianSystem *sys, short flag) +static void validate_solution(LaplacianSystem * sys, short flag, float lambda, float lambda_border) { - int i, idv1, idv2; - float leni, lene; + int i; + float lam; float vini, vend; - float *vi1, *vi2, ve1[3], ve2[3]; + if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { vini = compute_volume(sys->vertexCos, sys->mfaces, sys->numFaces); } - for (i = 0; i < sys->numEdges; i++) { - idv1 = sys->medges[i].v1; - idv2 = sys->medges[i].v2; - vi1 = sys->vertexCos[idv1]; - vi2 = sys->vertexCos[idv2]; - ve1[0] = nlGetVariable(0, idv1); - ve1[1] = nlGetVariable(1, idv1); - ve1[2] = nlGetVariable(2, idv1); - ve2[0] = nlGetVariable(0, idv2); - ve2[1] = nlGetVariable(1, idv2); - ve2[2] = nlGetVariable(2, idv2); - leni = len_v3v3(vi1, vi2); - lene = len_v3v3(ve1, ve2); - if (lene > leni * MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE || lene < leni * MOD_LAPLACIANSMOOTH_MIN_EDGE_PERCENTAGE) { - sys->zerola[idv1] = 1; - sys->zerola[idv2] = 1; - } - } for (i = 0; i < sys->numVerts; i++) { if (sys->zerola[i] == 0) { + lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f); if (flag & MOD_LAPLACIANSMOOTH_X) { - sys->vertexCos[i][0] = nlGetVariable(0, i); + sys->vertexCos[i][0] += lam * (nlGetVariable(0, i) - sys->vertexCos[i][0]); } if (flag & MOD_LAPLACIANSMOOTH_Y) { - sys->vertexCos[i][1] = nlGetVariable(1, i); + sys->vertexCos[i][1] += lam * (nlGetVariable(1, i) - sys->vertexCos[i][1]); } if (flag & MOD_LAPLACIANSMOOTH_Z) { - sys->vertexCos[i][2] = nlGetVariable(2, i); + sys->vertexCos[i][2] += lam * (nlGetVariable(2, i) - sys->vertexCos[i][2]); } } } @@ -578,17 +576,17 @@ static void laplaciansmoothModifier_do( sys->vert_centroid[0] = 0.0f; sys->vert_centroid[1] = 0.0f; sys->vert_centroid[2] = 0.0f; - for (iter = 0; iter < smd->repeat; iter++) { - memset_laplacian_system(sys, 0); - 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); + memset_laplacian_system(sys, 0); + 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); + 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]); @@ -605,46 +603,64 @@ static void laplaciansmoothModifier_do( nlBegin(NL_MATRIX); dv = dvert; for (i = 0; i < numVerts; i++) { - nlRightHandSideAdd(0, i, vertexCos[i][0]); - nlRightHandSideAdd(1, i, vertexCos[i][1]); - nlRightHandSideAdd(2, i, vertexCos[i][2]); - if (dv) { - wpaint = defvert_find_weight(dv, defgrp_index); - dv++; - } - else { - wpaint = 1.0f; - } - - if (sys->zerola[i] == 0) { - w = sys->vweights[i] * sys->ring_areas[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -smd->lambda * wpaint / (4.0f * w); - w = sys->vlengths[i]; - sys->vlengths[i] = (w == 0.0f) ? 0.0f : -smd->lambda_border * wpaint * 2.0f / w; + 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->numNeEd[i] == sys->numNeFa[i]) { - nlMatrixAdd(i, i, 1.0f + smd->lambda * wpaint / (4.0f * sys->ring_areas[i])); + 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 + smd->lambda_border * wpaint * 2.0f); + nlMatrixAdd(i, i, 1.0f); } } - else { - nlMatrixAdd(i, i, 1.0f); - } } - fill_laplacian_matrix(sys); + if (iter == 0) { + fill_laplacian_matrix(sys); + } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); if (nlSolveAdvanced(NULL, NL_TRUE)) { - validate_solution(sys, smd->flag); + validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } - nlDeleteContext(sys->context); - sys->context = NULL; } + nlDeleteContext(sys->context); + sys->context = NULL; delete_laplacian_system(sys); } |