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 --- .../modifiers/intern/MOD_correctivesmooth.c | 768 +++++++++++++++++++++ source/blender/modifiers/intern/MOD_util.c | 1 + 2 files changed, 769 insertions(+) create mode 100644 source/blender/modifiers/intern/MOD_correctivesmooth.c (limited to 'source/blender/modifiers/intern') 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