2014-09-05 12:48:49 +02: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,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) Blender Foundation
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Lukas Toenne
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/blenkernel/intern/implicit_eigen.cpp
|
2014-09-13 14:36:46 +02:00
|
|
|
* \ingroup bph
|
2014-09-05 12:48:49 +02:00
|
|
|
*/
|
|
|
|
|
2014-09-10 14:25:57 +02:00
|
|
|
#include "implicit.h"
|
|
|
|
|
|
|
|
#ifdef IMPLICIT_SOLVER_EIGEN
|
2014-09-05 12:48:49 +02:00
|
|
|
|
2014-09-08 19:03:39 +02:00
|
|
|
//#define USE_EIGEN_CORE
|
|
|
|
#define USE_EIGEN_CONSTRAINED_CG
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
#ifdef __GNUC__
|
|
|
|
# pragma GCC diagnostic push
|
|
|
|
/* XXX suppress verbose warnings in eigen */
|
|
|
|
# pragma GCC diagnostic ignored "-Wlogical-op"
|
|
|
|
#endif
|
|
|
|
|
2014-09-11 17:49:26 +02:00
|
|
|
#ifndef IMPLICIT_ENABLE_EIGEN_DEBUG
|
|
|
|
#ifdef NDEBUG
|
|
|
|
#define IMPLICIT_NDEBUG
|
|
|
|
#endif
|
|
|
|
#define NDEBUG
|
|
|
|
#endif
|
|
|
|
|
2014-09-05 12:48:49 +02:00
|
|
|
#include <Eigen/Sparse>
|
2014-09-08 19:03:39 +02:00
|
|
|
#include <Eigen/src/Core/util/DisableStupidWarnings.h>
|
|
|
|
|
|
|
|
#ifdef USE_EIGEN_CONSTRAINED_CG
|
|
|
|
#include <intern/ConstrainedConjugateGradient.h>
|
|
|
|
#endif
|
2014-09-05 12:48:49 +02:00
|
|
|
|
2014-09-11 17:49:26 +02:00
|
|
|
#ifndef IMPLICIT_ENABLE_EIGEN_DEBUG
|
|
|
|
#ifndef IMPLICIT_NDEBUG
|
|
|
|
#undef NDEBUG
|
|
|
|
#else
|
|
|
|
#undef IMPLICIT_NDEBUG
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
#ifdef __GNUC__
|
|
|
|
# pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
|
2014-09-05 12:48:49 +02:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_object_force.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_texture_types.h"
|
|
|
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
|
|
#include "BKE_cloth.h"
|
|
|
|
#include "BKE_collision.h"
|
|
|
|
#include "BKE_effect.h"
|
|
|
|
#include "BKE_global.h"
|
2014-09-13 14:36:46 +02:00
|
|
|
|
|
|
|
#include "BPH_mass_spring.h"
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef float Scalar;
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
|
|
|
|
static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
|
|
|
|
|
|
|
/* slightly extended Eigen vector class
|
|
|
|
* with conversion to/from plain C float array
|
|
|
|
*/
|
|
|
|
class fVector : public Eigen::Vector3f {
|
|
|
|
public:
|
|
|
|
typedef float *ctype;
|
|
|
|
|
|
|
|
fVector()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
fVector(const ctype &v)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < 3; ++k)
|
|
|
|
coeffRef(k) = v[k];
|
|
|
|
}
|
|
|
|
|
|
|
|
fVector &operator = (const ctype &v)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < 3; ++k)
|
|
|
|
coeffRef(k) = v[k];
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator ctype()
|
|
|
|
{
|
|
|
|
return data();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* slightly extended Eigen matrix class
|
|
|
|
* with conversion to/from plain C float array
|
|
|
|
*/
|
|
|
|
class fMatrix : public Eigen::Matrix3f {
|
|
|
|
public:
|
|
|
|
typedef float (*ctype)[3];
|
|
|
|
|
|
|
|
fMatrix()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
fMatrix(const ctype &v)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < 3; ++k)
|
|
|
|
for (int l = 0; l < 3; ++l)
|
|
|
|
coeffRef(l, k) = v[k][l];
|
|
|
|
}
|
|
|
|
|
|
|
|
fMatrix &operator = (const ctype &v)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < 3; ++k)
|
|
|
|
for (int l = 0; l < 3; ++l)
|
|
|
|
coeffRef(l, k) = v[k][l];
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator ctype()
|
|
|
|
{
|
|
|
|
return (ctype)data();
|
|
|
|
}
|
|
|
|
};
|
2014-09-05 12:48:49 +02:00
|
|
|
|
|
|
|
typedef Eigen::VectorXf lVector;
|
|
|
|
|
|
|
|
typedef Eigen::Triplet<Scalar> Triplet;
|
|
|
|
typedef std::vector<Triplet> TripletList;
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
typedef Eigen::SparseMatrix<Scalar> lMatrix;
|
|
|
|
|
|
|
|
struct lMatrixCtor {
|
|
|
|
lMatrixCtor(int numverts) :
|
|
|
|
m_numverts(numverts)
|
|
|
|
{
|
|
|
|
/* reserve for diagonal entries */
|
|
|
|
m_trips.reserve(numverts * 9);
|
|
|
|
}
|
|
|
|
|
|
|
|
int numverts() const { return m_numverts; }
|
|
|
|
|
|
|
|
void set(int i, int j, const fMatrix &m)
|
|
|
|
{
|
|
|
|
BLI_assert(i >= 0 && i < m_numverts);
|
|
|
|
BLI_assert(j >= 0 && j < m_numverts);
|
|
|
|
i *= 3;
|
|
|
|
j *= 3;
|
|
|
|
for (int k = 0; k < 3; ++k)
|
|
|
|
for (int l = 0; l < 3; ++l)
|
|
|
|
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline lMatrix construct() const
|
|
|
|
{
|
|
|
|
lMatrix m(m_numverts, m_numverts);
|
|
|
|
m.setFromTriplets(m_trips.begin(), m_trips.end());
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const int m_numverts;
|
|
|
|
TripletList m_trips;
|
|
|
|
};
|
|
|
|
|
2014-09-08 19:03:39 +02:00
|
|
|
#ifdef USE_EIGEN_CORE
|
2014-09-05 12:48:49 +02:00
|
|
|
typedef Eigen::ConjugateGradient<lMatrix, Eigen::Lower, Eigen::DiagonalPreconditioner<Scalar> > ConjugateGradient;
|
2014-09-08 19:03:39 +02:00
|
|
|
#endif
|
|
|
|
#ifdef USE_EIGEN_CONSTRAINED_CG
|
|
|
|
typedef Eigen::ConstrainedConjugateGradient<lMatrix, Eigen::Lower, lMatrix,
|
|
|
|
Eigen::DiagonalPreconditioner<Scalar> >
|
|
|
|
ConstraintConjGrad;
|
|
|
|
#endif
|
2014-09-05 12:48:49 +02:00
|
|
|
using Eigen::ComputationInfo;
|
|
|
|
|
2014-09-05 17:07:30 +02:00
|
|
|
static void print_lvector(const lVector &v)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < v.rows(); ++i) {
|
2014-09-10 16:04:31 +02:00
|
|
|
if (i > 0 && i % 3 == 0)
|
|
|
|
printf("\n");
|
|
|
|
|
2014-09-05 17:07:30 +02:00
|
|
|
printf("%f,\n", v[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_lmatrix(const lMatrix &m)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < m.rows(); ++j) {
|
2014-09-10 16:04:31 +02:00
|
|
|
if (j > 0 && j % 3 == 0)
|
|
|
|
printf("\n");
|
|
|
|
|
2014-09-05 17:07:30 +02:00
|
|
|
for (int i = 0; i < m.cols(); ++i) {
|
2014-09-10 16:04:31 +02:00
|
|
|
if (i > 0 && i % 3 == 0)
|
|
|
|
printf(" ");
|
|
|
|
|
|
|
|
implicit_print_matrix_elem(m.coeff(j, i));
|
2014-09-05 17:07:30 +02:00
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-08 19:03:39 +02:00
|
|
|
BLI_INLINE void lMatrix_reserve_elems(lMatrix &m, int num)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
|
|
|
m.reserve(Eigen::VectorXi::Constant(m.cols(), num));
|
|
|
|
}
|
|
|
|
|
2014-09-05 17:07:30 +02:00
|
|
|
BLI_INLINE float *lVector_v3(lVector &v, int vertex)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-09-05 17:07:30 +02:00
|
|
|
return v.data() + 3 * vertex;
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-09-05 17:07:30 +02:00
|
|
|
BLI_INLINE const float *lVector_v3(const lVector &v, int vertex)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-09-05 17:07:30 +02:00
|
|
|
return v.data() + 3 * vertex;
|
|
|
|
}
|
|
|
|
|
2014-09-11 11:14:11 +02:00
|
|
|
BLI_INLINE void triplets_m3(TripletList &tlist, float m[3][3], int i, int j)
|
|
|
|
{
|
|
|
|
i *= 3;
|
|
|
|
j *= 3;
|
|
|
|
for (int l = 0; l < 3; ++l) {
|
|
|
|
for (int k = 0; k < 3; ++k) {
|
|
|
|
tlist.push_back(Triplet(i + k, j + l, m[k][l]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void triplets_m3fl(TripletList &tlist, float m[3][3], int i, int j, float factor)
|
|
|
|
{
|
|
|
|
i *= 3;
|
|
|
|
j *= 3;
|
|
|
|
for (int l = 0; l < 3; ++l) {
|
|
|
|
for (int k = 0; k < 3; ++k) {
|
|
|
|
tlist.push_back(Triplet(i + k, j + l, m[k][l] * factor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void lMatrix_add_triplets(lMatrix &r, const TripletList &tlist)
|
|
|
|
{
|
|
|
|
lMatrix t(r.rows(), r.cols());
|
|
|
|
t.setFromTriplets(tlist.begin(), tlist.end());
|
|
|
|
r += t;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void lMatrix_madd_triplets(lMatrix &r, const TripletList &tlist, float f)
|
|
|
|
{
|
|
|
|
lMatrix t(r.rows(), r.cols());
|
|
|
|
t.setFromTriplets(tlist.begin(), tlist.end());
|
|
|
|
r += f * t;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_INLINE void lMatrix_sub_triplets(lMatrix &r, const TripletList &tlist)
|
|
|
|
{
|
|
|
|
lMatrix t(r.rows(), r.cols());
|
|
|
|
t.setFromTriplets(tlist.begin(), tlist.end());
|
|
|
|
r -= t;
|
|
|
|
}
|
|
|
|
|
2014-09-08 19:03:39 +02:00
|
|
|
BLI_INLINE void outerproduct(float r[3][3], const float a[3], const float b[3])
|
|
|
|
{
|
|
|
|
mul_v3_v3fl(r[0], a, b[0]);
|
|
|
|
mul_v3_v3fl(r[1], a, b[1]);
|
|
|
|
mul_v3_v3fl(r[2], a, b[2]);
|
|
|
|
}
|
|
|
|
|
2014-09-05 12:48:49 +02:00
|
|
|
struct Implicit_Data {
|
2014-10-12 12:45:07 +02:00
|
|
|
typedef std::vector<fMatrix> fMatrixVector;
|
2014-09-11 17:53:25 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
Implicit_Data(int numverts) :
|
|
|
|
M(numverts)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
|
|
|
resize(numverts);
|
|
|
|
}
|
|
|
|
|
|
|
|
void resize(int numverts)
|
|
|
|
{
|
|
|
|
this->numverts = numverts;
|
|
|
|
int tot = 3 * numverts;
|
|
|
|
|
|
|
|
dFdV.resize(tot, tot);
|
|
|
|
dFdX.resize(tot, tot);
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
tfm.resize(numverts, I);
|
2014-09-11 17:53:25 +02:00
|
|
|
|
2014-09-05 12:48:49 +02:00
|
|
|
X.resize(tot);
|
|
|
|
Xnew.resize(tot);
|
|
|
|
V.resize(tot);
|
|
|
|
Vnew.resize(tot);
|
|
|
|
F.resize(tot);
|
|
|
|
|
|
|
|
B.resize(tot);
|
|
|
|
A.resize(tot, tot);
|
|
|
|
|
|
|
|
dV.resize(tot);
|
|
|
|
z.resize(tot);
|
|
|
|
S.resize(tot, tot);
|
|
|
|
}
|
|
|
|
|
|
|
|
int numverts;
|
|
|
|
|
|
|
|
/* inputs */
|
2014-10-12 12:45:07 +02:00
|
|
|
lMatrixCtor M; /* masses */
|
2014-09-11 14:15:00 +02:00
|
|
|
lVector F; /* forces */
|
2014-09-05 12:48:49 +02:00
|
|
|
lMatrix dFdV, dFdX; /* force jacobians */
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
fMatrixVector tfm; /* local coordinate transform */
|
2014-09-11 17:53:25 +02:00
|
|
|
|
2014-09-05 12:48:49 +02:00
|
|
|
/* motion state data */
|
|
|
|
lVector X, Xnew; /* positions */
|
|
|
|
lVector V, Vnew; /* velocities */
|
|
|
|
|
|
|
|
/* internal solver data */
|
|
|
|
lVector B; /* B for A*dV = B */
|
|
|
|
lMatrix A; /* A for A*dV = B */
|
|
|
|
|
|
|
|
lVector dV; /* velocity change (solution of A*dV = B) */
|
|
|
|
lVector z; /* target velocity in constrained directions */
|
|
|
|
lMatrix S; /* filtering matrix for constraints */
|
2014-10-12 12:45:07 +02:00
|
|
|
|
|
|
|
struct SimDebugData *debug_data;
|
2014-09-05 12:48:49 +02:00
|
|
|
};
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
/* ==== Transformation from/to root reference frames ==== */
|
2014-09-11 17:53:25 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
BLI_INLINE void world_to_root_v3(Implicit_Data *data, int index, float r[3], const float v[3])
|
2014-09-11 17:53:25 +02:00
|
|
|
{
|
|
|
|
copy_v3_v3(r, v);
|
2014-10-12 12:45:07 +02:00
|
|
|
mul_transposed_m3_v3(data->tfm[index], r);
|
2014-09-12 10:19:41 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
BLI_INLINE void root_to_world_v3(Implicit_Data *data, int index, float r[3], const float v[3])
|
2014-09-12 10:19:41 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
mul_v3_m3v3(r, data->tfm[index], v);
|
2014-09-12 10:19:41 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
BLI_INLINE void world_to_root_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
|
2014-09-12 10:19:41 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
float trot[3][3];
|
|
|
|
copy_m3_m3(trot, data->tfm[index]);
|
|
|
|
transpose_m3(trot);
|
|
|
|
mul_m3_m3m3(r, trot, m);
|
2014-09-12 10:19:41 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
BLI_INLINE void root_to_world_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
|
2014-09-12 10:19:41 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
mul_m3_m3m3(r, data->tfm[index], m);
|
2014-09-12 10:19:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ================================ */
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
bool BPH_mass_spring_solve(Implicit_Data *data, float dt, ImplicitSolverResult *result)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-09-08 19:03:39 +02:00
|
|
|
#ifdef USE_EIGEN_CORE
|
2014-09-05 12:48:49 +02:00
|
|
|
ConjugateGradient cg;
|
|
|
|
cg.setMaxIterations(100);
|
|
|
|
cg.setTolerance(0.01f);
|
|
|
|
|
|
|
|
id->A = id->M - dt * id->dFdV - dt*dt * id->dFdX;
|
|
|
|
cg.compute(id->A);
|
|
|
|
|
|
|
|
id->B = dt * id->F + dt*dt * id->dFdX * id->V;
|
|
|
|
id->dV = cg.solve(id->B);
|
|
|
|
|
|
|
|
id->Vnew = id->V + id->dV;
|
|
|
|
|
|
|
|
return cg.info() != Eigen::Success;
|
2014-09-08 19:03:39 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_EIGEN_CONSTRAINED_CG
|
|
|
|
ConstraintConjGrad cg;
|
|
|
|
cg.setMaxIterations(100);
|
|
|
|
cg.setTolerance(0.01f);
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
lMatrix M = data->M.construct();
|
|
|
|
data->A = M - dt * data->dFdV - dt*dt * data->dFdX;
|
|
|
|
cg.compute(data->A);
|
|
|
|
cg.filter() = data->S;
|
2014-09-08 19:03:39 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
data->B = dt * data->F + dt*dt * data->dFdX * data->V;
|
2014-09-10 16:04:31 +02:00
|
|
|
#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
|
|
|
|
printf("==== A ====\n");
|
|
|
|
print_lmatrix(id->A);
|
|
|
|
printf("==== z ====\n");
|
|
|
|
print_lvector(id->z);
|
|
|
|
printf("==== B ====\n");
|
|
|
|
print_lvector(id->B);
|
|
|
|
printf("==== S ====\n");
|
|
|
|
print_lmatrix(id->S);
|
|
|
|
#endif
|
2014-10-12 12:45:07 +02:00
|
|
|
data->dV = cg.solveWithGuess(data->B, data->z);
|
2014-09-10 16:04:31 +02:00
|
|
|
#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
|
|
|
|
printf("==== dV ====\n");
|
|
|
|
print_lvector(id->dV);
|
|
|
|
printf("========\n");
|
|
|
|
#endif
|
2014-09-08 19:03:39 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
data->Vnew = data->V + data->dV;
|
|
|
|
data->Xnew = data->X + data->Vnew * dt;
|
2014-09-10 18:55:15 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
switch (cg.info()) {
|
|
|
|
case Eigen::Success: result->status = BPH_SOLVER_SUCCESS; break;
|
|
|
|
case Eigen::NoConvergence: result->status = BPH_SOLVER_NO_CONVERGENCE; break;
|
|
|
|
case Eigen::InvalidInput: result->status = BPH_SOLVER_INVALID_INPUT; break;
|
|
|
|
case Eigen::NumericalIssue: result->status = BPH_SOLVER_NUMERICAL_ISSUE; break;
|
2014-09-10 18:55:15 +02:00
|
|
|
}
|
2014-09-05 12:48:49 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
result->iterations = cg.iterations();
|
|
|
|
result->error = cg.error();
|
2014-09-05 17:07:30 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
return cg.info() != Eigen::Success;
|
2014-09-10 16:59:22 +02:00
|
|
|
#endif
|
2014-09-05 17:07:30 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
/* ================================ */
|
2014-09-10 23:11:56 +02:00
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_apply_result(Implicit_Data *data)
|
2014-09-10 23:11:56 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
data->X = data->Xnew;
|
|
|
|
data->V = data->Vnew;
|
2014-09-10 23:11:56 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3])
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
#ifdef CLOTH_ROOT_FRAME
|
|
|
|
copy_m3_m3(data->tfm[index], tfm);
|
2014-09-12 10:19:41 +02:00
|
|
|
#else
|
2014-10-12 12:45:07 +02:00
|
|
|
unit_m3(data->tfm[index]);
|
|
|
|
(void)tfm;
|
2014-09-12 10:19:41 +02:00
|
|
|
#endif
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_set_motion_state(Implicit_Data *data, int index, const float x[3], const float v[3])
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
world_to_root_v3(data, index, lVector_v3(data->X, index), x);
|
|
|
|
world_to_root_v3(data, index, lVector_v3(data->V, index), v);
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_set_position(Implicit_Data *data, int index, const float x[3])
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
world_to_root_v3(data, index, lVector_v3(data->X, index), x);
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3])
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
world_to_root_v3(data, index, lVector_v3(data->V, index), v);
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3])
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
if (x) root_to_world_v3(data, index, x, lVector_v3(data->X, index));
|
|
|
|
if (v) root_to_world_v3(data, index, v, lVector_v3(data->V, index));
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-12 12:45:07 +02:00
|
|
|
void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass)
|
2014-09-05 12:48:49 +02:00
|
|
|
{
|
2014-10-12 12:45:07 +02:00
|
|
|
float m[3][3];
|
|
|
|
copy_m3_m3(m, I);
|
|
|
|
mul_m3_fl(m, mass);
|
|
|
|
data->M.set(index, index, m);
|
2014-09-05 12:48:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* IMPLICIT_SOLVER_EIGEN */
|