From c16a8983efba9ecacd8da408d03c37a55483e528 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 29 Mar 2015 04:44:05 +1100 Subject: Corrective Smooth Modifier (aka delta-mush) This modifier can be used to correct bad deformations, Original patch D1183 by @sazerac, with own modifications --- source/blender/blenkernel/BKE_editmesh.h | 1 + source/blender/blenkernel/BKE_mesh.h | 2 +- source/blender/blenkernel/intern/editmesh.c | 18 + source/blender/blenkernel/intern/mesh.c | 2 +- source/blender/blenloader/intern/readfile.c | 14 + source/blender/blenloader/intern/writefile.c | 7 + source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_modifier.c | 67 ++ source/blender/editors/object/object_ops.c | 1 + .../blender/editors/space_outliner/outliner_draw.c | 1 + source/blender/makesdna/DNA_modifier_types.h | 43 ++ source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 116 ++++ source/blender/modifiers/CMakeLists.txt | 1 + source/blender/modifiers/MOD_modifiertypes.h | 1 + .../modifiers/intern/MOD_correctivesmooth.c | 768 +++++++++++++++++++++ source/blender/modifiers/intern/MOD_util.c | 1 + 17 files changed, 1043 insertions(+), 2 deletions(-) create mode 100644 source/blender/modifiers/intern/MOD_correctivesmooth.c (limited to 'source') diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index d0b94117b23..d350eea7ac7 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -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' */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 5cf557a07e5..05c20410458 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -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); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 2247b91df1d..87a5c6f149f 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -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; +} diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 8ebc318ff9e..adce6e15732 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -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"); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b8c3bffae0f..b0aa47787b6 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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; + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index bc1bc9c7759..afc53f343f1 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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); + } + } } } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index db040bc2017..d535457fc5b 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -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); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index f9315214557..ad02f78e7b6 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -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 *********************/ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 15eb9090ce5..422f0c12e51 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -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); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 873b5f5319f..420b73cee86 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -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; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index b32b228fda4..f3c61f0ab6c 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -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; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 577f27f564e..8aa1bc59b43 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index bde8fd73d85..635336004f9 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -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); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 57e927fffed..1de3fc9eac0 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -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 diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 66e613be68a..a5d96759952 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -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[]); diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c new file mode 100644 index 00000000000..82c1d6f2ec8 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -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, +}; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index eac2f24d064..be6f7af7791 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -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 } -- cgit v1.2.3