2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-01-05 15:19:31 +00:00
|
|
|
* ***** 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-01-05 15:19:31 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
* meshlaplacian.c: Algorithms using the mesh laplacian.
|
|
|
|
*/
|
|
|
|
|
2011-02-27 20:29:51 +00:00
|
|
|
/** \file blender/editors/armature/meshlaplacian.c
|
|
|
|
* \ingroup edarmature
|
|
|
|
*/
|
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "BLI_edgehash.h"
|
|
|
|
#include "BLI_memarena.h"
|
2012-01-11 12:33:51 +00:00
|
|
|
#include "BLI_string.h"
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-17 14:27:46 +00:00
|
|
|
#include "BLF_translation.h"
|
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2010-04-23 11:19:06 +00:00
|
|
|
#include "BKE_modifier.h"
|
2012-02-13 04:21:22 +00:00
|
|
|
#include "BKE_mesh.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
#ifdef RIGID_DEFORM
|
|
|
|
#include "BLI_polardecomp.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ONL_opennl.h"
|
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
#include "ED_mesh.h"
|
2011-02-14 17:55:27 +00:00
|
|
|
#include "ED_armature.h"
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "meshlaplacian.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* ************* XXX *************** */
|
2010-10-17 06:38:56 +00:00
|
|
|
static void waitcursor(int UNUSED(val)) {}
|
2010-10-16 14:32:17 +00:00
|
|
|
static void progress_bar(int UNUSED(dummy_val), const char *UNUSED(dummy)) {}
|
2010-12-03 12:30:59 +00:00
|
|
|
static void start_progress_bar(void) {}
|
|
|
|
static void end_progress_bar(void) {}
|
2010-12-03 17:05:21 +00:00
|
|
|
static void error(const char *str) { printf("error: %s\n", str); }
|
2009-01-05 15:19:31 +00:00
|
|
|
/* ************* XXX *************** */
|
|
|
|
|
|
|
|
|
|
|
|
/************************** Laplacian System *****************************/
|
|
|
|
|
|
|
|
struct LaplacianSystem {
|
2012-05-08 20:18:33 +00:00
|
|
|
NLContext context; /* opennl context */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
int totvert, totface;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
float **verts; /* vertex coordinates */
|
|
|
|
float *varea; /* vertex weights for laplacian computation */
|
|
|
|
char *vpinned; /* vertex pinning */
|
|
|
|
int (*faces)[3]; /* face vertex indices */
|
|
|
|
float (*fweights)[3]; /* cotangent weights per face */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
int areaweights; /* use area in cotangent weights? */
|
|
|
|
int storeweights; /* store cotangent weights in fweights */
|
|
|
|
int nlbegun; /* nlBegin(NL_SYSTEM/NL_MATRIX) done */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
EdgeHash *edgehash; /* edge hash for construction */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
struct HeatWeighting {
|
2009-11-28 13:33:17 +00:00
|
|
|
MFace *mface;
|
|
|
|
int totvert;
|
|
|
|
int totface;
|
2012-05-08 20:18:33 +00:00
|
|
|
float (*verts)[3]; /* vertex coordinates */
|
|
|
|
float (*vnors)[3]; /* vertex normals */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
float (*root)[3]; /* bone root */
|
|
|
|
float (*tip)[3]; /* bone tip */
|
2009-11-28 13:33:17 +00:00
|
|
|
float (*source)[3]; /* vertex source */
|
|
|
|
int numsource;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
float *H; /* diagonal H matrix */
|
|
|
|
float *p; /* values from all p vectors */
|
|
|
|
float *mindist; /* minimum distance to a bone for all vertices */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
BVHTree *bvhtree; /* ray tracing acceleration structure */
|
|
|
|
MFace **vface; /* a face that the vertex belongs to */
|
2009-01-05 15:19:31 +00:00
|
|
|
} heat;
|
|
|
|
|
|
|
|
#ifdef RIGID_DEFORM
|
|
|
|
struct RigidDeformation {
|
|
|
|
EditMesh *mesh;
|
|
|
|
|
|
|
|
float (*R)[3][3];
|
|
|
|
float (*rhs)[3];
|
|
|
|
float (*origco)[3];
|
|
|
|
int thrownerror;
|
|
|
|
} rigid;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Laplacian matrix construction */
|
|
|
|
|
|
|
|
/* Computation of these weights for the laplacian is based on:
|
2012-03-03 16:31:46 +00:00
|
|
|
* "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
|
|
|
|
* Meyer et al, 2002. Section 3.5, formula (8).
|
|
|
|
*
|
|
|
|
* We do it a bit different by going over faces instead of going over each
|
|
|
|
* vertex and adjacent faces, since we don't store this adjacency. Also, the
|
|
|
|
* formulas are tweaked a bit to work for non-manifold meshes. */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
|
|
|
|
{
|
|
|
|
void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (p)
|
2012-05-08 20:18:33 +00:00
|
|
|
*p = (void *)((intptr_t)*p + (intptr_t)1);
|
2009-01-05 15:19:31 +00:00
|
|
|
else
|
2012-05-08 20:18:33 +00:00
|
|
|
BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
|
|
|
|
{
|
|
|
|
return (int)(intptr_t)BLI_edgehash_lookup(edgehash, v1, v2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static float cotan_weight(float *v1, float *v2, float *v3)
|
|
|
|
{
|
|
|
|
float a[3], b[3], c[3], clen;
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(a, v2, v1);
|
|
|
|
sub_v3_v3v3(b, v3, v1);
|
|
|
|
cross_v3_v3v3(c, a, b);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
clen = len_v3(c);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
if (clen == 0.0f)
|
|
|
|
return 0.0f;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
return dot_v3v3(a, b) / clen;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
|
|
|
|
{
|
|
|
|
float t1, t2, t3, len1, len2, len3, area;
|
2012-05-08 20:18:33 +00:00
|
|
|
float *varea = sys->varea, *v1, *v2, *v3;
|
2009-01-05 15:19:31 +00:00
|
|
|
int obtuse = 0;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
v1 = sys->verts[i1];
|
|
|
|
v2 = sys->verts[i2];
|
|
|
|
v3 = sys->verts[i3];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
t1 = cotan_weight(v1, v2, v3);
|
|
|
|
t2 = cotan_weight(v2, v3, v1);
|
|
|
|
t3 = cotan_weight(v3, v1, v2);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
if (angle_v3v3v3(v2, v1, v3) > DEG2RADF(90.0f)) obtuse = 1;
|
|
|
|
else if (angle_v3v3v3(v1, v2, v3) > DEG2RADF(90.0f)) obtuse = 2;
|
|
|
|
else if (angle_v3v3v3(v1, v3, v2) > DEG2RADF(90.0f)) obtuse = 3;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
if (obtuse > 0) {
|
2012-05-08 20:18:33 +00:00
|
|
|
area = area_tri_v3(v1, v2, v3);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
varea[i1] += (obtuse == 1) ? area : area * 0.5f;
|
|
|
|
varea[i2] += (obtuse == 2) ? area : area * 0.5f;
|
|
|
|
varea[i3] += (obtuse == 3) ? area : area * 0.5f;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 20:18:33 +00:00
|
|
|
len1 = len_v3v3(v2, v3);
|
|
|
|
len2 = len_v3v3(v1, v3);
|
|
|
|
len3 = len_v3v3(v1, v2);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
t1 *= len1 * len1;
|
|
|
|
t2 *= len2 * len2;
|
|
|
|
t3 *= len3 * len3;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
varea[i1] += (t2 + t3) * 0.25f;
|
|
|
|
varea[i2] += (t1 + t3) * 0.25f;
|
|
|
|
varea[i3] += (t1 + t2) * 0.25f;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
|
|
|
|
{
|
|
|
|
float t1, t2, t3;
|
2012-05-08 20:18:33 +00:00
|
|
|
float *varea = sys->varea, *v1, *v2, *v3;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
v1 = sys->verts[i1];
|
|
|
|
v2 = sys->verts[i2];
|
|
|
|
v3 = sys->verts[i3];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* instead of *0.5 we divided by the number of faces of the edge, it still
|
2012-03-03 16:31:46 +00:00
|
|
|
* needs to be verified that this is indeed the correct thing to do! */
|
2012-05-08 20:18:33 +00:00
|
|
|
t1 = cotan_weight(v1, v2, v3) / laplacian_edge_count(sys->edgehash, i2, i3);
|
|
|
|
t2 = cotan_weight(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
|
|
|
|
t3 = cotan_weight(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
nlMatrixAdd(i1, i1, (t2 + t3) * varea[i1]);
|
|
|
|
nlMatrixAdd(i2, i2, (t1 + t3) * varea[i2]);
|
|
|
|
nlMatrixAdd(i3, i3, (t1 + t2) * varea[i3]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
nlMatrixAdd(i1, i2, -t3 * varea[i1]);
|
|
|
|
nlMatrixAdd(i2, i1, -t3 * varea[i2]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
nlMatrixAdd(i2, i3, -t1 * varea[i2]);
|
|
|
|
nlMatrixAdd(i3, i2, -t1 * varea[i3]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
nlMatrixAdd(i3, i1, -t2 * varea[i3]);
|
|
|
|
nlMatrixAdd(i1, i3, -t2 * varea[i1]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->storeweights) {
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->fweights[f][0] = t1 * varea[i1];
|
|
|
|
sys->fweights[f][1] = t2 * varea[i2];
|
|
|
|
sys->fweights[f][2] = t3 * varea[i3];
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totface, int lsq)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
LaplacianSystem *sys;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys = MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->verts = MEM_callocN(sizeof(float *) * totvert, "LaplacianSystemVerts");
|
|
|
|
sys->vpinned = MEM_callocN(sizeof(char) * totvert, "LaplacianSystemVpinned");
|
|
|
|
sys->faces = MEM_callocN(sizeof(int) * 3 * totface, "LaplacianSystemFaces");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->totvert = 0;
|
|
|
|
sys->totface = 0;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->areaweights = 1;
|
|
|
|
sys->storeweights = 0;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* create opennl context */
|
|
|
|
nlNewContext();
|
|
|
|
nlSolverParameteri(NL_NB_VARIABLES, totvert);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lsq)
|
2009-01-05 15:19:31 +00:00
|
|
|
nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->context = nlGetCurrent();
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
return sys;
|
|
|
|
}
|
|
|
|
|
|
|
|
void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->verts[sys->totvert] = co;
|
|
|
|
sys->vpinned[sys->totvert] = pinned;
|
2009-01-05 15:19:31 +00:00
|
|
|
sys->totvert++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->faces[sys->totface][0] = v1;
|
|
|
|
sys->faces[sys->totface][1] = v2;
|
|
|
|
sys->faces[sys->totface][2] = v3;
|
2009-01-05 15:19:31 +00:00
|
|
|
sys->totface++;
|
|
|
|
}
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static void laplacian_system_construct_end(LaplacianSystem *sys)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
int (*face)[3];
|
2012-05-08 20:18:33 +00:00
|
|
|
int a, totvert = sys->totvert, totface = sys->totface;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
laplacian_begin_solve(sys, 0);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->edgehash = BLI_edgehash_new();
|
|
|
|
for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
|
|
|
|
laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
|
|
|
|
laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->areaweights)
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, face = sys->faces; a < sys->totface; a++, face++)
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totvert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->areaweights) {
|
|
|
|
if (sys->varea[a] != 0.0f)
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->varea[a] = 0.5f / sys->varea[a];
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->varea[a] = 1.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* for heat weighting */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->heat.H)
|
2009-01-05 15:19:31 +00:00
|
|
|
nlMatrixAdd(a, a, sys->heat.H[a]);
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->storeweights)
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->fweights = MEM_callocN(sizeof(float) * 3 * totface, "LaplacianFWeight");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, face = sys->faces; a < totface; a++, face++)
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
|
|
|
|
|
|
|
|
MEM_freeN(sys->faces);
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->faces = NULL;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->varea) {
|
2009-01-05 15:19:31 +00:00
|
|
|
MEM_freeN(sys->varea);
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->varea = NULL;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_edgehash_free(sys->edgehash, NULL);
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->edgehash = NULL;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static void laplacian_system_delete(LaplacianSystem *sys)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->verts) MEM_freeN(sys->verts);
|
|
|
|
if (sys->varea) MEM_freeN(sys->varea);
|
|
|
|
if (sys->vpinned) MEM_freeN(sys->vpinned);
|
|
|
|
if (sys->faces) MEM_freeN(sys->faces);
|
|
|
|
if (sys->fweights) MEM_freeN(sys->fweights);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
nlDeleteContext(sys->context);
|
|
|
|
MEM_freeN(sys);
|
|
|
|
}
|
|
|
|
|
|
|
|
void laplacian_begin_solve(LaplacianSystem *sys, int index)
|
|
|
|
{
|
|
|
|
int a;
|
|
|
|
|
|
|
|
if (!sys->nlbegun) {
|
|
|
|
nlBegin(NL_SYSTEM);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (index >= 0) {
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < sys->totvert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->vpinned[a]) {
|
2009-01-05 15:19:31 +00:00
|
|
|
nlSetVariable(0, a, sys->verts[a][index]);
|
|
|
|
nlLockVariable(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nlBegin(NL_MATRIX);
|
|
|
|
sys->nlbegun = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-16 14:32:17 +00:00
|
|
|
void laplacian_add_right_hand_side(LaplacianSystem *UNUSED(sys), int v, float value)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
nlRightHandSideAdd(0, v, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
int laplacian_system_solve(LaplacianSystem *sys)
|
|
|
|
{
|
|
|
|
nlEnd(NL_MATRIX);
|
|
|
|
nlEnd(NL_SYSTEM);
|
|
|
|
sys->nlbegun = 0;
|
|
|
|
|
|
|
|
//nlPrintMatrix();
|
|
|
|
|
|
|
|
return nlSolveAdvanced(NULL, NL_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
float laplacian_system_get_solution(int v)
|
|
|
|
{
|
|
|
|
return nlGetVariable(0, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************* Heat Bone Weighting ******************************/
|
|
|
|
/* From "Automatic Rigging and Animation of 3D Characters"
|
2012-03-03 16:31:46 +00:00
|
|
|
* Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
#define C_WEIGHT 1.0f
|
|
|
|
#define WEIGHT_LIMIT_START 0.05f
|
|
|
|
#define WEIGHT_LIMIT_END 0.025f
|
|
|
|
#define DISTANCE_EPSILON 1e-4f
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2010-06-22 15:10:57 +00:00
|
|
|
typedef struct BVHCallbackUserData {
|
|
|
|
float start[3];
|
|
|
|
float vec[3];
|
|
|
|
LaplacianSystem *sys;
|
|
|
|
} BVHCallbackUserData;
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
|
2010-06-22 15:10:57 +00:00
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
BVHCallbackUserData *data = (struct BVHCallbackUserData *)userdata;
|
2010-06-22 15:10:57 +00:00
|
|
|
MFace *mf = data->sys->heat.mface + index;
|
|
|
|
float (*verts)[3] = data->sys->heat.verts;
|
|
|
|
float lambda, uv[2], n[3], dir[3];
|
|
|
|
|
|
|
|
mul_v3_v3fl(dir, data->vec, hit->dist);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) {
|
2010-06-22 15:10:57 +00:00
|
|
|
normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
|
2010-06-22 15:10:57 +00:00
|
|
|
hit->index = index;
|
|
|
|
hit->dist *= lambda;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mul_v3_v3fl(dir, data->vec, hit->dist);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) {
|
2010-06-22 15:10:57 +00:00
|
|
|
normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
|
2010-06-22 15:10:57 +00:00
|
|
|
hit->index = index;
|
|
|
|
hit->dist *= lambda;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
/* Raytracing for vertex to bone/vertex visibility */
|
2009-01-05 15:19:31 +00:00
|
|
|
static void heat_ray_tree_create(LaplacianSystem *sys)
|
|
|
|
{
|
2009-11-28 13:33:17 +00:00
|
|
|
MFace *mface = sys->heat.mface;
|
2010-06-22 15:10:57 +00:00
|
|
|
float (*verts)[3] = sys->heat.verts;
|
2009-11-28 13:33:17 +00:00
|
|
|
int totface = sys->heat.totface;
|
|
|
|
int totvert = sys->heat.totvert;
|
2009-01-05 15:19:31 +00:00
|
|
|
int a;
|
|
|
|
|
2010-06-22 15:10:57 +00:00
|
|
|
sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6);
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.vface = MEM_callocN(sizeof(MFace *) * totvert, "HeatVFaces");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totface; a++) {
|
|
|
|
MFace *mf = mface + a;
|
2010-06-22 15:10:57 +00:00
|
|
|
float bb[6];
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
INIT_MINMAX(bb, bb + 3);
|
2012-05-13 11:05:52 +00:00
|
|
|
minmax_v3v3_v3(bb, bb + 3, verts[mf->v1]);
|
|
|
|
minmax_v3v3_v3(bb, bb + 3, verts[mf->v2]);
|
|
|
|
minmax_v3v3_v3(bb, bb + 3, verts[mf->v3]);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mf->v4) {
|
2012-05-13 11:05:52 +00:00
|
|
|
minmax_v3v3_v3(bb, bb + 3, verts[mf->v4]);
|
2010-06-22 15:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
|
|
|
//Setup inverse pointers to use on isect.orig
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.vface[mf->v1] = mf;
|
|
|
|
sys->heat.vface[mf->v2] = mf;
|
|
|
|
sys->heat.vface[mf->v3] = mf;
|
|
|
|
if (mf->v4) sys->heat.vface[mf->v4] = mf;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
2010-06-22 15:10:57 +00:00
|
|
|
|
|
|
|
BLI_bvhtree_balance(sys->heat.bvhtree);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
2011-04-21 13:11:51 +00:00
|
|
|
BVHTreeRayHit hit;
|
2010-06-22 15:10:57 +00:00
|
|
|
BVHCallbackUserData data;
|
2009-01-05 15:19:31 +00:00
|
|
|
MFace *mface;
|
2009-10-22 23:22:05 +00:00
|
|
|
float end[3];
|
2009-01-05 15:19:31 +00:00
|
|
|
int visible;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mface = sys->heat.vface[vertex];
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!mface)
|
2009-01-05 15:19:31 +00:00
|
|
|
return 1;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
data.sys = sys;
|
2010-06-22 15:10:57 +00:00
|
|
|
copy_v3_v3(data.start, sys->heat.verts[vertex]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->heat.root) /* bone */
|
2010-06-22 15:10:57 +00:00
|
|
|
closest_to_line_segment_v3(end, data.start,
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.root[source], sys->heat.tip[source]);
|
2009-11-28 13:33:17 +00:00
|
|
|
else /* vertex */
|
|
|
|
copy_v3_v3(end, sys->heat.source[source]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2010-06-22 15:10:57 +00:00
|
|
|
sub_v3_v3v3(data.vec, end, data.start);
|
|
|
|
madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
|
2011-03-28 17:08:33 +00:00
|
|
|
mul_v3_fl(data.vec, 1.0f - 2e-5f);
|
2009-10-22 23:22:05 +00:00
|
|
|
|
2010-06-22 15:10:57 +00:00
|
|
|
/* pass normalized vec + distance to bvh */
|
|
|
|
hit.index = -1;
|
|
|
|
hit.dist = normalize_v3(data.vec);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
visible = BLI_bvhtree_ray_cast(sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void *)&data) == -1;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
return visible;
|
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
float closest[3], d[3], dist, cosine;
|
|
|
|
|
|
|
|
/* compute euclidian distance */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->heat.root) /* bone */
|
2009-11-28 13:33:17 +00:00
|
|
|
closest_to_line_segment_v3(closest, sys->heat.verts[vertex],
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.root[source], sys->heat.tip[source]);
|
2009-11-28 13:33:17 +00:00
|
|
|
else /* vertex */
|
|
|
|
copy_v3_v3(closest, sys->heat.source[source]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
|
2012-05-08 20:18:33 +00:00
|
|
|
dist = normalize_v3(d);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* if the vertex normal does not point along the bone, increase distance */
|
2012-05-08 20:18:33 +00:00
|
|
|
cosine = dot_v3v3(d, sys->heat.vnors[vertex]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
return dist / (0.5f * (cosine + 1.001f));
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
static int heat_source_closest(LaplacianSystem *sys, int vertex, int source)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
float dist;
|
2009-11-28 13:33:17 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
dist = heat_source_distance(sys, vertex, source);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
if (dist <= sys->heat.mindist[vertex] * (1.0f + DISTANCE_EPSILON))
|
2012-03-24 06:38:07 +00:00
|
|
|
if (heat_ray_source_visible(sys, vertex, source))
|
2009-01-05 15:19:31 +00:00
|
|
|
return 1;
|
2009-11-28 13:33:17 +00:00
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void heat_set_H(LaplacianSystem *sys, int vertex)
|
|
|
|
{
|
|
|
|
float dist, mindist, h;
|
|
|
|
int j, numclosest = 0;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mindist = 1e10;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute minimum distance */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (j = 0; j < sys->heat.numsource; j++) {
|
|
|
|
dist = heat_source_distance(sys, vertex, j);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dist < mindist)
|
2012-05-08 20:18:33 +00:00
|
|
|
mindist = dist;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.mindist[vertex] = mindist;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
/* count number of sources with approximately this minimum distance */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (j = 0; j < sys->heat.numsource; j++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (heat_source_closest(sys, vertex, j))
|
2009-01-05 15:19:31 +00:00
|
|
|
numclosest++;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.p[vertex] = (numclosest > 0) ? 1.0f / numclosest : 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute H entry */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (numclosest > 0) {
|
2012-10-23 13:28:22 +00:00
|
|
|
mindist = max_ff(mindist, 1e-4f);
|
2012-05-08 20:18:33 +00:00
|
|
|
h = numclosest * C_WEIGHT / (mindist * mindist);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else
|
2012-05-08 20:18:33 +00:00
|
|
|
h = 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.H[vertex] = h;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static void heat_calc_vnormals(LaplacianSystem *sys)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
float fnor[3];
|
|
|
|
int a, v1, v2, v3, (*face)[3];
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.vnors = MEM_callocN(sizeof(float) * 3 * sys->totvert, "HeatVNors");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
|
|
|
|
v1 = (*face)[0];
|
|
|
|
v2 = (*face)[1];
|
|
|
|
v3 = (*face)[2];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
normal_tri_v3(fnor, sys->verts[v1], sys->verts[v2], sys->verts[v3]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3(sys->heat.vnors[v1], fnor);
|
|
|
|
add_v3_v3(sys->heat.vnors[v2], fnor);
|
|
|
|
add_v3_v3(sys->heat.vnors[v3], fnor);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < sys->totvert; a++)
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(sys->heat.vnors[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void heat_laplacian_create(LaplacianSystem *sys)
|
|
|
|
{
|
2009-11-28 13:33:17 +00:00
|
|
|
MFace *mface = sys->heat.mface, *mf;
|
2012-05-08 20:18:33 +00:00
|
|
|
int totface = sys->heat.totface;
|
|
|
|
int totvert = sys->heat.totvert;
|
2009-01-05 15:19:31 +00:00
|
|
|
int a;
|
|
|
|
|
|
|
|
/* heat specific definitions */
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.mindist = MEM_callocN(sizeof(float) * totvert, "HeatMinDist");
|
|
|
|
sys->heat.H = MEM_callocN(sizeof(float) * totvert, "HeatH");
|
|
|
|
sys->heat.p = MEM_callocN(sizeof(float) * totvert, "HeatP");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* add verts and faces to laplacian */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totvert; a++)
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_vertex(sys, sys->heat.verts[a], 0);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, mf = mface; a < totface; a++, mf++) {
|
2009-11-28 13:33:17 +00:00
|
|
|
laplacian_add_triangle(sys, mf->v1, mf->v2, mf->v3);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mf->v4)
|
2009-11-28 13:33:17 +00:00
|
|
|
laplacian_add_triangle(sys, mf->v1, mf->v3, mf->v4);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* for distance computation in set_H */
|
|
|
|
heat_calc_vnormals(sys);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totvert; a++)
|
2009-01-05 15:19:31 +00:00
|
|
|
heat_set_H(sys, a);
|
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
static void heat_system_free(LaplacianSystem *sys)
|
|
|
|
{
|
2010-06-22 15:10:57 +00:00
|
|
|
BLI_bvhtree_free(sys->heat.bvhtree);
|
2009-11-28 13:33:17 +00:00
|
|
|
MEM_freeN(sys->heat.vface);
|
|
|
|
|
|
|
|
MEM_freeN(sys->heat.mindist);
|
|
|
|
MEM_freeN(sys->heat.H);
|
|
|
|
MEM_freeN(sys->heat.p);
|
|
|
|
MEM_freeN(sys->heat.vnors);
|
|
|
|
}
|
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
static float heat_limit_weight(float weight)
|
|
|
|
{
|
|
|
|
float t;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight < WEIGHT_LIMIT_END) {
|
2009-01-05 15:19:31 +00:00
|
|
|
return 0.0f;
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (weight < WEIGHT_LIMIT_START) {
|
2012-05-08 20:18:33 +00:00
|
|
|
t = (weight - WEIGHT_LIMIT_END) / (WEIGHT_LIMIT_START - WEIGHT_LIMIT_END);
|
|
|
|
return t * WEIGHT_LIMIT_START;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return weight;
|
|
|
|
}
|
|
|
|
|
2012-12-23 01:18:35 +00:00
|
|
|
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
|
|
|
|
bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
|
|
|
|
float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
LaplacianSystem *sys;
|
2012-02-13 04:21:22 +00:00
|
|
|
MPoly *mp;
|
|
|
|
MLoop *ml;
|
|
|
|
MFace *mf;
|
2009-01-05 15:19:31 +00:00
|
|
|
float solution, weight;
|
2012-05-08 20:18:33 +00:00
|
|
|
int *vertsflipped = NULL, *mask = NULL;
|
2012-02-13 04:21:22 +00:00
|
|
|
int a, tottri, j, bbone, firstsegment, lastsegment;
|
2011-01-09 01:17:56 +00:00
|
|
|
|
2011-09-19 02:43:03 +00:00
|
|
|
MVert *mvert = me->mvert;
|
2012-05-08 20:18:33 +00:00
|
|
|
int use_vert_sel = FALSE;
|
|
|
|
int use_face_sel = FALSE;
|
2011-07-18 17:38:17 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
*err_str = NULL;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2013-06-08 17:56:45 +00:00
|
|
|
/* bone heat needs triangulated faces */
|
|
|
|
BKE_mesh_tessface_ensure(me);
|
|
|
|
|
|
|
|
for (tottri = 0, a = 0, mf = me->mface; a < me->totface; mf++, a++) {
|
|
|
|
tottri++;
|
|
|
|
if (mf->v4) tottri++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tottri == 0)
|
|
|
|
return;
|
|
|
|
|
2010-03-30 12:01:17 +00:00
|
|
|
/* count triangles and create mask */
|
2012-12-22 14:25:34 +00:00
|
|
|
if ((use_face_sel = ((me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0)) ||
|
|
|
|
(use_vert_sel = ((me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0)))
|
2011-09-19 02:43:03 +00:00
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");
|
2010-03-30 12:01:17 +00:00
|
|
|
|
2011-09-18 17:10:28 +00:00
|
|
|
/* (added selectedVerts content for vertex mask, they used to just equal 1) */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (use_vert_sel) {
|
2012-06-28 07:18:19 +00:00
|
|
|
for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
|
|
|
|
for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
|
|
|
|
if (use_vert_sel) {
|
|
|
|
mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0;
|
|
|
|
}
|
2012-02-13 04:21:22 +00:00
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-13 03:32:47 +00:00
|
|
|
else if (use_face_sel) {
|
2012-06-28 07:18:19 +00:00
|
|
|
for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) {
|
|
|
|
if (mp->flag & ME_FACE_SEL) {
|
|
|
|
for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) {
|
|
|
|
mask[ml->v] = 1;
|
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-30 12:01:17 +00:00
|
|
|
}
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* create laplacian */
|
2012-02-13 04:21:22 +00:00
|
|
|
sys = laplacian_system_construct_begin(me->totvert, tottri, 1);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.mface = me->mface;
|
|
|
|
sys->heat.totface = me->totface;
|
|
|
|
sys->heat.totvert = me->totvert;
|
|
|
|
sys->heat.verts = verts;
|
|
|
|
sys->heat.root = root;
|
|
|
|
sys->heat.tip = tip;
|
|
|
|
sys->heat.numsource = numsource;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
heat_ray_tree_create(sys);
|
|
|
|
heat_laplacian_create(sys);
|
|
|
|
|
|
|
|
laplacian_system_construct_end(sys);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dgroupflip) {
|
2012-05-08 20:18:33 +00:00
|
|
|
vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped");
|
|
|
|
for (a = 0; a < me->totvert; a++)
|
2009-01-05 15:19:31 +00:00
|
|
|
vertsflipped[a] = mesh_get_x_mirror_vert(ob, a);
|
|
|
|
}
|
2011-02-27 06:19:40 +00:00
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
/* compute weights per bone */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (j = 0; j < numsource; j++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!selected[j])
|
2009-01-05 15:19:31 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]);
|
|
|
|
lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]);
|
|
|
|
bbone = !(firstsegment && lastsegment);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* clear weights */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (bbone && firstsegment) {
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < me->totvert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mask && !mask[a])
|
2010-03-30 12:01:17 +00:00
|
|
|
continue;
|
|
|
|
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgrouplist[j], a);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill right hand side */
|
|
|
|
laplacian_begin_solve(sys, -1);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < me->totvert; a++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (heat_source_closest(sys, a, j))
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_right_hand_side(sys, a,
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.H[a] * sys->heat.p[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* solve */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (laplacian_system_solve(sys)) {
|
2009-01-05 15:19:31 +00:00
|
|
|
/* load solution into vertex groups */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < me->totvert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mask && !mask[a])
|
2010-03-30 12:01:17 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
solution = laplacian_system_get_solution(a);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (bbone) {
|
|
|
|
if (solution > 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_add(ob, dgrouplist[j], a, solution,
|
2012-05-08 20:18:33 +00:00
|
|
|
WEIGHT_ADD);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = heat_limit_weight(solution);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight > 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_add(ob, dgrouplist[j], a, weight,
|
2012-05-08 20:18:33 +00:00
|
|
|
WEIGHT_REPLACE);
|
2009-01-05 15:19:31 +00:00
|
|
|
else
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgrouplist[j], a);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* do same for mirror */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
|
|
|
|
if (bbone) {
|
|
|
|
if (solution > 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
|
2012-05-08 20:18:33 +00:00
|
|
|
solution, WEIGHT_ADD);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = heat_limit_weight(solution);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight > 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a],
|
2012-05-08 20:18:33 +00:00
|
|
|
weight, WEIGHT_REPLACE);
|
2009-01-05 15:19:31 +00:00
|
|
|
else
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (*err_str == NULL) {
|
2012-10-26 17:32:50 +00:00
|
|
|
*err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones");
|
2009-01-05 15:19:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove too small vertex weights */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (bbone && lastsegment) {
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < me->totvert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mask && !mask[a])
|
2010-03-30 12:01:17 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a);
|
|
|
|
weight = heat_limit_weight(weight);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight <= 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgrouplist[j], a);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]);
|
|
|
|
weight = heat_limit_weight(weight);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight <= 0.0f)
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vertsflipped) MEM_freeN(vertsflipped);
|
|
|
|
if (mask) MEM_freeN(mask);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
heat_system_free(sys);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
laplacian_system_delete(sys);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef RIGID_DEFORM
|
|
|
|
/********************** As-Rigid-As-Possible Deformation ******************/
|
|
|
|
/* From "As-Rigid-As-Possible Surface Modeling",
|
2012-03-03 16:31:46 +00:00
|
|
|
* Olga Sorkine and Marc Alexa, ESGP 2007. */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* investigate:
|
2012-03-03 16:31:46 +00:00
|
|
|
* - transpose R in orthogonal
|
|
|
|
* - flipped normals and per face adding
|
2012-03-08 04:12:11 +00:00
|
|
|
* - move canceling to transform, make origco pointer
|
2012-03-03 16:31:46 +00:00
|
|
|
*/
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
static LaplacianSystem *RigidDeformSystem = NULL;
|
|
|
|
|
|
|
|
static void rigid_add_half_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
|
|
|
|
{
|
|
|
|
float e[3], e_[3];
|
|
|
|
int i;
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(e, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
|
|
|
|
sub_v3_v3v3(e_, v1->co, v2->co);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* formula (5) */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
sys->rigid.R[v1->tmp.l][i][0] += w * e[0] * e_[i];
|
|
|
|
sys->rigid.R[v1->tmp.l][i][1] += w * e[1] * e_[i];
|
|
|
|
sys->rigid.R[v1->tmp.l][i][2] += w * e[2] * e_[i];
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rigid_add_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
|
|
|
|
{
|
|
|
|
rigid_add_half_edge_to_R(sys, v1, v2, w);
|
|
|
|
rigid_add_half_edge_to_R(sys, v2, v1, w);
|
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
static void rigid_orthogonalize_R(float R[3][3])
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
HMatrix M, Q, S;
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_m4_m3(M, R);
|
2009-01-05 15:19:31 +00:00
|
|
|
polar_decomp(M, Q, S);
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_m3_m4(R, Q);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rigid_add_half_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
|
|
|
|
{
|
|
|
|
/* formula (8) */
|
|
|
|
float Rsum[3][3], rhs[3];
|
|
|
|
|
|
|
|
if (sys->vpinned[v1->tmp.l])
|
|
|
|
return;
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
add_m3_m3m3(Rsum, sys->rigid.R[v1->tmp.l], sys->rigid.R[v2->tmp.l]);
|
|
|
|
transpose_m3(Rsum);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
sub_v3_v3v3(rhs, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
|
|
|
|
mul_m3_v3(Rsum, rhs);
|
|
|
|
mul_v3_fl(rhs, 0.5f);
|
|
|
|
mul_v3_fl(rhs, w);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2010-04-21 12:27:48 +00:00
|
|
|
add_v3_v3(sys->rigid.rhs[v1->tmp.l], rhs);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void rigid_add_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
|
|
|
|
{
|
|
|
|
rigid_add_half_edge_to_rhs(sys, v1, v2, w);
|
|
|
|
rigid_add_half_edge_to_rhs(sys, v2, v1, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rigid_deform_iteration()
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
LaplacianSystem *sys = RigidDeformSystem;
|
2009-01-05 15:19:31 +00:00
|
|
|
EditMesh *em;
|
|
|
|
EditVert *eve;
|
|
|
|
EditFace *efa;
|
|
|
|
int a, i;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!sys)
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
nlMakeCurrent(sys->context);
|
2012-05-08 20:18:33 +00:00
|
|
|
em = sys->rigid.mesh;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute R */
|
2012-05-08 20:18:33 +00:00
|
|
|
memset(sys->rigid.R, 0, sizeof(float) * 3 * 3 * sys->totvert);
|
|
|
|
memset(sys->rigid.rhs, 0, sizeof(float) * 3 * sys->totvert);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, efa = em->faces.first; efa; efa = efa->next, a++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
rigid_add_edge_to_R(sys, efa->v1, efa->v2, sys->fweights[a][2]);
|
|
|
|
rigid_add_edge_to_R(sys, efa->v2, efa->v3, sys->fweights[a][0]);
|
|
|
|
rigid_add_edge_to_R(sys, efa->v3, efa->v1, sys->fweights[a][1]);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (efa->v4) {
|
2009-01-05 15:19:31 +00:00
|
|
|
a++;
|
|
|
|
rigid_add_edge_to_R(sys, efa->v1, efa->v3, sys->fweights[a][2]);
|
|
|
|
rigid_add_edge_to_R(sys, efa->v3, efa->v4, sys->fweights[a][0]);
|
|
|
|
rigid_add_edge_to_R(sys, efa->v4, efa->v1, sys->fweights[a][1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
rigid_orthogonalize_R(sys->rigid.R[a]);
|
2012-05-08 20:18:33 +00:00
|
|
|
eve->tmp.l = a;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* compute right hand sides for solving */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, efa = em->faces.first; efa; efa = efa->next, a++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
rigid_add_edge_to_rhs(sys, efa->v1, efa->v2, sys->fweights[a][2]);
|
|
|
|
rigid_add_edge_to_rhs(sys, efa->v2, efa->v3, sys->fweights[a][0]);
|
|
|
|
rigid_add_edge_to_rhs(sys, efa->v3, efa->v1, sys->fweights[a][1]);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (efa->v4) {
|
2009-01-05 15:19:31 +00:00
|
|
|
a++;
|
|
|
|
rigid_add_edge_to_rhs(sys, efa->v1, efa->v3, sys->fweights[a][2]);
|
|
|
|
rigid_add_edge_to_rhs(sys, efa->v3, efa->v4, sys->fweights[a][0]);
|
|
|
|
rigid_add_edge_to_rhs(sys, efa->v4, efa->v1, sys->fweights[a][1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
/* solve for positions, for X, Y and Z separately */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_begin_solve(sys, i);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < sys->totvert; a++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!sys->vpinned[a])
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (laplacian_system_solve(sys)) {
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
|
|
|
|
eve->co[i] = laplacian_system_get_solution(a);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!sys->rigid.thrownerror) {
|
2011-09-19 12:26:20 +00:00
|
|
|
error("RigidDeform: failed to find solution");
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->rigid.thrownerror = 1;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rigid_laplacian_create(LaplacianSystem *sys)
|
|
|
|
{
|
|
|
|
EditMesh *em = sys->rigid.mesh;
|
|
|
|
EditVert *eve;
|
|
|
|
EditFace *efa;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
/* add verts and faces to laplacian */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++) {
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_vertex(sys, eve->co, eve->pinned);
|
2012-05-08 20:18:33 +00:00
|
|
|
eve->tmp.l = a;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (efa = em->faces.first; efa; efa = efa->next) {
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_triangle(sys,
|
2012-05-08 20:18:33 +00:00
|
|
|
efa->v1->tmp.l, efa->v2->tmp.l, efa->v3->tmp.l);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (efa->v4)
|
2009-01-05 15:19:31 +00:00
|
|
|
laplacian_add_triangle(sys,
|
2012-05-08 20:18:33 +00:00
|
|
|
efa->v1->tmp.l, efa->v3->tmp.l, efa->v4->tmp.l);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rigid_deform_begin(EditMesh *em)
|
|
|
|
{
|
|
|
|
LaplacianSystem *sys;
|
|
|
|
EditVert *eve;
|
|
|
|
EditFace *efa;
|
|
|
|
int a, totvert, totface;
|
|
|
|
|
|
|
|
/* count vertices, triangles */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (totvert = 0, eve = em->verts.first; eve; eve = eve->next)
|
2009-01-05 15:19:31 +00:00
|
|
|
totvert++;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (totface = 0, efa = em->faces.first; efa; efa = efa->next) {
|
2009-01-05 15:19:31 +00:00
|
|
|
totface++;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (efa->v4) totface++;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* create laplacian */
|
|
|
|
sys = laplacian_system_construct_begin(totvert, totface, 0);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->rigid.mesh = em;
|
|
|
|
sys->rigid.R = MEM_callocN(sizeof(float) * 3 * 3 * totvert, "RigidDeformR");
|
|
|
|
sys->rigid.rhs = MEM_callocN(sizeof(float) * 3 * totvert, "RigidDeformRHS");
|
|
|
|
sys->rigid.origco = MEM_callocN(sizeof(float) * 3 * totvert, "RigidDeformCo");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_v3_v3(sys->rigid.origco[a], eve->co);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->areaweights = 0;
|
|
|
|
sys->storeweights = 1;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
rigid_laplacian_create(sys);
|
|
|
|
|
|
|
|
laplacian_system_construct_end(sys);
|
|
|
|
|
|
|
|
RigidDeformSystem = sys;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rigid_deform_end(int cancel)
|
|
|
|
{
|
|
|
|
LaplacianSystem *sys = RigidDeformSystem;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys) {
|
2009-01-05 15:19:31 +00:00
|
|
|
EditMesh *em = sys->rigid.mesh;
|
|
|
|
EditVert *eve;
|
|
|
|
int a;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (cancel)
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!eve->pinned)
|
2009-11-10 20:43:45 +00:00
|
|
|
copy_v3_v3(eve->co, sys->rigid.origco[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sys->rigid.R) MEM_freeN(sys->rigid.R);
|
|
|
|
if (sys->rigid.rhs) MEM_freeN(sys->rigid.rhs);
|
|
|
|
if (sys->rigid.origco) MEM_freeN(sys->rigid.origco);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* free */
|
|
|
|
laplacian_system_delete(sys);
|
|
|
|
}
|
|
|
|
|
|
|
|
RigidDeformSystem = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/************************** Harmonic Coordinates ****************************/
|
|
|
|
/* From "Harmonic Coordinates for Character Articulation",
|
2012-03-03 16:31:46 +00:00
|
|
|
* Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki,
|
|
|
|
* SIGGRAPH 2007. */
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
#define EPSILON 0.0001f
|
|
|
|
|
|
|
|
#define MESHDEFORM_TAG_UNTYPED 0
|
|
|
|
#define MESHDEFORM_TAG_BOUNDARY 1
|
|
|
|
#define MESHDEFORM_TAG_INTERIOR 2
|
|
|
|
#define MESHDEFORM_TAG_EXTERIOR 3
|
|
|
|
|
2011-03-28 17:08:33 +00:00
|
|
|
#define MESHDEFORM_LEN_THRESHOLD 1e-6f
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2011-03-28 17:08:33 +00:00
|
|
|
#define MESHDEFORM_MIN_INFLUENCE 0.0005f
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
static int MESHDEFORM_OFFSET[7][3] = {
|
|
|
|
{0, 0, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}
|
|
|
|
};
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
typedef struct MDefBoundIsect {
|
|
|
|
float co[3], uvw[4];
|
|
|
|
int nvert, v[4], facing;
|
|
|
|
float len;
|
|
|
|
} MDefBoundIsect;
|
|
|
|
|
|
|
|
typedef struct MDefBindInfluence {
|
|
|
|
struct MDefBindInfluence *next;
|
|
|
|
float weight;
|
|
|
|
int vertex;
|
|
|
|
} MDefBindInfluence;
|
|
|
|
|
|
|
|
typedef struct MeshDeformBind {
|
|
|
|
/* grid dimensions */
|
|
|
|
float min[3], max[3];
|
|
|
|
float width[3], halfwidth[3];
|
|
|
|
int size, size3;
|
|
|
|
|
|
|
|
/* meshes */
|
|
|
|
DerivedMesh *cagedm;
|
|
|
|
float (*cagecos)[3];
|
|
|
|
float (*vertexcos)[3];
|
|
|
|
int totvert, totcagevert;
|
|
|
|
|
|
|
|
/* grids */
|
|
|
|
MemArena *memarena;
|
|
|
|
MDefBoundIsect *(*boundisect)[6];
|
|
|
|
int *semibound;
|
|
|
|
int *tag;
|
|
|
|
float *phi, *totalphi;
|
|
|
|
|
|
|
|
/* mesh stuff */
|
|
|
|
int *inside;
|
|
|
|
float *weights;
|
|
|
|
MDefBindInfluence **dyngrid;
|
|
|
|
float cagemat[4][4];
|
|
|
|
|
|
|
|
/* direct solver */
|
|
|
|
int *varidx;
|
2012-10-04 21:40:10 +00:00
|
|
|
|
|
|
|
BVHTree *bvhtree;
|
|
|
|
BVHTreeFromMesh bvhdata;
|
2009-01-05 15:19:31 +00:00
|
|
|
} MeshDeformBind;
|
|
|
|
|
2010-06-22 15:10:57 +00:00
|
|
|
typedef struct MeshDeformIsect {
|
|
|
|
float start[3];
|
|
|
|
float vec[3];
|
2012-12-11 14:18:37 +00:00
|
|
|
float lambda;
|
2010-06-22 15:10:57 +00:00
|
|
|
|
|
|
|
void *face;
|
|
|
|
int isect;
|
|
|
|
float u, v;
|
|
|
|
|
|
|
|
} MeshDeformIsect;
|
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
/* ray intersection */
|
|
|
|
|
|
|
|
/* our own triangle intersection, so we can fully control the epsilons and
|
|
|
|
* prevent corner case from going wrong*/
|
2012-10-05 01:34:47 +00:00
|
|
|
static int meshdeform_tri_intersect(const float orig[3], const float end[3], const float vert0[3],
|
|
|
|
const float vert1[3], const float vert2[3],
|
|
|
|
float r_isectco[3], float r_uvw[3])
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
|
2012-04-29 15:47:02 +00:00
|
|
|
float det, inv_det, u, v, dir[3], isectdir[3];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
sub_v3_v3v3(dir, end, orig);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* find vectors for two edges sharing vert0 */
|
2009-11-28 13:33:17 +00:00
|
|
|
sub_v3_v3v3(edge1, vert1, vert0);
|
|
|
|
sub_v3_v3v3(edge2, vert2, vert0);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* begin calculating determinant - also used to calculate U parameter */
|
2009-11-10 20:43:45 +00:00
|
|
|
cross_v3_v3v3(pvec, dir, edge2);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* if determinant is near zero, ray lies in plane of triangle */
|
2011-09-11 02:50:01 +00:00
|
|
|
det = dot_v3v3(edge1, pvec);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
if (UNLIKELY(det == 0.0f)) {
|
2011-04-21 15:53:30 +00:00
|
|
|
return 0;
|
2012-10-05 01:34:47 +00:00
|
|
|
}
|
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
inv_det = 1.0f / det;
|
|
|
|
|
|
|
|
/* calculate distance from vert0 to ray origin */
|
2009-11-28 13:33:17 +00:00
|
|
|
sub_v3_v3v3(tvec, orig, vert0);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* calculate U parameter and test bounds */
|
2011-09-11 02:50:01 +00:00
|
|
|
u = dot_v3v3(tvec, pvec) * inv_det;
|
2012-05-08 20:18:33 +00:00
|
|
|
if (u < -EPSILON || u > 1.0f + EPSILON)
|
2011-04-21 15:53:30 +00:00
|
|
|
return 0;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* prepare to test V parameter */
|
2009-11-10 20:43:45 +00:00
|
|
|
cross_v3_v3v3(qvec, tvec, edge1);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* calculate V parameter and test bounds */
|
2011-09-11 02:50:01 +00:00
|
|
|
v = dot_v3v3(dir, qvec) * inv_det;
|
2012-05-08 20:18:33 +00:00
|
|
|
if (v < -EPSILON || u + v > 1.0f + EPSILON)
|
2011-04-21 15:53:30 +00:00
|
|
|
return 0;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
r_isectco[0] = (1.0f - u - v) * vert0[0] + u * vert1[0] + v * vert2[0];
|
|
|
|
r_isectco[1] = (1.0f - u - v) * vert0[1] + u * vert1[1] + v * vert2[1];
|
|
|
|
r_isectco[2] = (1.0f - u - v) * vert0[2] + u * vert1[2] + v * vert2[2];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
r_uvw[0] = 1.0f - u - v;
|
|
|
|
r_uvw[1] = u;
|
|
|
|
r_uvw[2] = v;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* check if it is within the length of the line segment */
|
2012-10-05 01:34:47 +00:00
|
|
|
sub_v3_v3v3(isectdir, r_isectco, orig);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dot_v3v3(dir, isectdir) < -EPSILON)
|
2009-01-05 15:19:31 +00:00
|
|
|
return 0;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dot_v3v3(dir, dir) + EPSILON < dot_v3v3(isectdir, isectdir))
|
2009-01-05 15:19:31 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
|
2012-10-21 07:58:38 +00:00
|
|
|
{
|
2012-10-04 21:40:10 +00:00
|
|
|
void **data = userdata;
|
|
|
|
MeshDeformBind *mdb = data[1];
|
|
|
|
MFace *mface = data[0], *mf;
|
|
|
|
MeshDeformIsect *isec = data[2];
|
|
|
|
float no[3], co[3], end[3], uvw[3], dist, face[4][3];
|
|
|
|
|
|
|
|
mf = mface + index;
|
|
|
|
|
|
|
|
copy_v3_v3(face[0], mdb->cagecos[mf->v1]);
|
|
|
|
copy_v3_v3(face[1], mdb->cagecos[mf->v2]);
|
|
|
|
copy_v3_v3(face[2], mdb->cagecos[mf->v3]);
|
|
|
|
if (mf->v4)
|
|
|
|
copy_v3_v3(face[3], mdb->cagecos[mf->v4]);
|
|
|
|
|
2012-10-21 07:58:38 +00:00
|
|
|
add_v3_v3v3(end, isec->start, isec->vec);
|
2012-10-04 21:40:10 +00:00
|
|
|
|
|
|
|
if (!meshdeform_tri_intersect(ray->origin, end, face[0], face[1], face[2], co, uvw))
|
|
|
|
if (!mf->v4 || !meshdeform_tri_intersect(ray->origin, end, face[0], face[2], face[3], co, uvw))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!mf->v4)
|
|
|
|
normal_tri_v3(no, face[0], face[1], face[2]);
|
|
|
|
else
|
|
|
|
normal_quad_v3(no, face[0], face[1], face[2], face[3]);
|
|
|
|
|
2012-10-10 23:44:07 +00:00
|
|
|
dist = len_v3v3(ray->origin, co) / len_v3(isec->vec);
|
2012-10-04 21:40:10 +00:00
|
|
|
if (dist < hit->dist) {
|
|
|
|
hit->index = index;
|
|
|
|
hit->dist = dist;
|
|
|
|
copy_v3_v3(hit->co, co);
|
|
|
|
|
2012-11-03 18:23:30 +00:00
|
|
|
isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
|
2012-12-11 14:18:37 +00:00
|
|
|
isec->lambda = dist;
|
2012-10-04 21:40:10 +00:00
|
|
|
isec->face = mf;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
2012-10-04 21:40:10 +00:00
|
|
|
BVHTreeRayHit hit;
|
2012-10-05 01:34:47 +00:00
|
|
|
MeshDeformIsect isect_mdef;
|
2009-01-05 15:19:31 +00:00
|
|
|
float (*cagecos)[3];
|
2012-10-05 01:34:47 +00:00
|
|
|
void *data[3] = {mdb->cagedm->getTessFaceArray(mdb->cagedm), mdb, &isect_mdef};
|
2012-10-04 21:40:10 +00:00
|
|
|
MFace *mface1 = data[0], *mface;
|
2009-10-22 23:22:05 +00:00
|
|
|
float vert[4][3], len, end[3];
|
2012-05-08 20:18:33 +00:00
|
|
|
static float epsilon[3] = {0, 0, 0}; //1e-4, 1e-4, 1e-4};
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* setup isec */
|
2012-10-05 01:34:47 +00:00
|
|
|
memset(&isect_mdef, 0, sizeof(isect_mdef));
|
2012-12-11 14:18:37 +00:00
|
|
|
isect_mdef.lambda = 1e10f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
add_v3_v3v3(isect_mdef.start, co1, epsilon);
|
2011-11-06 16:34:44 +00:00
|
|
|
add_v3_v3v3(end, co2, epsilon);
|
2012-10-05 01:34:47 +00:00
|
|
|
sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-04 21:40:10 +00:00
|
|
|
hit.index = -1;
|
|
|
|
hit.dist = FLT_MAX;
|
2012-10-07 14:00:18 +00:00
|
|
|
if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, isect_mdef.vec,
|
|
|
|
0.0, &hit, harmonic_ray_callback, data) != -1)
|
|
|
|
{
|
2012-12-11 14:18:37 +00:00
|
|
|
len = isect_mdef.lambda;
|
2012-10-05 01:34:47 +00:00
|
|
|
isect_mdef.face = mface = mface1 + hit.index;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* create MDefBoundIsect */
|
2012-05-08 20:18:33 +00:00
|
|
|
isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect));
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute intersection coordinate */
|
2012-10-05 01:34:47 +00:00
|
|
|
isect->co[0] = co1[0] + isect_mdef.vec[0] * len;
|
|
|
|
isect->co[1] = co1[1] + isect_mdef.vec[1] * len;
|
|
|
|
isect->co[2] = co1[2] + isect_mdef.vec[2] * len;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
isect->len = len_v3v3(co1, isect->co);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect->len < MESHDEFORM_LEN_THRESHOLD)
|
2012-05-08 20:18:33 +00:00
|
|
|
isect->len = MESHDEFORM_LEN_THRESHOLD;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
isect->v[0] = mface->v1;
|
|
|
|
isect->v[1] = mface->v2;
|
|
|
|
isect->v[2] = mface->v3;
|
|
|
|
isect->v[3] = mface->v4;
|
|
|
|
isect->nvert = (mface->v4) ? 4 : 3;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-10-05 01:34:47 +00:00
|
|
|
isect->facing = isect_mdef.isect;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute mean value coordinates for interpolation */
|
2012-05-08 20:18:33 +00:00
|
|
|
cagecos = mdb->cagecos;
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(vert[0], cagecos[mface->v1]);
|
|
|
|
copy_v3_v3(vert[1], cagecos[mface->v2]);
|
|
|
|
copy_v3_v3(vert[2], cagecos[mface->v3]);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]);
|
2012-04-29 17:11:40 +00:00
|
|
|
interp_weights_poly_v3(isect->uvw, vert, isect->nvert, isect->co);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
return isect;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
|
|
|
float outside[3], start[3], dir[3];
|
2011-01-09 01:17:56 +00:00
|
|
|
int i;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f) * MESHDEFORM_OFFSET[i][0];
|
|
|
|
outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f) * MESHDEFORM_OFFSET[i][1];
|
|
|
|
outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f) * MESHDEFORM_OFFSET[i][2];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(start, co);
|
|
|
|
sub_v3_v3v3(dir, outside, start);
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(dir);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
isect = meshdeform_ray_tree_intersect(mdb, start, outside);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect && !isect->facing)
|
2009-01-05 15:19:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* solving */
|
|
|
|
|
|
|
|
static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
int size = mdb->size;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
x += MESHDEFORM_OFFSET[n][0];
|
|
|
|
y += MESHDEFORM_OFFSET[n][1];
|
|
|
|
z += MESHDEFORM_OFFSET[n][2];
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (x < 0 || x >= mdb->size)
|
2009-01-05 15:19:31 +00:00
|
|
|
return -1;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (y < 0 || y >= mdb->size)
|
2009-01-05 15:19:31 +00:00
|
|
|
return -1;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (z < 0 || z >= mdb->size)
|
2009-01-05 15:19:31 +00:00
|
|
|
return -1;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
return x + y * size + z * size * size;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
|
|
|
|
{
|
|
|
|
x += MESHDEFORM_OFFSET[n][0];
|
|
|
|
y += MESHDEFORM_OFFSET[n][1];
|
|
|
|
z += MESHDEFORM_OFFSET[n][2];
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
center[0] = mdb->min[0] + x * mdb->width[0] + mdb->halfwidth[0];
|
|
|
|
center[1] = mdb->min[1] + y * mdb->width[1] + mdb->halfwidth[1];
|
|
|
|
center[2] = mdb->min[2] + z * mdb->width[2] + mdb->halfwidth[2];
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
|
|
|
float center[3], ncenter[3];
|
|
|
|
int i, a;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
a = meshdeform_index(mdb, x, y, z, 0);
|
2009-01-05 15:19:31 +00:00
|
|
|
meshdeform_cell_center(mdb, x, y, z, 0, center);
|
|
|
|
|
|
|
|
/* check each outgoing edge for intersection */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 1; i <= 6; i++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (meshdeform_index(mdb, x, y, z, i) == -1)
|
2009-01-05 15:19:31 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
meshdeform_cell_center(mdb, x, y, z, i, ncenter);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
isect = meshdeform_ray_tree_intersect(mdb, center, ncenter);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect) {
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->boundisect[a][i - 1] = isect;
|
|
|
|
mdb->tag[a] = MESHDEFORM_TAG_BOUNDARY;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
int *stack, *tag = mdb->tag;
|
|
|
|
int a, b, i, xyz[3], stacksize, size = mdb->size;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
stack = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindStack");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* we know lower left corner is EXTERIOR because of padding */
|
2012-05-08 20:18:33 +00:00
|
|
|
tag[0] = MESHDEFORM_TAG_EXTERIOR;
|
|
|
|
stack[0] = 0;
|
|
|
|
stacksize = 1;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* floodfill exterior tag */
|
2012-03-24 06:38:07 +00:00
|
|
|
while (stacksize > 0) {
|
2012-05-08 20:18:33 +00:00
|
|
|
a = stack[--stacksize];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
xyz[2] = a / (size * size);
|
|
|
|
xyz[1] = (a - xyz[2] * size * size) / size;
|
|
|
|
xyz[0] = a - xyz[1] * size - xyz[2] * size * size;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
b = meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (b != -1) {
|
|
|
|
if (tag[b] == MESHDEFORM_TAG_UNTYPED ||
|
2012-05-20 19:49:27 +00:00
|
|
|
(tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i - 1]))
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
tag[b] = MESHDEFORM_TAG_EXTERIOR;
|
|
|
|
stack[stacksize++] = b;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* other cells are interior */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < size * size * size; a++)
|
|
|
|
if (tag[a] == MESHDEFORM_TAG_UNTYPED)
|
|
|
|
tag[a] = MESHDEFORM_TAG_INTERIOR;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
int tb, ti, te, ts;
|
2012-05-08 20:18:33 +00:00
|
|
|
tb = ti = te = ts = 0;
|
|
|
|
for (a = 0; a < size * size * size; a++)
|
|
|
|
if (tag[a] == MESHDEFORM_TAG_BOUNDARY)
|
2009-01-05 15:19:31 +00:00
|
|
|
tb++;
|
2012-05-08 20:18:33 +00:00
|
|
|
else if (tag[a] == MESHDEFORM_TAG_INTERIOR)
|
2009-01-05 15:19:31 +00:00
|
|
|
ti++;
|
2012-05-08 20:18:33 +00:00
|
|
|
else if (tag[a] == MESHDEFORM_TAG_EXTERIOR) {
|
2009-01-05 15:19:31 +00:00
|
|
|
te++;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->semibound[a])
|
2009-01-05 15:19:31 +00:00
|
|
|
ts++;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
MEM_freeN(stack);
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static float meshdeform_boundary_phi(MeshDeformBind *UNUSED(mdb), MDefBoundIsect *isect, int cagevert)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
int a;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < isect->nvert; a++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (isect->v[a] == cagevert)
|
2009-01-05 15:19:31 +00:00
|
|
|
return isect->uvw[a];
|
|
|
|
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static float meshdeform_interp_w(MeshDeformBind *mdb, float *gridvec, float *UNUSED(vec), int UNUSED(cagevert))
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
float dvec[3], ivec[3], wx, wy, wz, result = 0.0f;
|
|
|
|
float weight, totweight = 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
int i, a, x, y, z;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
ivec[i] = (int)gridvec[i];
|
|
|
|
dvec[i] = gridvec[i] - ivec[i];
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (i & 1) { x = ivec[0] + 1; wx = dvec[0]; }
|
|
|
|
else { x = ivec[0]; wx = 1.0f - dvec[0]; }
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
if (i & 2) { y = ivec[1] + 1; wy = dvec[1]; }
|
|
|
|
else { y = ivec[1]; wy = 1.0f - dvec[1]; }
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
if (i & 4) { z = ivec[2] + 1; wz = dvec[2]; }
|
|
|
|
else { z = ivec[2]; wz = 1.0f - dvec[2]; }
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
CLAMP(x, 0, mdb->size - 1);
|
|
|
|
CLAMP(y, 0, mdb->size - 1);
|
|
|
|
CLAMP(z, 0, mdb->size - 1);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
a = meshdeform_index(mdb, x, y, z, 0);
|
|
|
|
weight = wx * wy * wz;
|
|
|
|
result += weight * mdb->phi[a];
|
2009-01-05 15:19:31 +00:00
|
|
|
totweight += weight;
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totweight > 0.0f)
|
2009-01-05 15:19:31 +00:00
|
|
|
result /= totweight;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
|
|
|
|
{
|
|
|
|
int i, a;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
a = meshdeform_index(mdb, x, y, z, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR)
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 1; i <= 6; i++)
|
|
|
|
if (mdb->boundisect[a][i - 1])
|
|
|
|
mdb->semibound[a] = 1;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
|
|
|
|
{
|
2012-05-08 20:18:33 +00:00
|
|
|
float weight, totweight = 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
int i, a;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
a = meshdeform_index(mdb, x, y, z, 0);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-01 12:20:18 +00:00
|
|
|
/* count weight for neighbor cells */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (i = 1; i <= 6; i++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (meshdeform_index(mdb, x, y, z, i) == -1)
|
2009-01-05 15:19:31 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
if (mdb->boundisect[a][i - 1])
|
|
|
|
weight = 1.0f / mdb->boundisect[a][i - 1]->len;
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (!mdb->semibound[a])
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = 1.0f / mdb->width[0];
|
2009-01-05 15:19:31 +00:00
|
|
|
else
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
totweight += weight;
|
|
|
|
}
|
|
|
|
|
|
|
|
return totweight;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
|
|
|
float weight, totweight;
|
|
|
|
int i, a, acenter;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
acenter = meshdeform_index(mdb, x, y, z, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
|
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
a = meshdeform_index(mdb, x, y, z, i);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
|
2009-01-05 15:19:31 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
isect = mdb->boundisect[acenter][i - 1];
|
2009-01-05 15:19:31 +00:00
|
|
|
if (!isect) {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = (1.0f / mdb->width[0]) / totweight;
|
2009-01-05 15:19:31 +00:00
|
|
|
nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[a], -weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
|
|
|
float rhs, weight, totweight;
|
|
|
|
int i, a, acenter;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
acenter = meshdeform_index(mdb, x, y, z, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
|
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
a = meshdeform_index(mdb, x, y, z, i);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (a == -1)
|
2009-01-05 15:19:31 +00:00
|
|
|
continue;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
isect = mdb->boundisect[acenter][i - 1];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
if (isect) {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = (1.0f / isect->len) / totweight;
|
|
|
|
rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
|
2009-01-05 15:19:31 +00:00
|
|
|
nlRightHandSideAdd(0, mdb->varidx[acenter], rhs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
|
|
|
|
{
|
|
|
|
MDefBoundIsect *isect;
|
|
|
|
float rhs, weight, totweight;
|
|
|
|
int i, a;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
a = meshdeform_index(mdb, x, y, z, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!mdb->semibound[a])
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->phi[a] = 0.0f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
|
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
isect = mdb->boundisect[a][i - 1];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
if (isect) {
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = (1.0f / isect->len) / totweight;
|
|
|
|
rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
|
2009-01-05 15:19:31 +00:00
|
|
|
mdb->phi[a] += rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int UNUSED(cagevert))
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
float phi, totweight;
|
|
|
|
int i, a, acenter;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
acenter = meshdeform_index(mdb, x, y, z, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter])
|
2009-01-05 15:19:31 +00:00
|
|
|
return;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
phi = 0.0f;
|
|
|
|
totweight = 0.0f;
|
|
|
|
for (i = 1; i <= 6; i++) {
|
|
|
|
a = meshdeform_index(mdb, x, y, z, i);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (a != -1 && mdb->semibound[a]) {
|
2009-01-05 15:19:31 +00:00
|
|
|
phi += mdb->phi[a];
|
|
|
|
totweight += 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totweight != 0.0f)
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->phi[acenter] = phi / totweight;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2011-12-02 21:10:29 +00:00
|
|
|
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
NLContext *context;
|
|
|
|
float vec[3], gridvec[3];
|
|
|
|
int a, b, x, y, z, totvar;
|
2012-01-11 12:33:51 +00:00
|
|
|
char message[256];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* setup variable indices */
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx");
|
|
|
|
for (a = 0, totvar = 0; a < mdb->size3; a++)
|
|
|
|
mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totvar == 0) {
|
2009-01-05 15:19:31 +00:00
|
|
|
MEM_freeN(mdb->varidx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
progress_bar(0, "Starting mesh deform solve");
|
|
|
|
|
|
|
|
/* setup opennl solver */
|
|
|
|
nlNewContext();
|
2012-05-08 20:18:33 +00:00
|
|
|
context = nlGetCurrent();
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
nlSolverParameteri(NL_NB_VARIABLES, totvar);
|
|
|
|
nlSolverParameteri(NL_NB_ROWS, totvar);
|
|
|
|
nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1);
|
|
|
|
|
|
|
|
nlBegin(NL_SYSTEM);
|
|
|
|
nlBegin(NL_MATRIX);
|
|
|
|
|
|
|
|
/* build matrix */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-01-05 15:19:31 +00:00
|
|
|
meshdeform_matrix_add_cell(mdb, x, y, z);
|
|
|
|
|
|
|
|
/* solve for each cage vert */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < mdb->totcagevert; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (a != 0) {
|
2009-01-05 15:19:31 +00:00
|
|
|
nlBegin(NL_SYSTEM);
|
|
|
|
nlBegin(NL_MATRIX);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill in right hand side and solve */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-01-05 15:19:31 +00:00
|
|
|
meshdeform_matrix_add_rhs(mdb, x, y, z, a);
|
|
|
|
|
|
|
|
nlEnd(NL_MATRIX);
|
|
|
|
nlEnd(NL_SYSTEM);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
nlPrintMatrix();
|
|
|
|
#endif
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (nlSolveAdvanced(NULL, NL_TRUE)) {
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-01-05 15:19:31 +00:00
|
|
|
meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-01-05 15:19:31 +00:00
|
|
|
meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (b = 0; b < mdb->size3; b++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->phi[b] = nlGetVariable(0, mdb->varidx[b]);
|
2009-01-05 15:19:31 +00:00
|
|
|
mdb->totalphi[b] += mdb->phi[b];
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->weights) {
|
2009-01-05 15:19:31 +00:00
|
|
|
/* static bind : compute weights for each vertex */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (b = 0; b < mdb->totvert; b++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->inside[b]) {
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(vec, mdb->vertexcos[b]);
|
2012-05-08 20:18:33 +00:00
|
|
|
gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0];
|
|
|
|
gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1];
|
|
|
|
gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MDefBindInfluence *inf;
|
|
|
|
|
|
|
|
/* dynamic bind */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (b = 0; b < mdb->size3; b++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
|
2012-05-08 20:18:33 +00:00
|
|
|
inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
|
|
|
|
inf->vertex = a;
|
|
|
|
inf->weight = mdb->phi[b];
|
|
|
|
inf->next = mdb->dyngrid[b];
|
|
|
|
mdb->dyngrid[b] = inf;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-10-27 11:12:09 +00:00
|
|
|
modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
|
2011-12-02 21:10:29 +00:00
|
|
|
error("Mesh Deform: failed to find bind solution.");
|
2009-01-05 15:19:31 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
BLI_snprintf(message, sizeof(message), "Mesh deform solve %d / %d |||", a + 1, mdb->totcagevert);
|
|
|
|
progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* sanity check */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (b = 0; b < mdb->size3; b++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
|
|
|
|
if (fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
|
2009-01-05 15:19:31 +00:00
|
|
|
printf("totalphi deficiency [%s|%d] %d: %.10f\n",
|
2012-05-08 20:18:33 +00:00
|
|
|
(mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
|
2009-01-05 15:19:31 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* free */
|
|
|
|
MEM_freeN(mdb->varidx);
|
|
|
|
|
|
|
|
nlDeleteContext(context);
|
|
|
|
}
|
|
|
|
|
2010-10-16 14:32:17 +00:00
|
|
|
static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb)
|
2009-01-05 15:19:31 +00:00
|
|
|
{
|
|
|
|
MDefBindInfluence *inf;
|
|
|
|
MDefInfluence *mdinf;
|
|
|
|
MDefCell *cell;
|
|
|
|
float center[3], vec[3], maxwidth, totweight;
|
|
|
|
int a, b, x, y, z, totinside, offset;
|
|
|
|
|
|
|
|
/* compute bounding box of the cage mesh */
|
2009-11-28 13:33:17 +00:00
|
|
|
INIT_MINMAX(mdb->min, mdb->max);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < mdb->totcagevert; a++)
|
2012-05-13 11:05:52 +00:00
|
|
|
minmax_v3v3_v3(mdb->min, mdb->max, mdb->cagecos[a]);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* allocate memory */
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->size = (2 << (mmd->gridsize - 1)) + 2;
|
|
|
|
mdb->size3 = mdb->size * mdb->size * mdb->size;
|
|
|
|
mdb->tag = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindTag");
|
|
|
|
mdb->phi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindPhi");
|
|
|
|
mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
|
|
|
|
mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
|
|
|
|
mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
|
2013-01-08 01:48:14 +00:00
|
|
|
mdb->bvhtree = bvhtree_from_mesh_faces(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6);
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->dyngrid = MEM_callocN(sizeof(MDefBindInfluence *) * mdb->size3, "MDefDynGrid");
|
2009-01-05 15:19:31 +00:00
|
|
|
else
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
|
2009-11-28 13:33:17 +00:00
|
|
|
BLI_memarena_use_calloc(mdb->memarena);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* make bounding box equal size in all directions, add padding, and compute
|
|
|
|
* width of the cells */
|
|
|
|
maxwidth = -1.0f;
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < 3; a++)
|
|
|
|
if (mdb->max[a] - mdb->min[a] > maxwidth)
|
|
|
|
maxwidth = mdb->max[a] - mdb->min[a];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < 3; a++) {
|
|
|
|
center[a] = (mdb->min[a] + mdb->max[a]) * 0.5f;
|
|
|
|
mdb->min[a] = center[a] - maxwidth * 0.5f;
|
|
|
|
mdb->max[a] = center[a] + maxwidth * 0.5f;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->width[a] = (mdb->max[a] - mdb->min[a]) / (mdb->size - 4);
|
|
|
|
mdb->min[a] -= 2.1f * mdb->width[a];
|
|
|
|
mdb->max[a] += 2.1f * mdb->width[a];
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->width[a] = (mdb->max[a] - mdb->min[a]) / mdb->size;
|
|
|
|
mdb->halfwidth[a] = mdb->width[a] * 0.5f;
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
progress_bar(0, "Setting up mesh deform system");
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
totinside = 0;
|
|
|
|
for (a = 0; a < mdb->totvert; a++) {
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(vec, mdb->vertexcos[a]);
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->inside[a] = meshdeform_inside_cage(mdb, vec);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mdb->inside[a])
|
2009-01-05 15:19:31 +00:00
|
|
|
totinside++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free temporary MDefBoundIsects */
|
2009-11-28 13:33:17 +00:00
|
|
|
BLI_memarena_free(mdb->memarena);
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* start with all cells untyped */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < mdb->size3; a++)
|
|
|
|
mdb->tag[a] = MESHDEFORM_TAG_UNTYPED;
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* detect intersections and tag boundary cells */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-11-28 13:33:17 +00:00
|
|
|
meshdeform_add_intersections(mdb, x, y, z);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* compute exterior and interior tags */
|
2009-11-28 13:33:17 +00:00
|
|
|
meshdeform_bind_floodfill(mdb);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (z = 0; z < mdb->size; z++)
|
|
|
|
for (y = 0; y < mdb->size; y++)
|
|
|
|
for (x = 0; x < mdb->size; x++)
|
2009-11-28 13:33:17 +00:00
|
|
|
meshdeform_check_semibound(mdb, x, y, z);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* solve */
|
2011-12-02 21:10:29 +00:00
|
|
|
meshdeform_matrix_solve(mmd, mdb);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* assign results */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->totinfluence = 0;
|
|
|
|
for (a = 0; a < mdb->size3; a++)
|
|
|
|
for (inf = mdb->dyngrid[a]; inf; inf = inf->next)
|
2009-01-05 15:19:31 +00:00
|
|
|
mmd->totinfluence++;
|
|
|
|
|
|
|
|
/* convert MDefBindInfluences to smaller MDefInfluences */
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->dyngrid = MEM_callocN(sizeof(MDefCell) * mdb->size3, "MDefDynGrid");
|
|
|
|
mmd->dyninfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefInfluence");
|
|
|
|
offset = 0;
|
|
|
|
for (a = 0; a < mdb->size3; a++) {
|
|
|
|
cell = &mmd->dyngrid[a];
|
|
|
|
cell->offset = offset;
|
|
|
|
|
|
|
|
totweight = 0.0f;
|
|
|
|
mdinf = mmd->dyninfluences + cell->offset;
|
|
|
|
for (inf = mdb->dyngrid[a]; inf; inf = inf->next, mdinf++) {
|
|
|
|
mdinf->weight = inf->weight;
|
|
|
|
mdinf->vertex = inf->vertex;
|
2009-01-05 15:19:31 +00:00
|
|
|
totweight += mdinf->weight;
|
|
|
|
cell->totinfluence++;
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totweight > 0.0f) {
|
2012-05-08 20:18:33 +00:00
|
|
|
mdinf = mmd->dyninfluences + cell->offset;
|
|
|
|
for (b = 0; b < cell->totinfluence; b++, mdinf++)
|
2009-01-05 15:19:31 +00:00
|
|
|
mdinf->weight /= totweight;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += cell->totinfluence;
|
|
|
|
}
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->dynverts = mdb->inside;
|
|
|
|
mmd->dyngridsize = mdb->size;
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(mmd->dyncellmin, mdb->min);
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->dyncellwidth = mdb->width[0];
|
2009-11-28 13:33:17 +00:00
|
|
|
MEM_freeN(mdb->dyngrid);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->bindweights = mdb->weights;
|
2009-11-28 13:33:17 +00:00
|
|
|
MEM_freeN(mdb->inside);
|
2009-01-05 15:19:31 +00:00
|
|
|
}
|
|
|
|
|
2009-11-28 13:33:17 +00:00
|
|
|
MEM_freeN(mdb->tag);
|
|
|
|
MEM_freeN(mdb->phi);
|
|
|
|
MEM_freeN(mdb->totalphi);
|
|
|
|
MEM_freeN(mdb->boundisect);
|
|
|
|
MEM_freeN(mdb->semibound);
|
|
|
|
BLI_memarena_free(mdb->memarena);
|
2012-10-04 21:40:10 +00:00
|
|
|
free_bvhtree_from_mesh(&mdb->bvhdata);
|
2009-11-28 13:33:17 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 11:39:40 +00:00
|
|
|
#if 0
|
2009-11-28 13:33:17 +00:00
|
|
|
static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb)
|
|
|
|
{
|
|
|
|
LaplacianSystem *sys;
|
2012-05-08 20:18:33 +00:00
|
|
|
MFace *mface = dm->getTessFaceArray(dm), *mf;
|
|
|
|
int totvert = dm->getNumVerts(dm);
|
|
|
|
int totface = dm->getNumTessFaces(dm);
|
2009-11-28 13:33:17 +00:00
|
|
|
float solution, weight;
|
|
|
|
int a, tottri, j, thrownerror = 0;
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");
|
2009-11-28 13:33:17 +00:00
|
|
|
|
|
|
|
/* count triangles */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (tottri = 0, a = 0, mf = mface; a < totface; a++, mf++) {
|
2009-11-28 13:33:17 +00:00
|
|
|
tottri++;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mf->v4) tottri++;
|
2009-11-28 13:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* create laplacian */
|
|
|
|
sys = laplacian_system_construct_begin(totvert, tottri, 1);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.mface = mface;
|
|
|
|
sys->heat.totface = totface;
|
|
|
|
sys->heat.totvert = totvert;
|
|
|
|
sys->heat.verts = mdb->vertexcos;
|
2009-11-28 13:33:17 +00:00
|
|
|
sys->heat.source = mdb->cagecos;
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.numsource = mdb->totcagevert;
|
2009-11-28 13:33:17 +00:00
|
|
|
|
|
|
|
heat_ray_tree_create(sys);
|
|
|
|
heat_laplacian_create(sys);
|
|
|
|
|
|
|
|
laplacian_system_construct_end(sys);
|
|
|
|
|
|
|
|
/* compute weights per bone */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (j = 0; j < mdb->totcagevert; j++) {
|
2009-11-28 13:33:17 +00:00
|
|
|
/* fill right hand side */
|
|
|
|
laplacian_begin_solve(sys, -1);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totvert; a++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (heat_source_closest(sys, a, j))
|
2009-11-28 13:33:17 +00:00
|
|
|
laplacian_add_right_hand_side(sys, a,
|
2012-05-08 20:18:33 +00:00
|
|
|
sys->heat.H[a] * sys->heat.p[a]);
|
2009-11-28 13:33:17 +00:00
|
|
|
|
|
|
|
/* solve */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (laplacian_system_solve(sys)) {
|
2009-11-28 13:33:17 +00:00
|
|
|
/* load solution into vertex groups */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < totvert; a++) {
|
|
|
|
solution = laplacian_system_get_solution(a);
|
2009-11-28 13:33:17 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
weight = heat_limit_weight(solution);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight > 0.0f)
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb->weights[a * mdb->totcagevert + j] = weight;
|
2009-11-28 13:33:17 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (!thrownerror) {
|
2009-11-28 13:33:17 +00:00
|
|
|
error("Mesh Deform Heat Weighting:"
|
2012-05-08 20:18:33 +00:00
|
|
|
" failed to find solution for one or more vertices");
|
|
|
|
thrownerror = 1;
|
2009-11-28 13:33:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free */
|
|
|
|
heat_system_free(sys);
|
|
|
|
laplacian_system_delete(sys);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->bindweights = mdb->weights;
|
2009-11-28 13:33:17 +00:00
|
|
|
}
|
2010-04-02 11:39:40 +00:00
|
|
|
#endif
|
2009-11-28 13:33:17 +00:00
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[4][4])
|
2009-11-28 13:33:17 +00:00
|
|
|
{
|
|
|
|
MeshDeformBind mdb;
|
|
|
|
MVert *mvert;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
waitcursor(1);
|
|
|
|
start_progress_bar();
|
|
|
|
|
|
|
|
memset(&mdb, 0, sizeof(MeshDeformBind));
|
|
|
|
|
|
|
|
/* get mesh and cage mesh */
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos");
|
|
|
|
mdb.totvert = totvert;
|
2009-11-28 13:33:17 +00:00
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mdb.cagedm = mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH);
|
|
|
|
mdb.totcagevert = mdb.cagedm->getNumVerts(mdb.cagedm);
|
|
|
|
mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos");
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_m4_m4(mdb.cagemat, cagemat);
|
|
|
|
|
2012-05-08 20:18:33 +00:00
|
|
|
mvert = mdb.cagedm->getVertArray(mdb.cagedm);
|
|
|
|
for (a = 0; a < mdb.totcagevert; a++)
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_v3_v3(mdb.cagecos[a], mvert[a].co);
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < mdb.totvert; a++)
|
|
|
|
mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
|
2009-11-28 13:33:17 +00:00
|
|
|
|
|
|
|
/* solve */
|
2010-04-02 11:39:40 +00:00
|
|
|
#if 0
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mmd->mode == MOD_MDEF_VOLUME)
|
2009-11-28 13:33:17 +00:00
|
|
|
harmonic_coordinates_bind(scene, mmd, &mdb);
|
|
|
|
else
|
|
|
|
heat_weighting_bind(scene, dm, mmd, &mdb);
|
2010-04-02 11:39:40 +00:00
|
|
|
#else
|
|
|
|
harmonic_coordinates_bind(scene, mmd, &mdb);
|
|
|
|
#endif
|
2009-11-28 13:33:17 +00:00
|
|
|
|
|
|
|
/* assign bind variables */
|
2012-05-08 20:18:33 +00:00
|
|
|
mmd->bindcagecos = (float *)mdb.cagecos;
|
|
|
|
mmd->totvert = mdb.totvert;
|
|
|
|
mmd->totcagevert = mdb.totcagevert;
|
2009-11-28 13:33:17 +00:00
|
|
|
copy_m4_m4(mmd->bindmat, mmd->object->obmat);
|
|
|
|
|
2010-04-23 11:19:06 +00:00
|
|
|
/* transform bindcagecos to world space */
|
2012-05-08 20:18:33 +00:00
|
|
|
for (a = 0; a < mdb.totcagevert; a++)
|
|
|
|
mul_m4_v3(mmd->object->obmat, mmd->bindcagecos + a * 3);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
|
|
|
/* free */
|
|
|
|
mdb.cagedm->release(mdb.cagedm);
|
2009-11-28 13:33:17 +00:00
|
|
|
MEM_freeN(mdb.vertexcos);
|
2009-01-05 15:19:31 +00:00
|
|
|
|
2010-04-23 11:19:06 +00:00
|
|
|
/* compact weights */
|
2012-05-08 20:18:33 +00:00
|
|
|
modifier_mdef_compact_influences((ModifierData *)mmd);
|
2010-04-23 11:19:06 +00:00
|
|
|
|
2009-01-05 15:19:31 +00:00
|
|
|
end_progress_bar();
|
|
|
|
waitcursor(0);
|
|
|
|
}
|
|
|
|
|