Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_laplaciansmooth.c
| Show All 28 Lines | |||||
| */ | */ | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_edgehash.h" /* for detecting missing tri edge users */ | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BKE_cdderivedmesh.h" | #include "BKE_cdderivedmesh.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "MOD_util.h" | #include "MOD_util.h" | ||||
| Show All 9 Lines | |||||
| struct BLaplacianSystem { | struct BLaplacianSystem { | ||||
| float *eweights; /* Length weights per Edge */ | float *eweights; /* Length weights per Edge */ | ||||
| float (*fweights)[3]; /* Cotangent weights per face */ | float (*fweights)[3]; /* Cotangent weights per face */ | ||||
| float *ring_areas; /* Total area per ring*/ | float *ring_areas; /* Total area per ring*/ | ||||
| float *vlengths; /* Total sum of lengths(edges) per vertice*/ | float *vlengths; /* Total sum of lengths(edges) per vertice*/ | ||||
| float *vweights; /* Total sum of weights per vertice*/ | float *vweights; /* Total sum of weights per vertice*/ | ||||
| int numEdges; /* Number of edges*/ | int numEdges; /* Number of edges*/ | ||||
| int numFaces; /* Number of faces*/ | int numTris; /* Number of triangular faces*/ | ||||
| int numVerts; /* Number of verts*/ | int numVerts; /* Number of verts*/ | ||||
| short *numNeFa; /* Number of neighboors faces around vertice*/ | short *numNeFa; /* Number of neighboors faces around vertice*/ | ||||
| short *numNeEd; /* Number of neighboors Edges around vertice*/ | short *numNeEd; /* Number of neighboors Edges around vertice*/ | ||||
| short *zerola; /* Is zero area or length*/ | short *zerola; /* Is zero area or length*/ | ||||
| /* Pointers to data*/ | /* Pointers to data*/ | ||||
| float (*vertexCos)[3]; | float (*vertexCos)[3]; | ||||
| MFace *mfaces; | const MLoopTri *mlooptris; | ||||
| MLoop *mloop; | |||||
| MEdge *medges; | MEdge *medges; | ||||
| NLContext *context; | NLContext *context; | ||||
| /*Data*/ | /*Data*/ | ||||
| float min_area; | float min_area; | ||||
| float vert_centroid[3]; | float vert_centroid[3]; | ||||
| }; | }; | ||||
| typedef struct BLaplacianSystem LaplacianSystem; | typedef struct BLaplacianSystem LaplacianSystem; | ||||
| static CustomDataMask required_data_mask(Object *ob, ModifierData *md); | static CustomDataMask required_data_mask(Object *ob, ModifierData *md); | ||||
| static bool is_disabled(ModifierData *md, int useRenderParams); | static bool is_disabled(ModifierData *md, int useRenderParams); | ||||
| static float average_area_quad_v3(float *v1, float *v2, float *v3, float *v4); | static float compute_volume(float (*vertexCos)[3], const MLoop *mloop, const MLoopTri *mlooptri, int numTris); | ||||
| static float compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces); | |||||
| static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, int a_numVerts); | static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, int a_numVerts); | ||||
| static void copy_data(ModifierData *md, ModifierData *target); | static void copy_data(ModifierData *md, ModifierData *target); | ||||
| static void delete_laplacian_system(LaplacianSystem *sys); | static void delete_laplacian_system(LaplacianSystem *sys); | ||||
| static void delete_void_pointer(void *data); | static void delete_void_pointer(void *data); | ||||
| static void fill_laplacian_matrix(LaplacianSystem *sys); | static void fill_laplacian_matrix(LaplacianSystem *sys); | ||||
| static void init_data(ModifierData *md); | static void init_data(ModifierData *md); | ||||
| static void init_laplacian_matrix(LaplacianSystem *sys); | static void init_laplacian_matrix(LaplacianSystem *sys); | ||||
| static void memset_laplacian_system(LaplacianSystem *sys, int val); | static void memset_laplacian_system(LaplacianSystem *sys, int val); | ||||
| Show All 16 Lines | static void delete_laplacian_system(LaplacianSystem *sys) | ||||
| delete_void_pointer(sys->ring_areas); | delete_void_pointer(sys->ring_areas); | ||||
| delete_void_pointer(sys->vlengths); | delete_void_pointer(sys->vlengths); | ||||
| delete_void_pointer(sys->vweights); | delete_void_pointer(sys->vweights); | ||||
| delete_void_pointer(sys->zerola); | delete_void_pointer(sys->zerola); | ||||
| if (sys->context) { | if (sys->context) { | ||||
| nlDeleteContext(sys->context); | nlDeleteContext(sys->context); | ||||
| } | } | ||||
| sys->vertexCos = NULL; | sys->vertexCos = NULL; | ||||
| sys->mfaces = NULL; | sys->mlooptris = NULL; | ||||
| sys->medges = NULL; | sys->medges = NULL; | ||||
| MEM_freeN(sys); | MEM_freeN(sys); | ||||
| } | } | ||||
| static void memset_laplacian_system(LaplacianSystem *sys, int val) | static void memset_laplacian_system(LaplacianSystem *sys, int val) | ||||
| { | { | ||||
| memset(sys->eweights, val, sizeof(float) * sys->numEdges); | memset(sys->eweights, val, sizeof(float) * sys->numEdges); | ||||
| memset(sys->fweights, val, sizeof(float) * sys->numFaces * 3); | memset(sys->fweights, val, sizeof(float) * sys->numTris * 3); | ||||
| memset(sys->numNeEd, val, sizeof(short) * sys->numVerts); | memset(sys->numNeEd, val, sizeof(short) * sys->numVerts); | ||||
| memset(sys->numNeFa, val, sizeof(short) * sys->numVerts); | memset(sys->numNeFa, val, sizeof(short) * sys->numVerts); | ||||
| memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); | memset(sys->ring_areas, val, sizeof(float) * sys->numVerts); | ||||
| memset(sys->vlengths, val, sizeof(float) * sys->numVerts); | memset(sys->vlengths, val, sizeof(float) * sys->numVerts); | ||||
| memset(sys->vweights, val, sizeof(float) * sys->numVerts); | memset(sys->vweights, val, sizeof(float) * sys->numVerts); | ||||
| memset(sys->zerola, val, sizeof(short) * sys->numVerts); | memset(sys->zerola, val, sizeof(short) * sys->numVerts); | ||||
| } | } | ||||
| static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, int a_numVerts) | static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numTris, int a_numVerts) | ||||
| { | { | ||||
| LaplacianSystem *sys; | LaplacianSystem *sys; | ||||
| sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); | sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem"); | ||||
| sys->numEdges = a_numEdges; | sys->numEdges = a_numEdges; | ||||
| sys->numFaces = a_numFaces; | sys->numTris = a_numTris; | ||||
| sys->numVerts = a_numVerts; | sys->numVerts = a_numVerts; | ||||
| sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight"); | sys->eweights = MEM_callocN(sizeof(float) * sys->numEdges, "ModLaplSmoothEWeight"); | ||||
| if (!sys->eweights) { | if (!sys->eweights) { | ||||
| delete_laplacian_system(sys); | delete_laplacian_system(sys); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| sys->fweights = MEM_callocN(sizeof(float) * 3 * sys->numFaces, "ModLaplSmoothFWeight"); | sys->fweights = MEM_callocN(sizeof(float) * 3 * sys->numTris, "ModLaplSmoothFWeight"); | ||||
| if (!sys->fweights) { | if (!sys->fweights) { | ||||
| delete_laplacian_system(sys); | delete_laplacian_system(sys); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| sys->numNeEd = MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothNumNeEd"); | sys->numNeEd = MEM_callocN(sizeof(short) * sys->numVerts, "ModLaplSmoothNumNeEd"); | ||||
| if (!sys->numNeEd) { | if (!sys->numNeEd) { | ||||
| delete_laplacian_system(sys); | delete_laplacian_system(sys); | ||||
| Show All 28 Lines | static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numTris, int a_numVerts) | ||||
| if (!sys->zerola) { | if (!sys->zerola) { | ||||
| delete_laplacian_system(sys); | delete_laplacian_system(sys); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return sys; | return sys; | ||||
| } | } | ||||
| static float average_area_quad_v3(float *v1, float *v2, float *v3, float *v4) | static float compute_volume(float (*vertexCos)[3], const MLoop *mloop, const MLoopTri *mlooptri, int numTris) | ||||
| { | |||||
| float areaq; | |||||
| 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 compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces) | |||||
| { | { | ||||
| float vol = 0.0f; | float vol = 0.0f; | ||||
| float x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4; | float x1, y1, z1, x2, y2, z2, x3, y3, z3; | ||||
| int i; | int i; | ||||
| float *vf[4]; | float *vf[3]; | ||||
| for (i = 0; i < numFaces; i++) { | |||||
| vf[0] = vertexCos[mfaces[i].v1]; | for (i = 0; i < numTris; i++) { | ||||
| vf[1] = vertexCos[mfaces[i].v2]; | vf[0] = vertexCos[mloop[mlooptri[i].tri[0]].v]; | ||||
| vf[2] = vertexCos[mfaces[i].v3]; | vf[1] = vertexCos[mloop[mlooptri[i].tri[1]].v]; | ||||
| vf[2] = vertexCos[mloop[mlooptri[i].tri[2]].v]; | |||||
| x1 = vf[0][0]; | x1 = vf[0][0]; | ||||
| y1 = vf[0][1]; | y1 = vf[0][1]; | ||||
| z1 = vf[0][2]; | z1 = vf[0][2]; | ||||
| x2 = vf[1][0]; | x2 = vf[1][0]; | ||||
| y2 = vf[1][1]; | y2 = vf[1][1]; | ||||
| z2 = vf[1][2]; | z2 = vf[1][2]; | ||||
| x3 = vf[2][0]; | x3 = vf[2][0]; | ||||
| y3 = vf[2][1]; | y3 = vf[2][1]; | ||||
| z3 = vf[2][2]; | z3 = vf[2][2]; | ||||
| vol += (1.0f / 6.0f) * (x2 * y3 * z1 + x3 * y1 * z2 - x1 * y3 * z2 - x2 * y1 * z3 + x1 * y2 * z3 - x3 * y2 * z1); | vol += (1.0f / 6.0f) * (x2 * y3 * z1 + x3 * y1 * z2 - x1 * y3 * z2 - x2 * y1 * z3 + x1 * y2 * z3 - x3 * y2 * z1); | ||||
| if ((&mfaces[i])->v4) { | |||||
| vf[3] = vertexCos[mfaces[i].v4]; | |||||
| x4 = vf[3][0]; | |||||
| y4 = vf[3][1]; | |||||
| z4 = vf[3][2]; | |||||
| vol += (1.0f / 6.0f) * (x1 * y3 * z4 - x1 * y4 * z3 - x3 * y1 * z4 + x3 * z1 * y4 + y1 * x4 * z3 - x4 * y3 * z1); | |||||
| } | |||||
| } | } | ||||
| return fabsf(vol); | return fabsf(vol); | ||||
| } | } | ||||
| static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag) | static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag) | ||||
| { | { | ||||
| float beta; | float beta; | ||||
| int i; | int i; | ||||
| Show All 12 Lines | for (i = 0; i < sys->numVerts; i++) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void init_laplacian_matrix(LaplacianSystem *sys) | static void init_laplacian_matrix(LaplacianSystem *sys) | ||||
| { | { | ||||
| float *v1, *v2, *v3, *v4; | float *v1, *v2, *v3; | ||||
| float w1, w2, w3, w4; | float w1, w2, w3; | ||||
| float areaf; | float areaf; | ||||
| int i, j; | int i; | ||||
| unsigned int idv1, idv2, idv3, idv4, idv[4]; | unsigned int idv1, idv2; | ||||
| bool has_4_vert; | EdgeHash *eh = BLI_edgehash_new(__func__); | ||||
| for (i = 0; i < sys->numEdges; i++) { | for (i = 0; i < sys->numEdges; i++) { | ||||
| idv1 = sys->medges[i].v1; | idv1 = sys->medges[i].v1; | ||||
| idv2 = sys->medges[i].v2; | idv2 = sys->medges[i].v2; | ||||
| BLI_edgehash_insert(eh, idv1, idv2, &(sys->medges[i])); | |||||
| v1 = sys->vertexCos[idv1]; | v1 = sys->vertexCos[idv1]; | ||||
| v2 = sys->vertexCos[idv2]; | v2 = sys->vertexCos[idv2]; | ||||
| sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1; | sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1; | ||||
| sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1; | sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1; | ||||
| w1 = len_v3v3(v1, v2); | w1 = len_v3v3(v1, v2); | ||||
| if (w1 < sys->min_area) { | if (w1 < sys->min_area) { | ||||
| sys->zerola[idv1] = 1; | sys->zerola[idv1] = 1; | ||||
| sys->zerola[idv2] = 1; | sys->zerola[idv2] = 1; | ||||
| } | } | ||||
| else { | else { | ||||
| w1 = 1.0f / w1; | w1 = 1.0f / w1; | ||||
| } | } | ||||
| sys->eweights[i] = w1; | sys->eweights[i] = w1; | ||||
| } | } | ||||
| for (i = 0; i < sys->numFaces; i++) { | for (i = 0; i < sys->numTris; i++) { | ||||
| has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0; | unsigned int idv[3]; | ||||
| MEdge *e[3]; | |||||
| idv1 = sys->mfaces[i].v1; | idv[0] = sys->mloop[sys->mlooptris[i].tri[0]].v; | ||||
| idv2 = sys->mfaces[i].v2; | idv[1] = sys->mloop[sys->mlooptris[i].tri[1]].v; | ||||
| idv3 = sys->mfaces[i].v3; | idv[2] = sys->mloop[sys->mlooptris[i].tri[2]].v; | ||||
| idv4 = has_4_vert ? sys->mfaces[i].v4 : 0; | |||||
| sys->numNeFa[idv1] += 1; | |||||
| sys->numNeFa[idv2] += 1; | |||||
| sys->numNeFa[idv3] += 1; | |||||
| if (has_4_vert) sys->numNeFa[idv4] += 1; | |||||
| v1 = sys->vertexCos[idv1]; | |||||
| v2 = sys->vertexCos[idv2]; | |||||
| v3 = sys->vertexCos[idv3]; | |||||
| v4 = has_4_vert ? sys->vertexCos[idv4] : NULL; | |||||
| if (has_4_vert) { | /* only increment if we find an edge user for this vert combination */ | ||||
| areaf = area_quad_v3(v1, v2, v3, sys->vertexCos[sys->mfaces[i].v4]); | e[0] = BLI_edgehash_lookup(eh, idv[0], idv[1]); | ||||
| } | if (e[0]) { | ||||
| else { | sys->numNeFa[idv[0]] += 1; | ||||
| areaf = area_tri_v3(v1, v2, v3); | |||||
| } | |||||
| if (fabsf(areaf) < sys->min_area) { | |||||
| sys->zerola[idv1] = 1; | |||||
| sys->zerola[idv2] = 1; | |||||
| sys->zerola[idv3] = 1; | |||||
| if (has_4_vert) sys->zerola[idv4] = 1; | |||||
| } | } | ||||
| if (has_4_vert) { | e[1] = BLI_edgehash_lookup(eh, idv[1], idv[2]); | ||||
| sys->ring_areas[idv1] += average_area_quad_v3(v1, v2, v3, v4); | if (e[1]) { | ||||
| sys->ring_areas[idv2] += average_area_quad_v3(v2, v3, v4, v1); | sys->numNeFa[idv[1]] += 1; | ||||
| 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) { | |||||
| idv[0] = idv1; | |||||
| idv[1] = idv2; | |||||
| idv[2] = idv3; | |||||
| idv[3] = idv4; | |||||
| for (j = 0; j < 4; j++) { | |||||
| idv1 = idv[j]; | |||||
| idv2 = idv[(j + 1) % 4]; | |||||
| idv3 = idv[(j + 2) % 4]; | |||||
| idv4 = idv[(j + 3) % 4]; | |||||
| v1 = sys->vertexCos[idv1]; | e[2] = BLI_edgehash_lookup(eh, idv[0], idv[2]); | ||||
| v2 = sys->vertexCos[idv2]; | if (e[2]) { | ||||
| v3 = sys->vertexCos[idv3]; | sys->numNeFa[idv[2]] += 1; | ||||
| v4 = sys->vertexCos[idv4]; | } | ||||
| w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); | v1 = sys->vertexCos[idv[0]]; | ||||
| w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); | v2 = sys->vertexCos[idv[1]]; | ||||
| w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); | v3 = sys->vertexCos[idv[2]]; | ||||
| areaf = area_tri_v3(v1, v2, v3); | |||||
| sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f; | if (fabsf(areaf) < sys->min_area) { | ||||
| } | sys->zerola[idv[0]] = 1; | ||||
| sys->zerola[idv[1]] = 1; | |||||
| sys->zerola[idv[2]] = 1; | |||||
| } | } | ||||
| else { | |||||
| sys->ring_areas[idv[0]] += areaf; | |||||
| sys->ring_areas[idv[1]] += areaf; | |||||
| sys->ring_areas[idv[2]] += areaf; | |||||
| w1 = cotangent_tri_weight_v3(v1, v2, v3) / 2.0f; | w1 = cotangent_tri_weight_v3(v1, v2, v3) / 2.0f; | ||||
| w2 = cotangent_tri_weight_v3(v2, v3, v1) / 2.0f; | w2 = cotangent_tri_weight_v3(v2, v3, v1) / 2.0f; | ||||
| w3 = cotangent_tri_weight_v3(v3, v1, v2) / 2.0f; | w3 = cotangent_tri_weight_v3(v3, v1, v2) / 2.0f; | ||||
| sys->fweights[i][0] = sys->fweights[i][0] + w1; | sys->fweights[i][0] = sys->fweights[i][0] + w1; | ||||
| sys->fweights[i][1] = sys->fweights[i][1] + w2; | sys->fweights[i][1] = sys->fweights[i][1] + w2; | ||||
campbellbarton: On IRC you reported that the results with this patch were different from 2.75a.
This would… | |||||
| sys->fweights[i][2] = sys->fweights[i][2] + w3; | sys->fweights[i][2] = sys->fweights[i][2] + w3; | ||||
| sys->vweights[idv1] = sys->vweights[idv1] + w2 + w3; | sys->vweights[idv[0]] = sys->vweights[idv[0]] + w2 + w3; | ||||
| sys->vweights[idv2] = sys->vweights[idv2] + w1 + w3; | sys->vweights[idv[1]] = sys->vweights[idv[1]] + w1 + w3; | ||||
| sys->vweights[idv3] = sys->vweights[idv3] + w1 + w2; | sys->vweights[idv[2]] = sys->vweights[idv[2]] + w1 + w2; | ||||
| } | |||||
| } | } | ||||
| for (i = 0; i < sys->numEdges; i++) { | for (i = 0; i < sys->numEdges; i++) { | ||||
| idv1 = sys->medges[i].v1; | idv1 = sys->medges[i].v1; | ||||
| idv2 = sys->medges[i].v2; | idv2 = sys->medges[i].v2; | ||||
| /* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */ | /* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */ | ||||
| if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { | if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) { | ||||
| sys->vlengths[idv1] += sys->eweights[i]; | sys->vlengths[idv1] += sys->eweights[i]; | ||||
| sys->vlengths[idv2] += sys->eweights[i]; | sys->vlengths[idv2] += sys->eweights[i]; | ||||
| } | } | ||||
| } | } | ||||
| BLI_edgehash_free(eh, NULL); | |||||
| } | } | ||||
| static void fill_laplacian_matrix(LaplacianSystem *sys) | static void fill_laplacian_matrix(LaplacianSystem *sys) | ||||
| { | { | ||||
| float *v1, *v2, *v3, *v4; | int i; | ||||
| float w2, w3, w4; | unsigned int idv1, idv2; | ||||
| int i, j; | |||||
| bool has_4_vert; | |||||
| unsigned int idv1, idv2, idv3, idv4, idv[4]; | |||||
| for (i = 0; i < sys->numFaces; i++) { | |||||
| idv1 = sys->mfaces[i].v1; | |||||
| idv2 = sys->mfaces[i].v2; | |||||
| idv3 = sys->mfaces[i].v3; | |||||
| has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0; | |||||
| if (has_4_vert) { | |||||
| idv[0] = sys->mfaces[i].v1; | |||||
| idv[1] = sys->mfaces[i].v2; | |||||
| idv[2] = sys->mfaces[i].v3; | |||||
| idv[3] = sys->mfaces[i].v4; | |||||
| for (j = 0; j < 4; j++) { | |||||
| idv1 = idv[j]; | |||||
| idv2 = idv[(j + 1) % 4]; | |||||
| idv3 = idv[(j + 2) % 4]; | |||||
| idv4 = idv[(j + 3) % 4]; | |||||
| v1 = sys->vertexCos[idv1]; | for (i = 0; i < sys->numTris; i++) { | ||||
| v2 = sys->vertexCos[idv2]; | const unsigned int vtri[3] = { | ||||
| v3 = sys->vertexCos[idv3]; | sys->mloop[sys->mlooptris[i].tri[0]].v, | ||||
| v4 = sys->vertexCos[idv4]; | sys->mloop[sys->mlooptris[i].tri[1]].v, | ||||
| sys->mloop[sys->mlooptris[i].tri[2]].v, | |||||
| }; | |||||
| w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2); | |||||
| w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3); | |||||
| w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1); | |||||
| w2 = w2 / 4.0f; | |||||
| w3 = w3 / 4.0f; | |||||
| w4 = w4 / 4.0f; | |||||
| if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) { | |||||
| nlMatrixAdd(idv1, idv2, w2 * sys->vweights[idv1]); | |||||
| nlMatrixAdd(idv1, idv3, w3 * sys->vweights[idv1]); | |||||
| nlMatrixAdd(idv1, idv4, w4 * sys->vweights[idv1]); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* Is ring if number of faces == number of edges around vertice*/ | /* Is ring if number of faces == number of edges around vertice*/ | ||||
| if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) { | if (sys->numNeEd[vtri[0]] == sys->numNeFa[vtri[0]] && sys->zerola[vtri[0]] == 0) { | ||||
| nlMatrixAdd(idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]); | nlMatrixAdd(vtri[0], vtri[1], sys->fweights[i][2] * sys->vweights[vtri[0]]); | ||||
| nlMatrixAdd(idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]); | nlMatrixAdd(vtri[0], vtri[2], sys->fweights[i][1] * sys->vweights[vtri[0]]); | ||||
| } | } | ||||
| if (sys->numNeEd[idv2] == sys->numNeFa[idv2] && sys->zerola[idv2] == 0) { | if (sys->numNeEd[vtri[1]] == sys->numNeFa[vtri[1]] && sys->zerola[vtri[1]] == 0) { | ||||
| nlMatrixAdd(idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]); | nlMatrixAdd(vtri[1], vtri[0], sys->fweights[i][2] * sys->vweights[vtri[1]]); | ||||
| nlMatrixAdd(idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]); | nlMatrixAdd(vtri[1], vtri[2], sys->fweights[i][0] * sys->vweights[vtri[1]]); | ||||
| } | } | ||||
| if (sys->numNeEd[idv3] == sys->numNeFa[idv3] && sys->zerola[idv3] == 0) { | if (sys->numNeEd[vtri[2]] == sys->numNeFa[vtri[2]] && sys->zerola[vtri[2]] == 0) { | ||||
| nlMatrixAdd(idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]); | nlMatrixAdd(vtri[2], vtri[0], sys->fweights[i][1] * sys->vweights[vtri[2]]); | ||||
| nlMatrixAdd(idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]); | nlMatrixAdd(vtri[2], vtri[1], sys->fweights[i][0] * sys->vweights[vtri[2]]); | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| for (i = 0; i < sys->numEdges; i++) { | for (i = 0; i < sys->numEdges; i++) { | ||||
| idv1 = sys->medges[i].v1; | idv1 = sys->medges[i].v1; | ||||
| idv2 = sys->medges[i].v2; | idv2 = sys->medges[i].v2; | ||||
| /* Is boundary */ | /* Is boundary */ | ||||
| if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && | if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && | ||||
| Show All 9 Lines | |||||
| static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border) | static void validate_solution(LaplacianSystem *sys, short flag, float lambda, float lambda_border) | ||||
| { | { | ||||
| int i; | int i; | ||||
| float lam; | float lam; | ||||
| float vini, vend; | float vini, vend; | ||||
| if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { | if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { | ||||
| vini = compute_volume(sys->vertexCos, sys->mfaces, sys->numFaces); | vini = compute_volume(sys->vertexCos, sys->mloop, sys->mlooptris, sys->numTris); | ||||
| } | } | ||||
| for (i = 0; i < sys->numVerts; i++) { | for (i = 0; i < sys->numVerts; i++) { | ||||
| if (sys->zerola[i] == 0) { | 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); | 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) { | if (flag & MOD_LAPLACIANSMOOTH_X) { | ||||
| sys->vertexCos[i][0] += lam * ((float)nlGetVariable(0, i) - sys->vertexCos[i][0]); | sys->vertexCos[i][0] += lam * ((float)nlGetVariable(0, i) - sys->vertexCos[i][0]); | ||||
| } | } | ||||
| if (flag & MOD_LAPLACIANSMOOTH_Y) { | if (flag & MOD_LAPLACIANSMOOTH_Y) { | ||||
| sys->vertexCos[i][1] += lam * ((float)nlGetVariable(1, i) - sys->vertexCos[i][1]); | sys->vertexCos[i][1] += lam * ((float)nlGetVariable(1, i) - sys->vertexCos[i][1]); | ||||
| } | } | ||||
| if (flag & MOD_LAPLACIANSMOOTH_Z) { | if (flag & MOD_LAPLACIANSMOOTH_Z) { | ||||
| sys->vertexCos[i][2] += lam * ((float)nlGetVariable(2, i) - sys->vertexCos[i][2]); | sys->vertexCos[i][2] += lam * ((float)nlGetVariable(2, i) - sys->vertexCos[i][2]); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { | if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) { | ||||
| vend = compute_volume(sys->vertexCos, sys->mfaces, sys->numFaces); | vend = compute_volume(sys->vertexCos, sys->mloop, sys->mlooptris, sys->numTris); | ||||
| volume_preservation(sys, vini, vend, flag); | volume_preservation(sys, vini, vend, flag); | ||||
| } | } | ||||
| } | } | ||||
| static void laplaciansmoothModifier_do( | static void laplaciansmoothModifier_do( | ||||
| LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, | LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, | ||||
| float (*vertexCos)[3], int numVerts) | float (*vertexCos)[3], int numVerts) | ||||
| { | { | ||||
| LaplacianSystem *sys; | LaplacianSystem *sys; | ||||
| MDeformVert *dvert = NULL; | MDeformVert *dvert = NULL; | ||||
| MDeformVert *dv = NULL; | MDeformVert *dv = NULL; | ||||
| float w, wpaint; | float w, wpaint; | ||||
| int i, iter; | int i, iter; | ||||
| int defgrp_index; | int defgrp_index; | ||||
| DM_ensure_tessface(dm); | DM_ensure_looptri(dm); | ||||
| sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumTessFaces(dm), numVerts); | sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumLoopTri(dm), numVerts); | ||||
| if (!sys) { | if (!sys) { | ||||
| return; | return; | ||||
| } | } | ||||
| sys->mfaces = dm->getTessFaceArray(dm); | sys->mlooptris = dm->getLoopTriArray(dm); | ||||
| sys->mloop = dm->getLoopArray(dm); | |||||
| sys->medges = dm->getEdgeArray(dm); | sys->medges = dm->getEdgeArray(dm); | ||||
| sys->vertexCos = vertexCos; | sys->vertexCos = vertexCos; | ||||
| sys->min_area = 0.00001f; | sys->min_area = 0.00001f; | ||||
| modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); | modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); | ||||
| sys->vert_centroid[0] = 0.0f; | sys->vert_centroid[0] = 0.0f; | ||||
| sys->vert_centroid[1] = 0.0f; | sys->vert_centroid[1] = 0.0f; | ||||
| sys->vert_centroid[2] = 0.0f; | sys->vert_centroid[2] = 0.0f; | ||||
| ▲ Show 20 Lines • Show All 214 Lines • Show Last 20 Lines | |||||
On IRC you reported that the results with this patch were different from 2.75a.
This would definitely be one reason why, since its adding the weight of a tessellated corner.
I think its worth to investigate supporting ngon's for this code, where each corner is calculated and evaluated based on the 2 adjacent verts of the loop. And the area is calculated on the polygon.