forked from bartvdbraak/blender
Corrective Smooth Modifier (aka delta-mush)
This modifier can be used to correct bad deformations, Original patch D1183 by @sazerac, with own modifications
This commit is contained in:
parent
660173ed72
commit
c16a8983ef
@ -1386,6 +1386,31 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
sub.active = has_vgroup
|
||||
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
|
||||
|
||||
def CORRECTIVE_SMOOTH(self, layout, ob, md):
|
||||
is_bind = md.is_bind
|
||||
|
||||
layout.prop(md, "iterations")
|
||||
layout.prop(md, "lambda_factor", text="Factor")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(md, "smooth_type")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Vertex Group:")
|
||||
row = col.row(align=True)
|
||||
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
||||
row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
|
||||
|
||||
col = split.column()
|
||||
col.prop(md, "use_only_smooth")
|
||||
col.prop(md, "use_pin_boundary")
|
||||
|
||||
layout.prop(md, "rest_source")
|
||||
if md.rest_source == 'BIND':
|
||||
layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
|
||||
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
bpy.utils.register_module(__name__)
|
||||
|
@ -92,6 +92,7 @@ void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
|
||||
|
||||
void BKE_editmesh_color_free(BMEditMesh *em);
|
||||
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
|
||||
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
|
||||
|
||||
/* editderivedmesh.c */
|
||||
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
|
||||
|
@ -119,7 +119,7 @@ bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, con
|
||||
const char *new_name, const bool do_tessface);
|
||||
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
|
||||
|
||||
float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3];
|
||||
float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
|
||||
|
||||
void BKE_mesh_calc_normals_split(struct Mesh *mesh);
|
||||
void BKE_mesh_split_faces(struct Mesh *mesh);
|
||||
|
@ -246,3 +246,21 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
|
||||
{
|
||||
BMIter iter;
|
||||
BMVert *eve;
|
||||
float (*orco)[3];
|
||||
int i;
|
||||
|
||||
orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
|
||||
|
||||
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
|
||||
copy_v3_v3(orco[i], eve->co);
|
||||
}
|
||||
|
||||
*r_numVerts = em->bm->totvert;
|
||||
|
||||
return orco;
|
||||
}
|
||||
|
@ -1805,7 +1805,7 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
|
||||
* Return a newly MEM_malloc'd array of all the mesh vertex locations
|
||||
* \note \a r_numVerts may be NULL
|
||||
*/
|
||||
float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3]
|
||||
float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
|
||||
{
|
||||
int i, numVerts = me->totvert;
|
||||
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "vertexcos1");
|
||||
|
@ -4949,6 +4949,20 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
|
||||
}
|
||||
lmd->cache_system = NULL;
|
||||
}
|
||||
else if (md->type == eModifierType_CorrectiveSmooth) {
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData*)md;
|
||||
|
||||
if (csmd->bind_coords) {
|
||||
csmd->bind_coords = newdataadr(fd, csmd->bind_coords);
|
||||
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
|
||||
BLI_endian_switch_float_array((float *)csmd->bind_coords, csmd->bind_coords_num * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* runtime only */
|
||||
csmd->delta_cache = NULL;
|
||||
csmd->delta_cache_num = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1620,6 +1620,13 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
|
||||
|
||||
writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco);
|
||||
}
|
||||
else if (md->type == eModifierType_CorrectiveSmooth) {
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
|
||||
if (csmd->bind_coords) {
|
||||
writedata(wd, DATA, sizeof(float[3]) * csmd->bind_coords_num, csmd->bind_coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,6 +174,7 @@ void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_ocean_bake(struct wmOperatorType *ot);
|
||||
|
@ -1815,6 +1815,73 @@ void OBJECT_OT_skin_armature_create(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
edit_modifier_properties(ot);
|
||||
}
|
||||
/************************ delta mush bind operator *********************/
|
||||
|
||||
static int correctivesmooth_poll(bContext *C)
|
||||
{
|
||||
return edit_modifier_poll_generic(C, &RNA_CorrectiveSmoothModifier, 0);
|
||||
}
|
||||
|
||||
static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = ED_object_active_context(C);
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)edit_modifier_property_get(op, ob, eModifierType_CorrectiveSmooth);
|
||||
bool is_bind;
|
||||
|
||||
if (!csmd) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
is_bind = (csmd->bind_coords != NULL);
|
||||
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
MEM_SAFE_FREE(csmd->delta_cache);
|
||||
|
||||
if (is_bind) {
|
||||
/* toggle off */
|
||||
csmd->bind_coords_num = 0;
|
||||
}
|
||||
else {
|
||||
/* signal to modifier to recalculate */
|
||||
csmd->bind_coords_num = (unsigned int)-1;
|
||||
}
|
||||
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
if (edit_modifier_invoke_properties(C, op))
|
||||
return correctivesmooth_bind_exec(C, op);
|
||||
else
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void OBJECT_OT_correctivesmooth_bind(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Corrective Smooth Bind";
|
||||
ot->description = "Bind base pose in delta mush modifier";
|
||||
ot->idname = "OBJECT_OT_correctivesmooth_bind";
|
||||
|
||||
/* api callbacks */
|
||||
ot->poll = correctivesmooth_poll;
|
||||
ot->invoke = correctivesmooth_bind_invoke;
|
||||
ot->exec = correctivesmooth_bind_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
edit_modifier_properties(ot);
|
||||
}
|
||||
|
||||
/************************ mdef bind operator *********************/
|
||||
|
||||
|
@ -144,6 +144,7 @@ void ED_operatortypes_object(void)
|
||||
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
|
||||
WM_operatortype_append(OBJECT_OT_skin_armature_create);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
|
||||
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
|
||||
WM_operatortype_append(OBJECT_OT_explode_refresh);
|
||||
WM_operatortype_append(OBJECT_OT_ocean_bake);
|
||||
|
@ -1121,6 +1121,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
|
||||
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
|
||||
case eModifierType_Smooth:
|
||||
case eModifierType_LaplacianSmooth:
|
||||
case eModifierType_CorrectiveSmooth:
|
||||
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
|
||||
case eModifierType_SimpleDeform:
|
||||
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
|
||||
|
@ -84,6 +84,7 @@ typedef enum ModifierType {
|
||||
eModifierType_Wireframe = 48,
|
||||
eModifierType_DataTransfer = 49,
|
||||
eModifierType_NormalEdit = 50,
|
||||
eModifierType_CorrectiveSmooth = 51,
|
||||
NUM_MODIFIER_TYPES
|
||||
} ModifierType;
|
||||
|
||||
@ -1288,6 +1289,48 @@ enum {
|
||||
MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5),
|
||||
};
|
||||
|
||||
|
||||
typedef struct CorrectiveSmoothModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
/* positions set during 'bind' operator
|
||||
* use for MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND */
|
||||
float (*bind_coords)[3];
|
||||
|
||||
/* note: -1 is used to bind */
|
||||
unsigned int bind_coords_num;
|
||||
|
||||
float lambda;
|
||||
short repeat, flag;
|
||||
char smooth_type, rest_source;
|
||||
char pad[2];
|
||||
|
||||
char defgrp_name[64]; /* MAX_VGROUP_NAME */
|
||||
|
||||
/* runtime-only cache (delta's between),
|
||||
* delta's between the original positions and the smoothed positions */
|
||||
float (*delta_cache)[3];
|
||||
unsigned int delta_cache_num;
|
||||
char pad2[4];
|
||||
} CorrectiveSmoothModifierData;
|
||||
|
||||
enum {
|
||||
MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE = 0,
|
||||
MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO = 0,
|
||||
MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
|
||||
};
|
||||
|
||||
/* Corrective Smooth modifier flags */
|
||||
enum {
|
||||
MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
|
||||
MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
|
||||
MOD_CORRECTIVESMOOTH_PIN_BOUNDARY = (1 << 2),
|
||||
};
|
||||
|
||||
typedef struct UVWarpModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
|
@ -202,6 +202,7 @@ extern StructRNA RNA_DampedTrackConstraint;
|
||||
extern StructRNA RNA_DataTransferModifier;
|
||||
extern StructRNA RNA_DecimateModifier;
|
||||
extern StructRNA RNA_DelaySensor;
|
||||
extern StructRNA RNA_CorrectiveSmoothModifier;
|
||||
extern StructRNA RNA_DisplaceModifier;
|
||||
extern StructRNA RNA_DisplaySafeAreas;
|
||||
extern StructRNA RNA_DistortedNoiseTexture;
|
||||
|
@ -92,6 +92,7 @@ EnumPropertyItem modifier_type_items[] = {
|
||||
{0, "", 0, N_("Deform"), ""},
|
||||
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
|
||||
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
|
||||
{eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Corrective Smooth", ""},
|
||||
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
|
||||
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
|
||||
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
|
||||
@ -377,6 +378,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
|
||||
return &RNA_DataTransferModifier;
|
||||
case eModifierType_NormalEdit:
|
||||
return &RNA_NormalEditModifier;
|
||||
case eModifierType_CorrectiveSmooth:
|
||||
return &RNA_CorrectiveSmoothModifier;
|
||||
/* Default */
|
||||
case eModifierType_None:
|
||||
case eModifierType_ShapeKey:
|
||||
@ -444,6 +447,7 @@ RNA_MOD_VGROUP_NAME_SET(Cast, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Curve, name);
|
||||
RNA_MOD_VGROUP_NAME_SET(DataTransfer, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Decimate, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(CorrectiveSmooth, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Displace, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Hook, name);
|
||||
RNA_MOD_VGROUP_NAME_SET(LaplacianDeform, anchor_grp_name);
|
||||
@ -1034,6 +1038,33 @@ static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, Po
|
||||
return item;
|
||||
}
|
||||
|
||||
static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
|
||||
|
||||
MEM_SAFE_FREE(csmd->delta_cache);
|
||||
|
||||
rna_Modifier_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_CorrectiveSmoothModifier_rest_source_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
|
||||
|
||||
if (csmd->rest_source != MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
csmd->bind_coords_num = 0;
|
||||
}
|
||||
|
||||
rna_CorrectiveSmoothModifier_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data;
|
||||
return (csmd->bind_coords != NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
|
||||
@ -2111,6 +2142,90 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
}
|
||||
|
||||
|
||||
static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem modifier_smooth_type_items[] = {
|
||||
{MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE, "SIMPLE", 0, "Simple",
|
||||
"Use the average of adjacent edge-vertices"},
|
||||
{MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT, "LENGTH_WEIGHTED", 0, "Length Weight",
|
||||
"Use the average of adjacent edge-vertices weighted by their length"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static EnumPropertyItem modifier_rest_source_items[] = {
|
||||
{MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO, "ORCO", 0, "Original Coords",
|
||||
"Use base mesh vert coords as the rest position"},
|
||||
{MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND, "BIND", 0, "Bind Coords",
|
||||
"Use bind vert coords for rest position"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "CorrectiveSmoothModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Corrective Smooth Modifier", "Correct distortion caused by deformation");
|
||||
RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
|
||||
|
||||
prop = RNA_def_property(srna, "lambda_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "lambda");
|
||||
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0, 1.0, 5, 3);
|
||||
RNA_def_property_ui_text(prop, "Lambda Factor", "Smooth factor effect");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "repeat");
|
||||
RNA_def_property_ui_range(prop, 0, 200, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Repeat", "");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "rest_source", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "rest_source");
|
||||
RNA_def_property_enum_items(prop, modifier_rest_source_items);
|
||||
RNA_def_property_ui_text(prop, "Rest Source", "Select the source of rest positions");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_rest_source_update");
|
||||
|
||||
prop = RNA_def_property(srna, "smooth_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "smooth_type");
|
||||
RNA_def_property_enum_items(prop, modifier_smooth_type_items);
|
||||
RNA_def_property_ui_text(prop, "Smooth Type", "Method used for smoothing");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_INVERT_VGROUP);
|
||||
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
|
||||
RNA_def_property_ui_text(prop, "Vertex Group",
|
||||
"Name of Vertex Group which determines influence of modifier per point");
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CorrectiveSmoothModifier_defgrp_name_set");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "is_bind", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Bind current shape", "");
|
||||
RNA_def_property_boolean_funcs(prop, "rna_CorrectiveSmoothModifier_is_bind_get", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_only_smooth", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_ONLY_SMOOTH);
|
||||
RNA_def_property_ui_text(prop, "Only Smooth",
|
||||
"Apply smoothing without reconstructing the surface");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_pin_boundary", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CORRECTIVESMOOTH_PIN_BOUNDARY);
|
||||
RNA_def_property_ui_text(prop, "Pin Boundaries",
|
||||
"Excludes boundary vertices from being smoothed");
|
||||
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
|
||||
}
|
||||
|
||||
|
||||
static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
@ -4520,6 +4635,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
||||
rna_def_modifier_displace(brna);
|
||||
rna_def_modifier_uvproject(brna);
|
||||
rna_def_modifier_smooth(brna);
|
||||
rna_def_modifier_correctivesmooth(brna);
|
||||
rna_def_modifier_cast(brna);
|
||||
rna_def_modifier_meshdeform(brna);
|
||||
rna_def_modifier_particlesystem(brna);
|
||||
|
@ -51,6 +51,7 @@ set(SRC
|
||||
intern/MOD_cast.c
|
||||
intern/MOD_cloth.c
|
||||
intern/MOD_collision.c
|
||||
intern/MOD_correctivesmooth.c
|
||||
intern/MOD_curve.c
|
||||
intern/MOD_datatransfer.c
|
||||
intern/MOD_decimate.c
|
||||
|
@ -83,6 +83,7 @@ extern ModifierTypeInfo modifierType_LaplacianDeform;
|
||||
extern ModifierTypeInfo modifierType_Wireframe;
|
||||
extern ModifierTypeInfo modifierType_DataTransfer;
|
||||
extern ModifierTypeInfo modifierType_NormalEdit;
|
||||
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
|
||||
|
||||
/* MOD_util.c */
|
||||
void modifier_type_init(ModifierTypeInfo *types[]);
|
||||
|
768
source/blender/modifiers/intern/MOD_correctivesmooth.c
Normal file
768
source/blender/modifiers/intern/MOD_correctivesmooth.c
Normal file
@ -0,0 +1,768 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2015 by the Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Jack Simpson,
|
||||
* Campbell Barton
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
/** \file blender/modifiers/intern/MOD_correctivesmooth.c
|
||||
* \ingroup modifiers
|
||||
*
|
||||
* Method of smoothing deformation, also known as 'delta-mush'.
|
||||
*/
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BKE_cdderivedmesh.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_editmesh.h"
|
||||
|
||||
#include "MOD_modifiertypes.h"
|
||||
#include "MOD_util.h"
|
||||
|
||||
#include "BLI_strict_flags.h"
|
||||
|
||||
|
||||
// #define DEBUG_TIME
|
||||
|
||||
#include "PIL_time.h"
|
||||
#ifdef DEBUG_TIME
|
||||
# include "PIL_time_utildefines.h"
|
||||
#endif
|
||||
|
||||
/* minor optimization, calculate this inline */
|
||||
#define USE_TANGENT_CALC_INLINE
|
||||
|
||||
static void initData(ModifierData *md)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
|
||||
csmd->bind_coords = NULL;
|
||||
csmd->bind_coords_num = 0;
|
||||
|
||||
csmd->lambda = 0.5f;
|
||||
csmd->repeat = 5;
|
||||
csmd->flag = 0;
|
||||
csmd->smooth_type = MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE;
|
||||
|
||||
csmd->defgrp_name[0] = '\0';
|
||||
|
||||
csmd->delta_cache = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void copyData(ModifierData *md, ModifierData *target)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
|
||||
|
||||
modifier_copyData_generic(md, target);
|
||||
|
||||
if (csmd->bind_coords) {
|
||||
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
|
||||
}
|
||||
|
||||
tcsmd->delta_cache = NULL;
|
||||
tcsmd->delta_cache_num = 0;
|
||||
}
|
||||
|
||||
|
||||
static void freeBind(CorrectiveSmoothModifierData *csmd)
|
||||
{
|
||||
MEM_SAFE_FREE(csmd->bind_coords);
|
||||
MEM_SAFE_FREE(csmd->delta_cache);
|
||||
|
||||
csmd->bind_coords_num = 0;
|
||||
}
|
||||
|
||||
|
||||
static void freeData(ModifierData *md)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
freeBind(csmd);
|
||||
}
|
||||
|
||||
|
||||
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
CustomDataMask dataMask = 0;
|
||||
/* ask for vertex groups if we need them */
|
||||
if (csmd->defgrp_name[0]) {
|
||||
dataMask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
return dataMask;
|
||||
}
|
||||
|
||||
|
||||
/* check individual weights for changes and cache values */
|
||||
static void dm_get_weights(
|
||||
MDeformVert *dvert, const int defgrp_index,
|
||||
const unsigned int numVerts, const bool use_invert_vgroup,
|
||||
float *smooth_weights)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < numVerts; i++, dvert++) {
|
||||
const float w = defvert_find_weight(dvert, defgrp_index);
|
||||
|
||||
if (use_invert_vgroup == false) {
|
||||
smooth_weights[i] = w;
|
||||
}
|
||||
else {
|
||||
smooth_weights[i] = 1.0f - w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
|
||||
{
|
||||
const MPoly *mpoly = dm->getPolyArray(dm);
|
||||
const MLoop *mloop = dm->getLoopArray(dm);
|
||||
const MEdge *medge = dm->getEdgeArray(dm);
|
||||
unsigned int mpoly_num, medge_num, i;
|
||||
unsigned short *boundaries;
|
||||
|
||||
mpoly_num = (unsigned int)dm->getNumPolys(dm);
|
||||
medge_num = (unsigned int)dm->getNumEdges(dm);
|
||||
|
||||
boundaries = MEM_callocN(medge_num * sizeof(*boundaries), __func__);
|
||||
|
||||
/* count the number of adjacent faces */
|
||||
for (i = 0; i < mpoly_num; i++) {
|
||||
const MPoly *p = &mpoly[i];
|
||||
const int totloop = p->totloop;
|
||||
int j;
|
||||
for (j = 0; j < totloop; j++) {
|
||||
boundaries[mloop[p->loopstart + j].e]++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < medge_num; i++) {
|
||||
if (boundaries[i] == 1) {
|
||||
smooth_weights[medge[i].v1] = 0.0f;
|
||||
smooth_weights[medge[i].v2] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(boundaries);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Simple Weighted Smoothing
|
||||
*
|
||||
* (average of surrounding verts)
|
||||
*/
|
||||
static void smooth_iter__simple(
|
||||
CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
|
||||
float (*vertexCos)[3], unsigned int numVerts,
|
||||
const float *smooth_weights,
|
||||
unsigned int iterations)
|
||||
{
|
||||
const float lambda = csmd->lambda;
|
||||
unsigned int i;
|
||||
|
||||
const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
|
||||
const MEdge *edges = dm->getEdgeArray(dm);
|
||||
float *vertex_edge_count_div;
|
||||
|
||||
struct SmoothingData_Simple {
|
||||
float delta[3];
|
||||
} *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
|
||||
|
||||
vertex_edge_count_div = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
|
||||
|
||||
/* calculate as floats to avoid int->float conversion in #smooth_iter */
|
||||
for (i = 0; i < numEdges; i++) {
|
||||
vertex_edge_count_div[edges[i].v1] += 1.0f;
|
||||
vertex_edge_count_div[edges[i].v2] += 1.0f;
|
||||
}
|
||||
|
||||
/* a little confusing, but we can include 'lambda' and smoothing weight
|
||||
* here to avoid multiplying for every iteration */
|
||||
if (smooth_weights == NULL) {
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
vertex_edge_count_div[i] =
|
||||
lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
vertex_edge_count_div[i] =
|
||||
smooth_weights[i] * lambda * (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) : 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Main Smoothing Loop */
|
||||
|
||||
while (iterations--) {
|
||||
for (i = 0; i < numEdges; i++) {
|
||||
struct SmoothingData_Simple *sd_v1;
|
||||
struct SmoothingData_Simple *sd_v2;
|
||||
float edge_dir[3];
|
||||
|
||||
sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
|
||||
|
||||
sd_v1 = &smooth_data[edges[i].v1];
|
||||
sd_v2 = &smooth_data[edges[i].v2];
|
||||
|
||||
add_v3_v3(sd_v1->delta, edge_dir);
|
||||
sub_v3_v3(sd_v2->delta, edge_dir);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
struct SmoothingData_Simple *sd = &smooth_data[i];
|
||||
madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
|
||||
/* zero for the next iteration (saves memset on entire array) */
|
||||
memset(sd, 0, sizeof(*sd));
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(vertex_edge_count_div);
|
||||
MEM_freeN(smooth_data);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Edge-Length Weighted Smoothing
|
||||
*/
|
||||
static void smooth_iter__length_weight(
|
||||
CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
|
||||
float (*vertexCos)[3], unsigned int numVerts,
|
||||
const float *smooth_weights,
|
||||
unsigned int iterations)
|
||||
{
|
||||
const float eps = FLT_EPSILON * 10.0f;
|
||||
const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
|
||||
/* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
|
||||
* and 2.0 rarely spikes, double the value for consistent behavior. */
|
||||
const float lambda = csmd->lambda * 2.0f;
|
||||
const MEdge *edges = dm->getEdgeArray(dm);
|
||||
float *vertex_edge_count;
|
||||
unsigned int i;
|
||||
|
||||
struct SmoothingData_Weighted {
|
||||
float delta[3];
|
||||
float edge_length_sum;
|
||||
} *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__);
|
||||
|
||||
|
||||
/* calculate as floats to avoid int->float conversion in #smooth_iter */
|
||||
vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__);
|
||||
for (i = 0; i < numEdges; i++) {
|
||||
vertex_edge_count[edges[i].v1] += 1.0f;
|
||||
vertex_edge_count[edges[i].v2] += 1.0f;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Main Smoothing Loop */
|
||||
|
||||
while (iterations--) {
|
||||
for (i = 0; i < numEdges; i++) {
|
||||
struct SmoothingData_Weighted *sd_v1;
|
||||
struct SmoothingData_Weighted *sd_v2;
|
||||
float edge_dir[3];
|
||||
float edge_dist;
|
||||
|
||||
sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
|
||||
edge_dist = len_v3(edge_dir);
|
||||
|
||||
/* weight by distance */
|
||||
mul_v3_fl(edge_dir, edge_dist);
|
||||
|
||||
|
||||
sd_v1 = &smooth_data[edges[i].v1];
|
||||
sd_v2 = &smooth_data[edges[i].v2];
|
||||
|
||||
add_v3_v3(sd_v1->delta, edge_dir);
|
||||
sub_v3_v3(sd_v2->delta, edge_dir);
|
||||
|
||||
sd_v1->edge_length_sum += edge_dist;
|
||||
sd_v2->edge_length_sum += edge_dist;
|
||||
}
|
||||
|
||||
if (smooth_weights == NULL) {
|
||||
/* fast-path */
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
struct SmoothingData_Weighted *sd = &smooth_data[i];
|
||||
/* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */
|
||||
const float div = sd->edge_length_sum * vertex_edge_count[i];
|
||||
if (div > eps) {
|
||||
#if 0
|
||||
/* first calculate the new location */
|
||||
mul_v3_fl(sd->delta, 1.0f / div);
|
||||
/* then interpolate */
|
||||
madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
|
||||
#else
|
||||
/* do this in one step */
|
||||
madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
|
||||
#endif
|
||||
}
|
||||
/* zero for the next iteration (saves memset on entire array) */
|
||||
memset(sd, 0, sizeof(*sd));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
struct SmoothingData_Weighted *sd = &smooth_data[i];
|
||||
const float div = sd->edge_length_sum * vertex_edge_count[i];
|
||||
if (div > eps) {
|
||||
const float lambda_w = lambda * smooth_weights[i];
|
||||
madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
|
||||
}
|
||||
|
||||
memset(sd, 0, sizeof(*sd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(vertex_edge_count);
|
||||
MEM_freeN(smooth_data);
|
||||
}
|
||||
|
||||
|
||||
static void smooth_iter(
|
||||
CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
|
||||
float (*vertexCos)[3], unsigned int numVerts,
|
||||
const float *smooth_weights,
|
||||
unsigned int iterations)
|
||||
{
|
||||
switch (csmd->smooth_type) {
|
||||
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
|
||||
smooth_iter__length_weight(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
|
||||
break;
|
||||
|
||||
/* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
|
||||
default:
|
||||
smooth_iter__simple(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void smooth_verts(
|
||||
CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
|
||||
MDeformVert *dvert, const int defgrp_index,
|
||||
float (*vertexCos)[3], unsigned int numVerts)
|
||||
{
|
||||
float *smooth_weights = NULL;
|
||||
|
||||
if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
|
||||
|
||||
smooth_weights = MEM_mallocN(numVerts * sizeof(float), __func__);
|
||||
|
||||
if (dvert) {
|
||||
dm_get_weights(
|
||||
dvert, defgrp_index,
|
||||
numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
|
||||
smooth_weights);
|
||||
}
|
||||
else {
|
||||
fill_vn_fl(smooth_weights, (int)numVerts, 1.0f);
|
||||
}
|
||||
|
||||
if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
|
||||
dm_get_boundaries(dm, smooth_weights);
|
||||
}
|
||||
}
|
||||
|
||||
smooth_iter(csmd, dm, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
|
||||
|
||||
if (smooth_weights) {
|
||||
MEM_freeN(smooth_weights);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* finalize after accumulation.
|
||||
*/
|
||||
static void calc_tangent_ortho(float ts[3][3])
|
||||
{
|
||||
float v_tan_a[3], v_tan_b[3];
|
||||
float t_vec_a[3], t_vec_b[3];
|
||||
|
||||
normalize_v3(ts[2]);
|
||||
|
||||
copy_v3_v3(v_tan_a, ts[0]);
|
||||
copy_v3_v3(v_tan_b, ts[1]);
|
||||
|
||||
cross_v3_v3v3(ts[1], ts[2], v_tan_a);
|
||||
mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);
|
||||
|
||||
/* orthognalise tangent */
|
||||
mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
|
||||
sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);
|
||||
|
||||
/* orthognalise bitangent */
|
||||
mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
|
||||
mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
|
||||
sub_v3_v3(ts[1], t_vec_a);
|
||||
sub_v3_v3(ts[1], t_vec_b);
|
||||
|
||||
normalize_v3(ts[0]);
|
||||
normalize_v3(ts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* accumulate edge-vectors from all polys.
|
||||
*/
|
||||
static void calc_tangent_loop_accum(
|
||||
const float v_dir_prev[3],
|
||||
const float v_dir_next[3],
|
||||
float r_tspace[3][3])
|
||||
{
|
||||
add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next);
|
||||
|
||||
if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) {
|
||||
const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev)));
|
||||
float nor[3];
|
||||
|
||||
cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
|
||||
normalize_v3(nor);
|
||||
|
||||
cross_v3_v3v3(r_tspace[0], r_tspace[1], nor);
|
||||
|
||||
mul_v3_fl(nor, weight);
|
||||
/* accumulate weighted normals */
|
||||
add_v3_v3(r_tspace[2], nor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void calc_tangent_spaces(
|
||||
DerivedMesh *dm, float (*vertexCos)[3],
|
||||
float (*r_tangent_spaces)[3][3])
|
||||
{
|
||||
const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
|
||||
#ifndef USE_TANGENT_CALC_INLINE
|
||||
const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
|
||||
#endif
|
||||
const MPoly *mpoly = dm->getPolyArray(dm);
|
||||
const MLoop *mloop = dm->getLoopArray(dm);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < mpoly_num; i++) {
|
||||
const MPoly *mp = &mpoly[i];
|
||||
const MLoop *l_next = &mloop[mp->loopstart];
|
||||
const MLoop *l_term = l_next + mp->totloop;
|
||||
const MLoop *l_prev = l_term - 2;
|
||||
const MLoop *l_curr = l_term - 1;
|
||||
|
||||
/* loop directions */
|
||||
float v_dir_prev[3], v_dir_next[3];
|
||||
|
||||
/* needed entering the loop */
|
||||
sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
|
||||
normalize_v3(v_dir_prev);
|
||||
|
||||
for (;
|
||||
l_next != l_term;
|
||||
l_prev = l_curr, l_curr = l_next, l_next++)
|
||||
{
|
||||
float (*ts)[3] = r_tangent_spaces[l_curr->v];
|
||||
|
||||
/* re-use the previous value */
|
||||
#if 0
|
||||
sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
|
||||
normalize_v3(v_dir_prev);
|
||||
#endif
|
||||
sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
|
||||
normalize_v3(v_dir_next);
|
||||
|
||||
calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);
|
||||
|
||||
copy_v3_v3(v_dir_prev, v_dir_next);
|
||||
}
|
||||
}
|
||||
|
||||
/* do inline */
|
||||
#ifndef USE_TANGENT_CALC_INLINE
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
float (*ts)[3] = r_tangent_spaces[i];
|
||||
calc_tangent_ortho(ts);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This calculates #CorrectiveSmoothModifierData.delta_cache
|
||||
* It's not run on every update (during animation for example).
|
||||
*/
|
||||
static void calc_deltas(
|
||||
CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
|
||||
MDeformVert *dvert, const int defgrp_index,
|
||||
const float (*rest_coords)[3], unsigned int numVerts)
|
||||
{
|
||||
float (*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
|
||||
float (*tangent_spaces)[3][3];
|
||||
unsigned int i;
|
||||
|
||||
tangent_spaces = MEM_callocN((size_t)(numVerts) * sizeof(float[3][3]), __func__);
|
||||
|
||||
if (csmd->delta_cache_num != numVerts) {
|
||||
MEM_SAFE_FREE(csmd->delta_cache);
|
||||
}
|
||||
|
||||
/* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
|
||||
if (!csmd->delta_cache) {
|
||||
csmd->delta_cache_num = numVerts;
|
||||
csmd->delta_cache = MEM_mallocN((size_t)numVerts * sizeof(float[3]), __func__);
|
||||
}
|
||||
|
||||
smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
|
||||
|
||||
calc_tangent_spaces(dm, smooth_vertex_coords, tangent_spaces);
|
||||
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
float imat[3][3], delta[3];
|
||||
|
||||
#ifdef USE_TANGENT_CALC_INLINE
|
||||
calc_tangent_ortho(tangent_spaces[i]);
|
||||
#endif
|
||||
|
||||
sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
|
||||
if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
|
||||
transpose_m3_m3(imat, tangent_spaces[i]);
|
||||
}
|
||||
mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
|
||||
}
|
||||
|
||||
MEM_freeN(tangent_spaces);
|
||||
MEM_freeN(smooth_vertex_coords);
|
||||
}
|
||||
|
||||
|
||||
static void correctivesmooth_modifier_do(
|
||||
ModifierData *md, Object *ob, DerivedMesh *dm,
|
||||
float (*vertexCos)[3], unsigned int numVerts,
|
||||
struct BMEditMesh *em)
|
||||
{
|
||||
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
|
||||
|
||||
const bool force_delta_cache_update =
|
||||
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
|
||||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
|
||||
(((ID *)ob->data)->flag & LIB_ID_RECALC));
|
||||
|
||||
bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
|
||||
MDeformVert *dvert = NULL;
|
||||
int defgrp_index;
|
||||
|
||||
modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);
|
||||
|
||||
/* if rest bind_coords not are defined, set them (only run during bind) */
|
||||
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
|
||||
/* signal to recalculate, whoever sets MUST also free bind coords */
|
||||
(csmd->bind_coords_num == (unsigned int)-1))
|
||||
{
|
||||
BLI_assert(csmd->bind_coords == NULL);
|
||||
csmd->bind_coords = MEM_dupallocN(vertexCos);
|
||||
csmd->bind_coords_num = numVerts;
|
||||
BLI_assert(csmd->bind_coords != NULL);
|
||||
}
|
||||
|
||||
if (UNLIKELY(use_only_smooth)) {
|
||||
smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
|
||||
modifier_setError(md, "Bind data required");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If the number of verts has changed, the bind is invalid, so we do nothing */
|
||||
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
|
||||
if (csmd->bind_coords_num != numVerts) {
|
||||
modifier_setError(md, "Bind vertex count mismatch: %d to %d", csmd->bind_coords_num, numVerts);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
|
||||
if (ob->type != OB_MESH) {
|
||||
modifier_setError(md, "Object is not a mesh");
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
int me_numVerts = (em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert;
|
||||
|
||||
if ((unsigned int)me_numVerts != numVerts) {
|
||||
modifier_setError(md, "Original vertex count mismatch: %d to %d", me_numVerts, numVerts);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check to see if our deltas are still valid */
|
||||
if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
|
||||
const float (*rest_coords)[3];
|
||||
bool is_rest_coords_alloc = false;
|
||||
|
||||
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
|
||||
/* caller needs to do sanity check here */
|
||||
csmd->bind_coords_num = numVerts;
|
||||
rest_coords = (const float (*)[3])csmd->bind_coords;
|
||||
}
|
||||
else {
|
||||
int me_numVerts;
|
||||
rest_coords = (const float (*)[3]) ((em) ?
|
||||
BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
|
||||
BKE_mesh_vertexCos_get(ob->data, &me_numVerts));
|
||||
|
||||
BLI_assert((unsigned int)me_numVerts == numVerts);
|
||||
is_rest_coords_alloc = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
TIMEIT_START(corrective_smooth_deltas);
|
||||
#endif
|
||||
|
||||
calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
TIMEIT_END(corrective_smooth_deltas);
|
||||
#endif
|
||||
if (is_rest_coords_alloc) {
|
||||
MEM_freeN((void *)rest_coords);
|
||||
}
|
||||
}
|
||||
|
||||
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
|
||||
/* this could be a check, but at this point it _must_ be valid */
|
||||
BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
TIMEIT_START(corrective_smooth);
|
||||
#endif
|
||||
|
||||
/* do the actual delta mush */
|
||||
smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
|
||||
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
float (*tangent_spaces)[3][3];
|
||||
|
||||
/* calloc, since values are accumulated */
|
||||
tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);
|
||||
|
||||
calc_tangent_spaces(dm, vertexCos, tangent_spaces);
|
||||
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
float delta[3];
|
||||
|
||||
#ifdef USE_TANGENT_CALC_INLINE
|
||||
calc_tangent_ortho(tangent_spaces[i]);
|
||||
#endif
|
||||
|
||||
mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
|
||||
add_v3_v3(vertexCos[i], delta);
|
||||
}
|
||||
|
||||
MEM_freeN(tangent_spaces);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
TIMEIT_END(corrective_smooth);
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
/* when the modifier fails to execute */
|
||||
error:
|
||||
MEM_SAFE_FREE(csmd->delta_cache);
|
||||
csmd->delta_cache_num = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void deformVerts(
|
||||
ModifierData *md, Object *ob, DerivedMesh *derivedData,
|
||||
float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
|
||||
{
|
||||
DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
|
||||
|
||||
correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, NULL);
|
||||
|
||||
if (dm != derivedData) {
|
||||
dm->release(dm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void deformVertsEM(
|
||||
ModifierData *md, Object *ob, struct BMEditMesh *editData,
|
||||
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
|
||||
{
|
||||
DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
|
||||
|
||||
correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, editData);
|
||||
|
||||
if (dm != derivedData) {
|
||||
dm->release(dm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ModifierTypeInfo modifierType_CorrectiveSmooth = {
|
||||
/* name */ "CorrectiveSmooth",
|
||||
/* structName */ "CorrectiveSmoothModifierData",
|
||||
/* structSize */ sizeof(CorrectiveSmoothModifierData),
|
||||
/* type */ eModifierTypeType_OnlyDeform,
|
||||
/* flags */ eModifierTypeFlag_AcceptsMesh |
|
||||
eModifierTypeFlag_SupportsEditmode,
|
||||
|
||||
/* copyData */ copyData,
|
||||
/* deformVerts */ deformVerts,
|
||||
/* deformMatrices */ NULL,
|
||||
/* deformVertsEM */ deformVertsEM,
|
||||
/* deformMatricesEM */ NULL,
|
||||
/* applyModifier */ NULL,
|
||||
/* applyModifierEM */ NULL,
|
||||
/* initData */ initData,
|
||||
/* requiredDataMask */ requiredDataMask,
|
||||
/* freeData */ freeData,
|
||||
/* isDisabled */ NULL,
|
||||
/* updateDepgraph */ NULL,
|
||||
/* dependsOnTime */ NULL,
|
||||
/* dependsOnNormals */ NULL,
|
||||
/* foreachObjectLink */ NULL,
|
||||
/* foreachIDLink */ NULL,
|
||||
/* foreachTexLink */ NULL,
|
||||
};
|
@ -306,5 +306,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
||||
INIT_TYPE(Wireframe);
|
||||
INIT_TYPE(DataTransfer);
|
||||
INIT_TYPE(NormalEdit);
|
||||
INIT_TYPE(CorrectiveSmooth);
|
||||
#undef INIT_TYPE
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user