This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/modifiers/intern/MOD_correctivesmooth.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

871 lines
26 KiB
C
Raw Normal View History

/*
2016-07-02 10:02:04 +10:00
* 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
2020-05-09 17:14:35 +10:00
* along with this program; if not, write to the Free Software Foundation,
2016-07-02 10:02:04 +10:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup modifiers
*
* Method of smoothing deformation, also known as 'delta-mush'.
*/
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
#include "MOD_util.h"
#include "BLO_read_write.h"
#include "DEG_depsgraph_query.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;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(csmd, modifier));
MEMCPY_STRUCT_AFTER(csmd, DNA_struct_default_get(CorrectiveSmoothModifierData), modifier);
csmd->delta_cache.deltas = NULL;
}
#include "BLI_strict_flags.h"
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md;
CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
BKE_modifier_copydata_generic(md, target, flag);
if (csmd->bind_coords) {
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
}
tcsmd->delta_cache.deltas = NULL;
tcsmd->delta_cache.totverts = 0;
}
static void freeBind(CorrectiveSmoothModifierData *csmd)
{
MEM_SAFE_FREE(csmd->bind_coords);
MEM_SAFE_FREE(csmd->delta_cache.deltas);
csmd->bind_coords_num = 0;
}
static void freeData(ModifierData *md)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
freeBind(csmd);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
/* ask for vertex groups if we need them */
if (csmd->defgrp_name[0] != '\0') {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
}
/* check individual weights for changes and cache values */
static void mesh_get_weights(MDeformVert *dvert,
const int defgrp_index,
const uint numVerts,
const bool use_invert_vgroup,
float *smooth_weights)
{
uint i;
for (i = 0; i < numVerts; i++, dvert++) {
const float w = BKE_defvert_find_weight(dvert, defgrp_index);
if (use_invert_vgroup == false) {
smooth_weights[i] = w;
}
else {
smooth_weights[i] = 1.0f - w;
}
}
}
static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
{
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
const MEdge *medge = mesh->medge;
uint mpoly_num, medge_num, i;
ushort *boundaries;
mpoly_num = (uint)mesh->totpoly;
medge_num = (uint)mesh->totedge;
boundaries = MEM_calloc_arrayN(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,
Mesh *mesh,
float (*vertexCos)[3],
uint numVerts,
const float *smooth_weights,
uint iterations)
{
const float lambda = csmd->lambda;
uint i;
const uint numEdges = (uint)mesh->totedge;
const MEdge *edges = mesh->medge;
float *vertex_edge_count_div;
struct SmoothingData_Simple {
float delta[3];
} *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
vertex_edge_count_div = MEM_calloc_arrayN(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,
Mesh *mesh,
float (*vertexCos)[3],
uint numVerts,
const float *smooth_weights,
uint iterations)
{
const float eps = FLT_EPSILON * 10.0f;
const uint numEdges = (uint)mesh->totedge;
/* 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 = mesh->medge;
float *vertex_edge_count;
uint i;
struct SmoothingData_Weighted {
float delta[3];
float edge_length_sum;
} *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
/* calculate as floats to avoid int->float conversion in #smooth_iter */
vertex_edge_count = MEM_calloc_arrayN(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];
2019-08-04 12:51:44 +10:00
/* Divide by sum of all neighbor distances (weighted) and amount of neighbors,
* (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,
Mesh *mesh,
float (*vertexCos)[3],
uint numVerts,
const float *smooth_weights,
uint iterations)
{
switch (csmd->smooth_type) {
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
smooth_iter__length_weight(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
break;
/* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
default:
smooth_iter__simple(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
break;
}
}
static void smooth_verts(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
MDeformVert *dvert,
const int defgrp_index,
float (*vertexCos)[3],
uint numVerts)
{
float *smooth_weights = NULL;
if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__);
if (dvert) {
mesh_get_weights(dvert,
defgrp_index,
numVerts,
(csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
smooth_weights);
}
else {
copy_vn_fl(smooth_weights, (int)numVerts, 1.0f);
}
if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
mesh_get_boundaries(mesh, smooth_weights);
}
}
smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)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);
2021-02-05 16:23:34 +11:00
/* Orthogonalize 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);
2021-02-05 16:23:34 +11:00
/* Orthogonalize bi-tangent. */
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(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
{
const uint mpoly_num = (uint)mesh->totpoly;
#ifndef USE_TANGENT_CALC_INLINE
const uint mvert_num = (uint)dm->getNumVerts(dm);
#endif
const MPoly *mpoly = mesh->mpoly;
const MLoop *mloop = mesh->mloop;
uint 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
}
static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
{
csmd->delta_cache.lambda = csmd->lambda;
csmd->delta_cache.repeat = csmd->repeat;
csmd->delta_cache.flag = csmd->flag;
csmd->delta_cache.smooth_type = csmd->smooth_type;
csmd->delta_cache.rest_source = csmd->rest_source;
}
static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
{
return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
csmd->delta_cache.flag == csmd->flag &&
csmd->delta_cache.smooth_type == csmd->smooth_type &&
csmd->delta_cache.rest_source == csmd->rest_source);
}
/**
* This calculates #CorrectiveSmoothModifierData.delta_cache
* It's not run on every update (during animation for example).
*/
static void calc_deltas(CorrectiveSmoothModifierData *csmd,
Mesh *mesh,
MDeformVert *dvert,
const int defgrp_index,
const float (*rest_coords)[3],
uint numVerts)
{
float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
float(*tangent_spaces)[3][3];
uint i;
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
if (csmd->delta_cache.totverts != numVerts) {
MEM_SAFE_FREE(csmd->delta_cache.deltas);
}
/* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
if (!csmd->delta_cache.deltas) {
csmd->delta_cache.totverts = numVerts;
csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
calc_tangent_spaces(mesh, 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.deltas[i], imat, delta);
}
MEM_freeN(tangent_spaces);
MEM_freeN(smooth_vertex_coords);
}
static void correctivesmooth_modifier_do(ModifierData *md,
Depsgraph *depsgraph,
Object *ob,
Mesh *mesh,
float (*vertexCos)[3],
uint 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 */
!cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
MDeformVert *dvert = NULL;
int defgrp_index;
2018-06-29 19:02:19 +02:00
MOD_get_vgroup(ob, mesh, 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 == (uint)-1)) {
if (DEG_is_active(depsgraph)) {
BLI_assert(csmd->bind_coords == NULL);
csmd->bind_coords = MEM_dupallocN(vertexCos);
csmd->bind_coords_num = numVerts;
BLI_assert(csmd->bind_coords != NULL);
/* Copy bound data to the original modifier. */
CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *)
BKE_modifier_get_original(&csmd->modifier);
csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
csmd_orig->bind_coords_num = csmd->bind_coords_num;
}
else {
BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
}
}
if (UNLIKELY(use_only_smooth)) {
smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
return;
}
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
BKE_modifier_set_error(ob, 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) {
BKE_modifier_set_error(
ob, md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
goto error;
}
}
else {
/* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
if (ob->type != OB_MESH) {
BKE_modifier_set_error(ob, md, "Object is not a mesh");
goto error;
}
else {
uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
2015-04-14 10:30:14 +10:00
if (me_numVerts != numVerts) {
2020-05-08 19:02:03 +10:00
BKE_modifier_set_error(
ob, md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
goto error;
}
}
}
/* check to see if our deltas are still valid */
if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) ||
force_delta_cache_update) {
const float(*rest_coords)[3];
bool is_rest_coords_alloc = false;
store_cache_settings(csmd);
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
/* caller needs to do sanity check here */
csmd->bind_coords_num = numVerts;
rest_coords = csmd->bind_coords;
}
else {
int me_numVerts;
rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
BLI_assert((uint)me_numVerts == numVerts);
is_rest_coords_alloc = true;
}
#ifdef DEBUG_TIME
TIMEIT_START(corrective_smooth_deltas);
#endif
calc_deltas(csmd, mesh, 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.deltas);
}
#ifdef DEBUG_TIME
TIMEIT_START(corrective_smooth);
#endif
/* do the actual delta mush */
smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
{
uint i;
float(*tangent_spaces)[3][3];
const float scale = csmd->scale;
/* calloc, since values are accumulated */
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
calc_tangent_spaces(mesh, 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.deltas[i]);
madd_v3_v3fl(vertexCos[i], delta, scale);
}
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.deltas);
csmd->delta_cache.totverts = 0;
}
static void deformVerts(ModifierData *md,
const ModifierEvalContext *ctx,
Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
correctivesmooth_modifier_do(
md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
static void deformVertsEM(ModifierData *md,
const ModifierEvalContext *ctx,
struct BMEditMesh *editData,
Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
/* TODO(Campbell): use edit-mode data only (remove this line). */
if (mesh_src != NULL) {
BKE_mesh_wrapper_ensure_mdata(mesh_src);
}
correctivesmooth_modifier_do(
md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "factor", 0, IFACE_("Factor"), ICON_NONE);
uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "scale", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "smooth_type", 0, NULL, ICON_NONE);
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
uiItemR(layout, ptr, "use_only_smooth", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_pin_boundary", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "rest_source", 0, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "rest_source") == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
uiItemO(layout,
(RNA_boolean_get(ptr, "is_bind") ? IFACE_("Unbind") : IFACE_("Bind")),
ICON_NONE,
"OBJECT_OT_correctivesmooth_bind");
}
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_CorrectiveSmooth, panel_draw);
}
static void blendWrite(BlendWriter *writer, const ModifierData *md)
{
const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md;
if (csmd->bind_coords) {
BLO_write_float3_array(writer, csmd->bind_coords_num, (float *)csmd->bind_coords);
}
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
{
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
if (csmd->bind_coords) {
BLO_read_float3_array(reader, (int)csmd->bind_coords_num, (float **)&csmd->bind_coords);
}
/* runtime only */
csmd->delta_cache.deltas = NULL;
csmd->delta_cache.totverts = 0;
}
ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* name */ "CorrectiveSmooth",
/* structName */ "CorrectiveSmoothModifierData",
/* structSize */ sizeof(CorrectiveSmoothModifierData),
/* srna */ &RNA_CorrectiveSmoothModifier,
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
/* icon */ ICON_MOD_SMOOTH,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* modifyMesh */ NULL,
/* modifyHair */ NULL,
/* modifyGeometrySet */ NULL,
/* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
Depsgraph: New dependency graph integration commit This commit integrates the work done so far on the new dependency graph system, where goal was to replace legacy depsgraph with the new one, supporting loads of neat features like: - More granular dependency relation nature, which solves issues with fake cycles in the dependencies. - Move towards all-animatable, by better integration of drivers into the system. - Lay down some basis for upcoming copy-on-write, overrides and so on. The new system is living side-by-side with the previous one and disabled by default, so nothing will become suddenly broken. The way to enable new depsgraph is to pass `--new-depsgraph` command line argument. It's a bit early to consider the system production-ready, there are some TODOs and issues were discovered during the merge period, they'll be addressed ASAP. But it's important to merge, because it's the only way to attract artists to really start testing this system. There are number of assorted documents related on the design of the new system: * http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents * http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph There are also some user-related information online: * http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/ * http://code.blender.org/2015/03/more-dependency-graph-tricks/ Kudos to everyone who was involved into the project: - Joshua "Aligorith" Leung -- design specification, initial code - Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes - Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the project and so - Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the issues and recording/writing documentation. - Everyone else who i forgot to mention here :)
2015-05-12 15:05:57 +05:00
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
/* blendWrite */ blendWrite,
/* blendRead */ blendRead,
};