Shape enhanced method exaggerates a shape using a Laplacian smoothing operator in the reverse direction.

http://wiki.blender.org/index.php/User:Apinzonf/shape_enhanced
This commit is contained in:
Alexander Pinzon 2013-01-16 19:38:50 +00:00
parent 337695d496
commit f1cd290e08
4 changed files with 61 additions and 24 deletions

@ -349,6 +349,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.separator() col.separator()
col.prop(md, "use_volume_preserve") col.prop(md, "use_volume_preserve")
col.prop(md, "use_normalized")
layout.label(text="Vertex Group:") layout.label(text="Vertex Group:")
layout.prop_search(md, "vertex_group", ob, "vertex_groups", text="") layout.prop_search(md, "vertex_group", ob, "vertex_groups", text="")

@ -1133,6 +1133,7 @@ enum {
#define MOD_LAPLACIANSMOOTH_Y (1<<2) #define MOD_LAPLACIANSMOOTH_Y (1<<2)
#define MOD_LAPLACIANSMOOTH_Z (1<<3) #define MOD_LAPLACIANSMOOTH_Z (1<<3)
#define MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME (1 << 4) #define MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME (1 << 4)
#define MOD_LAPLACIANSMOOTH_NORMALIZED (1 << 5)
typedef struct LaplacianSmoothModifierData { typedef struct LaplacianSmoothModifierData {
ModifierData modifier; ModifierData modifier;

@ -1841,17 +1841,22 @@ static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Preserve Volume", "Apply volume preservation after smooth"); RNA_def_property_ui_text(prop, "Preserve Volume", "Apply volume preservation after smooth");
RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_normalized", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_NORMALIZED);
RNA_def_property_ui_text(prop, "Normalized Version", "Improves and stabilizes the shape enhanced");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "lambda_factor", PROP_FLOAT, PROP_NONE); prop = RNA_def_property(srna, "lambda_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "lambda"); RNA_def_property_float_sdna(prop, NULL, "lambda");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0000001, 1000.0, 0.0000001, 8); RNA_def_property_ui_range(prop, -1000.0, 1000.0, 0.0000001, 8);
RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect"); RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "lambda_border", PROP_FLOAT, PROP_NONE); prop = RNA_def_property(srna, "lambda_border", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "lambda_border"); RNA_def_property_float_sdna(prop, NULL, "lambda_border");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0000001, 1000.0, 0.0000001, 8); RNA_def_property_ui_range(prop, -1000.0, 1000.0, 0.0000001, 8);
RNA_def_property_ui_text(prop, "Lambda Border", "Lambda factor in border"); RNA_def_property_ui_text(prop, "Lambda Border", "Lambda factor in border");
RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_update(prop, 0, "rna_Modifier_update");

@ -82,6 +82,7 @@ typedef struct BLaplacianSystem LaplacianSystem;
static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md); static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md);
static int is_disabled(ModifierData *md, int UNUSED(useRenderParams)); 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 compute_volume(float (*vertexCos)[3], MFace *mfaces, int numFaces);
static float cotan_weight(float *v1, float *v2, float *v3); static float cotan_weight(float *v1, float *v2, float *v3);
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);
@ -93,7 +94,7 @@ 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);
static void volume_preservation(LaplacianSystem *sys, float vini, float vend, short flag); 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) static void delete_void_pointer(void *data)
{ {
@ -199,7 +200,7 @@ static void init_data(ModifierData *md)
smd->lambda = 0.00001f; smd->lambda = 0.00001f;
smd->lambda_border = 0.00005f; smd->lambda_border = 0.00005f;
smd->repeat = 1; 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'; smd->defgrp_name[0] = '\0';
} }
@ -239,6 +240,13 @@ static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md)
return dataMask; 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) static float cotan_weight(float *v1, float *v2, float *v3)
{ {
float a[3], b[3], c[3], clen; float a[3], b[3], c[3], clen;
@ -372,10 +380,16 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
if (has_4_vert) sys->zerola[idv4] = 1; if (has_4_vert) sys->zerola[idv4] = 1;
} }
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[idv1] += areaf;
sys->ring_areas[idv2] += areaf; sys->ring_areas[idv2] += areaf;
sys->ring_areas[idv3] += areaf; sys->ring_areas[idv3] += areaf;
if (has_4_vert) sys->ring_areas[idv4] += areaf; }
if (has_4_vert) { if (has_4_vert) {
@ -403,9 +417,9 @@ static void init_laplacian_matrix(LaplacianSystem *sys)
} }
} }
else { else {
w1 = cotan_weight(v1, v2, v3); w1 = cotan_weight(v1, v2, v3) / 2.0f;
w2 = cotan_weight(v2, v3, v1); w2 = cotan_weight(v2, v3, v1) / 2.0f;
w3 = cotan_weight(v3, v1, v2); w3 = cotan_weight(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;
@ -505,9 +519,10 @@ 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; int i, idv1, idv2;
float lam;
float leni, lene; float leni, lene;
float vini, vend; float vini, vend;
float *vi1, *vi2, ve1[3], ve2[3]; float *vi1, *vi2, ve1[3], ve2[3];
@ -534,14 +549,15 @@ static void validate_solution(LaplacianSystem *sys, short flag)
} }
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.0 ? 1.0 : -1.0) : (lambda_border >= 0.0 ? 1.0 : -1.0);
if (flag & MOD_LAPLACIANSMOOTH_X) { 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) { 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) { if (flag & MOD_LAPLACIANSMOOTH_Z) {
sys->vertexCos[i][2] = nlGetVariable(2, i); sys->vertexCos[i][2] += lam * (nlGetVariable(2, i) - sys->vertexCos[i][2]);
} }
} }
} }
@ -617,16 +633,30 @@ static void laplaciansmoothModifier_do(
} }
if (sys->zerola[i] == 0) { if (sys->zerola[i] == 0) {
w = sys->vweights[i] * sys->ring_areas[i]; if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) {
sys->vweights[i] = (w == 0.0f) ? 0.0f : -smd->lambda * wpaint / (4.0f * w); w = sys->vweights[i];
sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabs(smd->lambda) * wpaint / w;
w = sys->vlengths[i]; w = sys->vlengths[i];
sys->vlengths[i] = (w == 0.0f) ? 0.0f : -smd->lambda_border * wpaint * 2.0f / w; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabs(smd->lambda_border) * wpaint * 2.0f / w;
if (sys->numNeEd[i] == sys->numNeFa[i]) { if (sys->numNeEd[i] == sys->numNeFa[i]) {
nlMatrixAdd(i, i, 1.0f + smd->lambda * wpaint / (4.0f * sys->ring_areas[i])); nlMatrixAdd(i, i, 1.0f + fabs(smd->lambda) * wpaint);
} }
else { else {
nlMatrixAdd(i, i, 1.0f + smd->lambda_border * wpaint * 2.0f); nlMatrixAdd(i, i, 1.0f + fabs(smd->lambda_border) * wpaint * 2.0f);
}
}
else {
w = sys->vweights[i] * sys->ring_areas[i];
sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabs(smd->lambda) * wpaint / (4.0f * w);
w = sys->vlengths[i];
sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabs(smd->lambda_border) * wpaint * 2.0f / w;
if (sys->numNeEd[i] == sys->numNeFa[i]) {
nlMatrixAdd(i, i, 1.0f + fabs(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
}
else {
nlMatrixAdd(i, i, 1.0f + fabs(smd->lambda_border) * wpaint * 2.0f);
}
} }
} }
else { else {
@ -640,7 +670,7 @@ static void laplaciansmoothModifier_do(
nlEnd(NL_SYSTEM); nlEnd(NL_SYSTEM);
if (nlSolveAdvanced(NULL, NL_TRUE)) { if (nlSolveAdvanced(NULL, NL_TRUE)) {
validate_solution(sys, smd->flag); validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
} }
nlDeleteContext(sys->context); nlDeleteContext(sys->context);
sys->context = NULL; sys->context = NULL;