2011-02-23 18:03:40 +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,
|
|
|
|
* 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): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
2008-03-13 22:45:36 +00:00
|
|
|
|
2011-02-27 20:40:57 +00:00
|
|
|
/** \file blender/blenkernel/intern/implicit.c
|
|
|
|
* \ingroup bke
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2008-03-13 22:45:36 +00:00
|
|
|
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
#include "DNA_object_force.h"
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
|
|
|
#include "BLI_threads.h"
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#include "BLI_linklist.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2008-03-13 22:45:36 +00:00
|
|
|
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "BKE_cloth.h"
|
|
|
|
#include "BKE_collision.h"
|
2008-01-29 21:01:12 +00:00
|
|
|
#include "BKE_effect.h"
|
|
|
|
#include "BKE_global.h"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-09-20 01:02:39 +00:00
|
|
|
#ifdef _OPENMP
|
|
|
|
# define CLOTH_OPENMP_LIMIT 512
|
|
|
|
#endif
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2012-09-15 01:52:28 +00:00
|
|
|
#if 0 /* debug timing */
|
2008-01-29 21:01:12 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
static LARGE_INTEGER _itstart, _itend;
|
|
|
|
static LARGE_INTEGER ifreq;
|
2009-09-14 16:52:06 +00:00
|
|
|
static void itstart(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
static int first = 1;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (first) {
|
2008-01-29 21:01:12 +00:00
|
|
|
QueryPerformanceFrequency(&ifreq);
|
|
|
|
first = 0;
|
|
|
|
}
|
|
|
|
QueryPerformanceCounter(&_itstart);
|
|
|
|
}
|
2009-09-14 16:52:06 +00:00
|
|
|
static void itend(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
QueryPerformanceCounter(&_itend);
|
|
|
|
}
|
2010-12-03 16:45:04 +00:00
|
|
|
double itval(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
return ((double)_itend.QuadPart -
|
|
|
|
(double)_itstart.QuadPart)/((double)ifreq.QuadPart);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
// intrinsics need better compile flag checking
|
|
|
|
// #include <xmmintrin.h>
|
|
|
|
// #include <pmmintrin.h>
|
|
|
|
// #include <pthread.h>
|
|
|
|
|
2011-11-11 13:09:14 +00:00
|
|
|
static struct timeval _itstart, _itend;
|
|
|
|
static struct timezone itz;
|
2012-09-15 01:52:28 +00:00
|
|
|
static void itstart(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
gettimeofday(&_itstart, &itz);
|
|
|
|
}
|
2009-09-14 16:52:06 +00:00
|
|
|
static void itend(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
gettimeofday(&_itend, &itz);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2012-09-15 01:52:28 +00:00
|
|
|
static double itval(void)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
double t1, t2;
|
|
|
|
t1 = (double)_itstart.tv_sec + (double)_itstart.tv_usec/(1000*1000);
|
|
|
|
t2 = (double)_itend.tv_sec + (double)_itend.tv_usec/(1000*1000);
|
|
|
|
return t2-t1;
|
|
|
|
}
|
|
|
|
#endif
|
2012-09-15 01:52:28 +00:00
|
|
|
#endif /* debug timing */
|
2008-01-29 23:13:31 +00:00
|
|
|
|
2012-04-29 15:47:02 +00: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}};
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
/*
|
|
|
|
#define C99
|
|
|
|
#ifdef C99
|
|
|
|
#defineDO_INLINE inline
|
|
|
|
#else
|
|
|
|
#defineDO_INLINE static
|
|
|
|
#endif
|
|
|
|
*/
|
|
|
|
struct Cloth;
|
|
|
|
|
|
|
|
//////////////////////////////////////////
|
|
|
|
/* fast vector / matrix library, enhancements are welcome :) -dg */
|
|
|
|
/////////////////////////////////////////
|
|
|
|
|
|
|
|
/* DEFINITIONS */
|
|
|
|
typedef float lfVector[3];
|
|
|
|
typedef struct fmatrix3x3 {
|
2008-02-03 22:37:43 +00:00
|
|
|
float m[3][3]; /* 3x3 matrix */
|
2012-04-29 15:47:02 +00:00
|
|
|
unsigned int c, r; /* column and row number */
|
2012-08-10 00:04:15 +00:00
|
|
|
/* int pinned; // is this vertex allowed to move? */
|
2012-04-29 15:47:02 +00:00
|
|
|
float n1, n2, n3; /* three normal vectors for collision constrains */
|
2008-01-29 21:01:12 +00:00
|
|
|
unsigned int vcount; /* vertex count */
|
|
|
|
unsigned int scount; /* spring count */
|
|
|
|
} fmatrix3x3;
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
// float[3] vector
|
|
|
|
///////////////////////////
|
|
|
|
/* simple vector code */
|
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_fvector_S(float to[3], float from[3], float scalar)
|
|
|
|
{
|
|
|
|
to[0] = from[0] * scalar;
|
|
|
|
to[1] = from[1] * scalar;
|
|
|
|
to[2] = from[2] * scalar;
|
|
|
|
}
|
|
|
|
/* simple cross product */
|
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void cross_fvector(float to[3], float vectorA[3], float vectorB[3])
|
|
|
|
{
|
|
|
|
to[0] = vectorA[1] * vectorB[2] - vectorA[2] * vectorB[1];
|
|
|
|
to[1] = vectorA[2] * vectorB[0] - vectorA[0] * vectorB[2];
|
|
|
|
to[2] = vectorA[0] * vectorB[1] - vectorA[1] * vectorB[0];
|
|
|
|
}
|
|
|
|
/* simple v^T * v product ("outer product") */
|
|
|
|
/* STATUS: HAS TO BE verified (*should* work) */
|
|
|
|
DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vectorB[3])
|
|
|
|
{
|
|
|
|
mul_fvector_S(to[0], vectorB, vectorA[0]);
|
|
|
|
mul_fvector_S(to[1], vectorB, vectorA[1]);
|
|
|
|
mul_fvector_S(to[2], vectorB, vectorA[2]);
|
|
|
|
}
|
|
|
|
/* simple v^T * v product with scalar ("outer product") */
|
|
|
|
/* STATUS: HAS TO BE verified (*should* work) */
|
|
|
|
DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS)
|
2008-02-08 00:55:48 +00:00
|
|
|
{
|
2008-02-03 22:37:43 +00:00
|
|
|
mul_fvectorT_fvector(to, vectorA, vectorB);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
mul_fvector_S(to[0], to[0], aS);
|
|
|
|
mul_fvector_S(to[1], to[1], aS);
|
|
|
|
mul_fvector_S(to[2], to[2], aS);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
/* printf vector[3] on console: for debug output */
|
2009-09-14 16:52:06 +00:00
|
|
|
static void print_fvector(float m3[3])
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
printf("%f\n%f\n%f\n\n", m3[0], m3[1], m3[2]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
// long float vector float (*)[3]
|
|
|
|
///////////////////////////
|
|
|
|
/* print long vector on console: for debug output */
|
|
|
|
DO_INLINE void print_lfvector(float (*fLongVector)[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
print_fvector(fLongVector[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* create long vector */
|
|
|
|
DO_INLINE lfVector *create_lfvector(unsigned int verts)
|
|
|
|
{
|
2012-07-16 23:23:33 +00:00
|
|
|
/* TODO: check if memory allocation was successful */
|
2012-06-17 09:58:26 +00:00
|
|
|
return (lfVector *)MEM_callocN(verts * sizeof(lfVector), "cloth_implicit_alloc_vector");
|
2008-01-29 21:01:12 +00:00
|
|
|
// return (lfVector *)cloth_aligned_malloc(&MEMORY_BASE, verts * sizeof(lfVector));
|
|
|
|
}
|
|
|
|
/* delete long vector */
|
|
|
|
DO_INLINE void del_lfvector(float (*fLongVector)[3])
|
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
if (fLongVector != NULL) {
|
2012-09-08 06:40:03 +00:00
|
|
|
MEM_freeN(fLongVector);
|
2008-01-29 21:01:12 +00:00
|
|
|
// cloth_aligned_free(&MEMORY_BASE, fLongVector);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* copy long vector */
|
|
|
|
DO_INLINE void cp_lfvector(float (*to)[3], float (*from)[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
memcpy(to, from, verts * sizeof(lfVector));
|
|
|
|
}
|
|
|
|
/* init long vector with float[3] */
|
|
|
|
DO_INLINE void init_lfvector(float (*fLongVector)[3], float vector[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(fLongVector[i], vector);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* zero long vector with float[3] */
|
|
|
|
DO_INLINE void zero_lfvector(float (*to)[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
memset(to, 0.0f, verts * sizeof(lfVector));
|
|
|
|
}
|
|
|
|
/* multiply long vector with scalar*/
|
|
|
|
DO_INLINE void mul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvector_S(to[i], fLongVector[i], scalar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* multiply long vector with scalar*/
|
|
|
|
/* A -= B * float */
|
|
|
|
DO_INLINE void submul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
VECSUBMUL(to[i], fLongVector[i], scalar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* dot product for big vector */
|
|
|
|
DO_INLINE float dot_lfvector(float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
|
|
|
|
{
|
2008-02-11 08:27:54 +00:00
|
|
|
long i = 0;
|
2008-01-29 21:01:12 +00:00
|
|
|
float temp = 0.0;
|
2010-05-25 13:33:59 +00:00
|
|
|
// XXX brecht, disabled this for now (first schedule line was already disabled),
|
|
|
|
// due to non-commutative nature of floating point ops this makes the sim give
|
|
|
|
// different results each time you run it!
|
2008-01-29 21:01:12 +00:00
|
|
|
// schedule(guided, 2)
|
2012-03-24 07:52:14 +00:00
|
|
|
//#pragma omp parallel for reduction(+: temp) if (verts > CLOTH_OPENMP_LIMIT)
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < (long)verts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
temp += dot_v3v3(fLongVectorA[i], fLongVectorB[i]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
/* A = B + C --> for big vector */
|
|
|
|
DO_INLINE void add_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
VECADD(to[i], fLongVectorA[i], fLongVectorB[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* A = B + C * float --> for big vector */
|
|
|
|
DO_INLINE void add_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
VECADDS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* A = B * float + C * float --> for big vector */
|
|
|
|
DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float aS, float (*fLongVectorB)[3], float bS, unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
VECADDSS(to[i], fLongVectorA[i], aS, fLongVectorB[i], bS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* A = B - C * float --> for big vector */
|
|
|
|
DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
VECSUBS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* A = B - C --> for big vector */
|
|
|
|
DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < verts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(to[i], fLongVectorA[i], fLongVectorB[i]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
///////////////////////////
|
2008-02-03 22:37:43 +00:00
|
|
|
// 3x3 matrix
|
2008-01-29 21:01:12 +00:00
|
|
|
///////////////////////////
|
2009-11-11 09:59:51 +00:00
|
|
|
#if 0
|
2008-02-03 22:37:43 +00:00
|
|
|
/* printf 3x3 matrix on console: for debug output */
|
2009-09-14 16:52:06 +00:00
|
|
|
static void print_fmatrix(float m3[3][3])
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
printf("%f\t%f\t%f\n", m3[0][0], m3[0][1], m3[0][2]);
|
|
|
|
printf("%f\t%f\t%f\n", m3[1][0], m3[1][1], m3[1][2]);
|
|
|
|
printf("%f\t%f\t%f\n\n", m3[2][0], m3[2][1], m3[2][2]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2009-11-11 09:59:51 +00:00
|
|
|
#endif
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
/* copy 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3])
|
|
|
|
{
|
|
|
|
// memcpy(to, from, sizeof (float) * 9);
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(to[0], from[0]);
|
|
|
|
copy_v3_v3(to[1], from[1]);
|
|
|
|
copy_v3_v3(to[2], from[2]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
/* copy 3x3 matrix */
|
|
|
|
DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS)
|
|
|
|
{
|
|
|
|
cp_fmatrix(to, ZERO);
|
|
|
|
|
|
|
|
to[0][0] = aS;
|
|
|
|
to[1][1] = aS;
|
|
|
|
to[2][2] = aS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate determinant of 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE float det_fmatrix(float m[3][3])
|
|
|
|
{
|
|
|
|
return m[0][0]*m[1][1]*m[2][2] + m[1][0]*m[2][1]*m[0][2] + m[0][1]*m[1][2]*m[2][0]
|
|
|
|
-m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] - m[2][0]*m[1][1]*m[0][2];
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void inverse_fmatrix(float to[3][3], float from[3][3])
|
|
|
|
{
|
|
|
|
unsigned int i, j;
|
|
|
|
float d;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if ((d=det_fmatrix(from)) == 0) {
|
2008-01-29 21:01:12 +00:00
|
|
|
printf("can't build inverse");
|
|
|
|
exit(0);
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i=0;i<3;i++) {
|
|
|
|
for (j=0;j<3;j++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
int i1=(i+1)%3;
|
|
|
|
int i2=(i+2)%3;
|
|
|
|
int j1=(j+1)%3;
|
|
|
|
int j2=(j+2)%3;
|
|
|
|
// reverse indexs i&j to take transpose
|
|
|
|
to[j][i] = (from[i1][j1]*from[i2][j2]-from[i1][j2]*from[i2][j1])/d;
|
|
|
|
/*
|
2012-03-24 06:18:31 +00:00
|
|
|
if (i==j)
|
2008-01-29 21:01:12 +00:00
|
|
|
to[i][j] = 1.0f / from[i][j];
|
|
|
|
else
|
|
|
|
to[i][j] = 0;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied by a scalar */
|
2008-01-29 21:01:12 +00:00
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar)
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
mul_fvector_S(matrix[0], matrix[0], scalar);
|
|
|
|
mul_fvector_S(matrix[1], matrix[1], scalar);
|
|
|
|
mul_fvector_S(matrix[2], matrix[2], scalar);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
/* a vector multiplied by a 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3])
|
|
|
|
{
|
|
|
|
to[0] = matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2];
|
|
|
|
to[1] = matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2];
|
|
|
|
to[2] = matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2];
|
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied by a vector */
|
2008-01-29 21:01:12 +00:00
|
|
|
/* STATUS: verified */
|
2012-03-09 06:04:17 +00:00
|
|
|
DO_INLINE void mul_fmatrix_fvector(float *to, float matrix[3][3], float from[3])
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
to[0] = dot_v3v3(matrix[0], from);
|
|
|
|
to[1] = dot_v3v3(matrix[1], from);
|
|
|
|
to[2] = dot_v3v3(matrix[2], from);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied by a 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
mul_fvector_fmatrix(to[0], matrixA[0], matrixB);
|
|
|
|
mul_fvector_fmatrix(to[1], matrixA[1], matrixB);
|
|
|
|
mul_fvector_fmatrix(to[2], matrixA[2], matrixB);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix addition with 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void add_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
|
|
|
VECADD(to[0], matrixA[0], matrixB[0]);
|
|
|
|
VECADD(to[1], matrixA[1], matrixB[1]);
|
|
|
|
VECADD(to[2], matrixA[2], matrixB[2]);
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix add-addition with 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void addadd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
|
|
|
VECADDADD(to[0], matrixA[0], matrixB[0]);
|
|
|
|
VECADDADD(to[1], matrixA[1], matrixB[1]);
|
|
|
|
VECADDADD(to[2], matrixA[2], matrixB[2]);
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix sub-addition with 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void addsub_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS)
|
|
|
|
{
|
|
|
|
VECADDSUBSS(to[0], matrixA[0], aS, matrixB[0], bS);
|
|
|
|
VECADDSUBSS(to[1], matrixA[1], aS, matrixB[1], bS);
|
|
|
|
VECADDSUBSS(to[2], matrixA[2], aS, matrixB[2], bS);
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* A -= B + C (3x3 matrix sub-addition with 3x3 matrix) */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void subadd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
|
|
|
VECSUBADD(to[0], matrixA[0], matrixB[0]);
|
|
|
|
VECSUBADD(to[1], matrixA[1], matrixB[1]);
|
|
|
|
VECSUBADD(to[2], matrixA[2], matrixB[2]);
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void subadd_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS)
|
|
|
|
{
|
|
|
|
VECSUBADDSS(to[0], matrixA[0], aS, matrixB[0], bS);
|
|
|
|
VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS);
|
|
|
|
VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS);
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void sub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(to[0], matrixA[0], matrixB[0]);
|
|
|
|
sub_v3_v3v3(to[1], matrixA[1], matrixB[1]);
|
|
|
|
sub_v3_v3v3(to[2], matrixA[2], matrixB[2]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* A += B - C (3x3 matrix add-subtraction with 3x3 matrix) */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void addsub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
|
|
|
VECADDSUB(to[0], matrixA[0], matrixB[0]);
|
|
|
|
VECADDSUB(to[1], matrixA[1], matrixB[1]);
|
|
|
|
VECADDSUB(to[2], matrixA[2], matrixB[2]);
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
// special functions
|
|
|
|
/////////////////////////////////////////////////////////////////
|
2008-02-03 22:37:43 +00:00
|
|
|
/* a vector multiplied and added to/by a 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void muladd_fvector_fmatrix(float to[3], float from[3], float matrix[3][3])
|
|
|
|
{
|
|
|
|
to[0] += matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2];
|
|
|
|
to[1] += matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2];
|
|
|
|
to[2] += matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2];
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied and added to/by a 3x3 matrix and added to another 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void muladd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
muladd_fvector_fmatrix(to[0], matrixA[0], matrixB);
|
|
|
|
muladd_fvector_fmatrix(to[1], matrixA[1], matrixB);
|
|
|
|
muladd_fvector_fmatrix(to[2], matrixA[2], matrixB);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* a vector multiplied and sub'd to/by a 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void mulsub_fvector_fmatrix(float to[3], float from[3], float matrix[3][3])
|
|
|
|
{
|
|
|
|
to[0] -= matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2];
|
|
|
|
to[1] -= matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2];
|
|
|
|
to[2] -= matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2];
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied and sub'd to/by a 3x3 matrix and added to another 3x3 matrix */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void mulsub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
mulsub_fvector_fmatrix(to[0], matrixA[0], matrixB);
|
|
|
|
mulsub_fvector_fmatrix(to[1], matrixA[1], matrixB);
|
|
|
|
mulsub_fvector_fmatrix(to[2], matrixA[2], matrixB);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied+added by a vector */
|
2008-01-29 21:01:12 +00:00
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float from[3])
|
|
|
|
{
|
2012-03-09 06:04:17 +00:00
|
|
|
to[0] += dot_v3v3(matrix[0], from);
|
|
|
|
to[1] += dot_v3v3(matrix[1], from);
|
|
|
|
to[2] += dot_v3v3(matrix[2], from);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
/* 3x3 matrix multiplied+sub'ed by a vector */
|
2008-01-29 21:01:12 +00:00
|
|
|
DO_INLINE void mulsub_fmatrix_fvector(float to[3], float matrix[3][3], float from[3])
|
|
|
|
{
|
2012-03-09 06:04:17 +00:00
|
|
|
to[0] -= dot_v3v3(matrix[0], from);
|
|
|
|
to[1] -= dot_v3v3(matrix[1], from);
|
|
|
|
to[2] -= dot_v3v3(matrix[2], from);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
///////////////////////////
|
2008-02-03 22:37:43 +00:00
|
|
|
// SPARSE SYMMETRIC big matrix with 3x3 matrix entries
|
2008-01-29 21:01:12 +00:00
|
|
|
///////////////////////////
|
|
|
|
/* printf a big matrix on console: for debug output */
|
2009-09-17 14:46:22 +00:00
|
|
|
#if 0
|
2009-09-14 16:52:06 +00:00
|
|
|
static void print_bfmatrix(fmatrix3x3 *m3)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < m3[0].vcount + m3[0].scount; i++)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
print_fmatrix(m3[i].m);
|
|
|
|
}
|
|
|
|
}
|
2009-09-17 14:46:22 +00:00
|
|
|
#endif
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
/* create big matrix */
|
|
|
|
DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
|
|
|
|
{
|
2012-07-16 23:23:33 +00:00
|
|
|
// TODO: check if memory allocation was successful */
|
2012-06-17 09:58:26 +00:00
|
|
|
fmatrix3x3 *temp = (fmatrix3x3 *)MEM_callocN(sizeof(fmatrix3x3) * (verts + springs), "cloth_implicit_alloc_matrix");
|
2008-01-29 21:01:12 +00:00
|
|
|
temp[0].vcount = verts;
|
|
|
|
temp[0].scount = springs;
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
/* delete big matrix */
|
|
|
|
DO_INLINE void del_bfmatrix(fmatrix3x3 *matrix)
|
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
if (matrix != NULL) {
|
2012-09-08 06:40:03 +00:00
|
|
|
MEM_freeN(matrix);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
/* copy big matrix */
|
|
|
|
DO_INLINE void cp_bfmatrix(fmatrix3x3 *to, fmatrix3x3 *from)
|
2012-07-06 23:56:59 +00:00
|
|
|
{
|
|
|
|
// TODO bounds checking
|
2012-04-29 17:55:54 +00:00
|
|
|
memcpy(to, from, sizeof(fmatrix3x3) * (from[0].vcount+from[0].scount));
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
/* init big matrix */
|
|
|
|
// slow in parallel
|
|
|
|
DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-02-03 22:37:43 +00:00
|
|
|
cp_fmatrix(matrix[i].m, m3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
/* init the diagonal of big matrix */
|
|
|
|
// slow in parallel
|
|
|
|
DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
unsigned int i, j;
|
|
|
|
float tmatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
cp_fmatrix(matrix[i].m, m3);
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
for (j = matrix[0].vcount; j < matrix[0].vcount+matrix[0].scount; j++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
cp_fmatrix(matrix[j].m, tmatrix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* multiply big matrix with scalar*/
|
|
|
|
DO_INLINE void mul_bfmatrix_S(fmatrix3x3 *matrix, float scalar)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fmatrix_S(matrix[i].m, scalar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SPARSE SYMMETRIC multiply big matrix with long vector*/
|
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
2010-05-25 13:33:59 +00:00
|
|
|
unsigned int vcount = from[0].vcount;
|
|
|
|
lfVector *temp = create_lfvector(vcount);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2010-05-25 13:33:59 +00:00
|
|
|
zero_lfvector(to, vcount);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-03-24 07:52:14 +00:00
|
|
|
#pragma omp parallel sections private(i) if (vcount > CLOTH_OPENMP_LIMIT)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
#pragma omp section
|
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = from[0].vcount; i < from[0].vcount+from[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
muladd_fmatrix_fvector(to[from[i].c], from[i].m, fLongVector[from[i].r]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#pragma omp section
|
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < from[0].vcount+from[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
muladd_fmatrix_fvector(temp[from[i].r], from[i].m, fLongVector[from[i].c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_lfvector_lfvector(to, to, temp, from[0].vcount);
|
|
|
|
|
|
|
|
del_lfvector(temp);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SPARSE SYMMETRIC multiply big matrix with long vector (for diagonal preconditioner) */
|
|
|
|
/* STATUS: verified */
|
|
|
|
DO_INLINE void mul_prevfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < from[0].vcount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fmatrix_fvector(to[from[i].r], from[i].m, fLongVector[from[i].c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SPARSE SYMMETRIC add big matrix with big matrix: A = B + C*/
|
|
|
|
DO_INLINE void add_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
add_fmatrix_fmatrix(to[i].m, from[i].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* SPARSE SYMMETRIC add big matrix with big matrix: A += B + C */
|
|
|
|
DO_INLINE void addadd_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
addadd_fmatrix_fmatrix(to[i].m, from[i].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* SPARSE SYMMETRIC subadd big matrix with big matrix: A -= B + C */
|
|
|
|
DO_INLINE void subadd_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
subadd_fmatrix_fmatrix(to[i].m, from[i].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* A = B - C (SPARSE SYMMETRIC sub big matrix with big matrix) */
|
|
|
|
DO_INLINE void sub_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
sub_fmatrix_fmatrix(to[i].m, from[i].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* SPARSE SYMMETRIC sub big matrix with big matrix S (special constraint matrix with limited entries) */
|
|
|
|
DO_INLINE void sub_bfmatrix_Smatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
sub_fmatrix_fmatrix(to[matrix[i].c].m, from[matrix[i].c].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* A += B - C (SPARSE SYMMETRIC addsub big matrix with big matrix) */
|
|
|
|
DO_INLINE void addsub_bfmatrix_bfmatrix( fmatrix3x3 *to, fmatrix3x3 *from, fmatrix3x3 *matrix)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
addsub_fmatrix_fmatrix(to[i].m, from[i].m, matrix[i].m);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* SPARSE SYMMETRIC sub big matrix with big matrix*/
|
|
|
|
/* A -= B * float + C * float --> for big matrix */
|
|
|
|
/* VERIFIED */
|
|
|
|
DO_INLINE void subadd_bfmatrixS_bfmatrixS( fmatrix3x3 *to, fmatrix3x3 *from, float aS, fmatrix3x3 *matrix, float bS)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
subadd_fmatrixS_fmatrixS(to[i].m, from[i].m, aS, matrix[i].m, bS);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
// simulator start
|
|
|
|
///////////////////////////////////////////////////////////////////
|
2012-06-06 22:38:39 +00:00
|
|
|
typedef struct Implicit_Data {
|
2008-01-29 21:01:12 +00:00
|
|
|
lfVector *X, *V, *Xnew, *Vnew, *olddV, *F, *B, *dV, *z;
|
2008-02-03 22:37:43 +00:00
|
|
|
fmatrix3x3 *A, *dFdV, *dFdX, *S, *P, *Pinv, *bigI, *M;
|
2008-01-29 21:01:12 +00:00
|
|
|
} Implicit_Data;
|
|
|
|
|
2012-08-10 00:04:15 +00:00
|
|
|
/* Init constraint matrix */
|
|
|
|
static void update_matrixS(ClothVertex *verts, int numverts, fmatrix3x3 *S)
|
|
|
|
{
|
|
|
|
unsigned int pinned = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* Clear matrix from old vertex constraints */
|
|
|
|
for(i = 0; i < S[0].vcount; i++)
|
|
|
|
S[i].c = S[i].r = 0;
|
|
|
|
|
|
|
|
/* Set new vertex constraints */
|
|
|
|
for (i = 0; i < numverts; i++) {
|
|
|
|
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
|
|
|
|
S[pinned].c = S[pinned].r = i;
|
|
|
|
pinned++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// S is special and needs specific vcount and scount
|
|
|
|
S[0].vcount = pinned;
|
|
|
|
S[0].scount = 0;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
int implicit_init(Object *UNUSED(ob), ClothModifierData *clmd)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
Cloth *cloth = NULL;
|
|
|
|
ClothVertex *verts = NULL;
|
|
|
|
ClothSpring *spring = NULL;
|
|
|
|
Implicit_Data *id = NULL;
|
|
|
|
LinkNode *search = NULL;
|
|
|
|
|
2012-08-08 18:21:54 +00:00
|
|
|
if (G.debug_value > 0)
|
2008-01-29 21:01:12 +00:00
|
|
|
printf("implicit_init\n");
|
|
|
|
|
|
|
|
// init memory guard
|
|
|
|
// MEMORY_BASE.first = MEMORY_BASE.last = NULL;
|
|
|
|
|
|
|
|
cloth = (Cloth *)clmd->clothObject;
|
|
|
|
verts = cloth->verts;
|
|
|
|
|
|
|
|
// create implicit base
|
2012-06-17 09:58:26 +00:00
|
|
|
id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat");
|
2008-01-29 21:01:12 +00:00
|
|
|
cloth->implicit = id;
|
|
|
|
|
|
|
|
/* process diagonal elements */
|
|
|
|
id->A = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
|
|
|
id->dFdV = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
|
|
|
id->dFdX = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
|
|
|
id->S = create_bfmatrix(cloth->numverts, 0);
|
|
|
|
id->Pinv = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
|
|
|
id->P = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
|
|
|
id->bigI = create_bfmatrix(cloth->numverts, cloth->numsprings); // TODO 0 springs
|
2008-02-03 22:37:43 +00:00
|
|
|
id->M = create_bfmatrix(cloth->numverts, cloth->numsprings);
|
2008-01-29 21:01:12 +00:00
|
|
|
id->X = create_lfvector(cloth->numverts);
|
|
|
|
id->Xnew = create_lfvector(cloth->numverts);
|
|
|
|
id->V = create_lfvector(cloth->numverts);
|
|
|
|
id->Vnew = create_lfvector(cloth->numverts);
|
|
|
|
id->olddV = create_lfvector(cloth->numverts);
|
|
|
|
zero_lfvector(id->olddV, cloth->numverts);
|
|
|
|
id->F = create_lfvector(cloth->numverts);
|
|
|
|
id->B = create_lfvector(cloth->numverts);
|
|
|
|
id->dV = create_lfvector(cloth->numverts);
|
|
|
|
id->z = create_lfvector(cloth->numverts);
|
|
|
|
|
2012-08-10 00:04:15 +00:00
|
|
|
id->S[0].vcount = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < cloth->numverts; i++) {
|
2008-02-03 22:37:43 +00:00
|
|
|
id->A[i].r = id->A[i].c = id->dFdV[i].r = id->dFdV[i].c = id->dFdX[i].r = id->dFdX[i].c = id->P[i].c = id->P[i].r = id->Pinv[i].c = id->Pinv[i].r = id->bigI[i].c = id->bigI[i].r = id->M[i].r = id->M[i].c = i;
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-08-10 00:04:15 +00:00
|
|
|
update_matrixS(verts, cloth->numverts, id->S);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
initdiag_fmatrixS(id->M[i].m, verts[i].mass);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
// init springs
|
2008-01-29 21:01:12 +00:00
|
|
|
search = cloth->springs;
|
2012-08-10 00:04:15 +00:00
|
|
|
for (i = 0; i < cloth->numsprings; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
spring = search->link;
|
|
|
|
|
|
|
|
// dFdV_start[i].r = big_I[i].r = big_zero[i].r =
|
|
|
|
id->A[i+cloth->numverts].r = id->dFdV[i+cloth->numverts].r = id->dFdX[i+cloth->numverts].r =
|
2008-02-03 22:37:43 +00:00
|
|
|
id->P[i+cloth->numverts].r = id->Pinv[i+cloth->numverts].r = id->bigI[i+cloth->numverts].r = id->M[i+cloth->numverts].r = spring->ij;
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
// dFdV_start[i].c = big_I[i].c = big_zero[i].c =
|
|
|
|
id->A[i+cloth->numverts].c = id->dFdV[i+cloth->numverts].c = id->dFdX[i+cloth->numverts].c =
|
2008-02-03 22:37:43 +00:00
|
|
|
id->P[i+cloth->numverts].c = id->Pinv[i+cloth->numverts].c = id->bigI[i+cloth->numverts].c = id->M[i+cloth->numverts].c = spring->kl;
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
spring->matrix_index = i + cloth->numverts;
|
|
|
|
|
|
|
|
search = search->next;
|
|
|
|
}
|
2008-02-08 00:55:48 +00:00
|
|
|
|
|
|
|
initdiag_bfmatrix(id->bigI, I);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < cloth->numverts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(id->X[i], verts[i].x);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2012-08-10 00:04:15 +00:00
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
int implicit_free(ClothModifierData *clmd)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
Implicit_Data *id;
|
|
|
|
Cloth *cloth;
|
|
|
|
cloth = (Cloth *)clmd->clothObject;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (cloth) {
|
2008-01-29 21:01:12 +00:00
|
|
|
id = cloth->implicit;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (id) {
|
2008-01-29 21:01:12 +00:00
|
|
|
del_bfmatrix(id->A);
|
|
|
|
del_bfmatrix(id->dFdV);
|
|
|
|
del_bfmatrix(id->dFdX);
|
|
|
|
del_bfmatrix(id->S);
|
|
|
|
del_bfmatrix(id->P);
|
|
|
|
del_bfmatrix(id->Pinv);
|
|
|
|
del_bfmatrix(id->bigI);
|
2008-02-03 22:37:43 +00:00
|
|
|
del_bfmatrix(id->M);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
del_lfvector(id->X);
|
|
|
|
del_lfvector(id->Xnew);
|
|
|
|
del_lfvector(id->V);
|
|
|
|
del_lfvector(id->Vnew);
|
|
|
|
del_lfvector(id->olddV);
|
|
|
|
del_lfvector(id->F);
|
|
|
|
del_lfvector(id->B);
|
|
|
|
del_lfvector(id->dV);
|
|
|
|
del_lfvector(id->z);
|
|
|
|
|
|
|
|
MEM_freeN(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DO_INLINE float fb(float length, float L)
|
|
|
|
{
|
|
|
|
float x = length/L;
|
2012-04-29 15:47:02 +00:00
|
|
|
return (-11.541f*pow(x, 4)+34.193f*pow(x, 3)-39.083f*pow(x, 2)+23.116f*x-9.713f);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DO_INLINE float fbderiv(float length, float L)
|
|
|
|
{
|
|
|
|
float x = length/L;
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
return (-46.164f*pow(x, 3)+102.579f*pow(x, 2)-78.166f*x+23.116f);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DO_INLINE float fbstar(float length, float L, float kb, float cb)
|
|
|
|
{
|
|
|
|
float tempfb = kb * fb(length, L);
|
|
|
|
|
|
|
|
float fbstar = cb * (length - L);
|
2008-02-28 00:01:19 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (tempfb < fbstar)
|
2008-01-29 21:01:12 +00:00
|
|
|
return fbstar;
|
|
|
|
else
|
|
|
|
return tempfb;
|
|
|
|
}
|
|
|
|
|
|
|
|
// function to calculae bending spring force (taken from Choi & Co)
|
|
|
|
DO_INLINE float fbstar_jacobi(float length, float L, float kb, float cb)
|
|
|
|
{
|
|
|
|
float tempfb = kb * fb(length, L);
|
|
|
|
float fbstar = cb * (length - L);
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (tempfb < fbstar) {
|
2008-01-29 21:01:12 +00:00
|
|
|
return cb;
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else {
|
2008-01-29 21:01:12 +00:00
|
|
|
return kb * fbderiv(length, L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
|
|
|
|
{
|
|
|
|
unsigned int i=0;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < S[0].vcount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvector_fmatrix(V[S[i].r], V[S[i].r], S[i].m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
// Solves for unknown X in equation AX=B
|
|
|
|
unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
|
2011-09-29 15:28:22 +00:00
|
|
|
float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */;
|
2008-01-29 21:01:12 +00:00
|
|
|
lfVector *q, *d, *tmp, *r;
|
|
|
|
float s, starget, a, s_prev;
|
|
|
|
unsigned int numverts = lA[0].vcount;
|
|
|
|
q = create_lfvector(numverts);
|
|
|
|
d = create_lfvector(numverts);
|
|
|
|
tmp = create_lfvector(numverts);
|
|
|
|
r = create_lfvector(numverts);
|
|
|
|
|
|
|
|
// zero_lfvector(ldV, CLOTHPARTICLES);
|
|
|
|
filter(ldV, S);
|
|
|
|
|
|
|
|
add_lfvector_lfvector(ldV, ldV, z, numverts);
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
// r = B - Mul(tmp, A, X); // just use B if X known to be zero
|
2008-01-29 21:01:12 +00:00
|
|
|
cp_lfvector(r, lB, numverts);
|
|
|
|
mul_bfmatrix_lfvector(tmp, lA, ldV);
|
|
|
|
sub_lfvector_lfvector(r, r, tmp, numverts);
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
filter(r, S);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
cp_lfvector(d, r, numverts);
|
|
|
|
|
|
|
|
s = dot_lfvector(r, r, numverts);
|
|
|
|
starget = s * sqrt(conjgrad_epsilon);
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
while (s>starget && conjgrad_loopcount < conjgrad_looplimit) {
|
2012-04-29 15:47:02 +00:00
|
|
|
// Mul(q, A, d); // q = A*d;
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_bfmatrix_lfvector(q, lA, d);
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
filter(q, S);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
a = s/dot_lfvector(d, q, numverts);
|
|
|
|
|
|
|
|
// X = X + d*a;
|
|
|
|
add_lfvector_lfvectorS(ldV, ldV, d, a, numverts);
|
|
|
|
|
|
|
|
// r = r - q*a;
|
|
|
|
sub_lfvector_lfvectorS(r, r, q, a, numverts);
|
|
|
|
|
|
|
|
s_prev = s;
|
|
|
|
s = dot_lfvector(r, r, numverts);
|
|
|
|
|
|
|
|
//d = r+d*(s/s_prev);
|
|
|
|
add_lfvector_lfvectorS(d, r, d, (s/s_prev), numverts);
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
filter(d, S);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
conjgrad_loopcount++;
|
|
|
|
}
|
2011-09-29 15:28:22 +00:00
|
|
|
/* conjgrad_lasterror = s; */ /* UNUSED */
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
del_lfvector(q);
|
|
|
|
del_lfvector(d);
|
|
|
|
del_lfvector(tmp);
|
|
|
|
del_lfvector(r);
|
|
|
|
// printf("W/O conjgrad_loopcount: %d\n", conjgrad_loopcount);
|
|
|
|
|
|
|
|
return conjgrad_loopcount<conjgrad_looplimit; // true means we reached desired accuracy in given time - ie stable
|
|
|
|
}
|
|
|
|
|
|
|
|
// block diagonalizer
|
|
|
|
DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
|
|
|
// Take only the diagonal blocks of A
|
2012-03-24 07:52:14 +00:00
|
|
|
// #pragma omp parallel for private(i) if (lA[0].vcount > CLOTH_OPENMP_LIMIT)
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i<lA[0].vcount; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// block diagonalizer
|
|
|
|
cp_fmatrix(P[i].m, lA[i].m);
|
|
|
|
inverse_fmatrix(Pinv[i].m, P[i].m);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2009-11-11 09:59:51 +00:00
|
|
|
#if 0
|
2008-02-08 00:55:48 +00:00
|
|
|
/*
|
2008-01-29 21:01:12 +00:00
|
|
|
// version 1.3
|
2009-09-14 16:52:06 +00:00
|
|
|
static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
|
|
|
|
float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0;
|
|
|
|
float conjgrad_epsilon=0.0001; // 0.2 is dt for steps=5
|
|
|
|
lfVector *r = create_lfvector(numverts);
|
|
|
|
lfVector *p = create_lfvector(numverts);
|
|
|
|
lfVector *s = create_lfvector(numverts);
|
|
|
|
lfVector *h = create_lfvector(numverts);
|
|
|
|
|
|
|
|
BuildPPinv(lA, P, Pinv);
|
|
|
|
|
|
|
|
filter(dv, S);
|
|
|
|
add_lfvector_lfvector(dv, dv, z, numverts);
|
|
|
|
|
|
|
|
mul_bfmatrix_lfvector(r, lA, dv);
|
|
|
|
sub_lfvector_lfvector(r, lB, r, numverts);
|
|
|
|
filter(r, S);
|
|
|
|
|
|
|
|
mul_prevfmatrix_lfvector(p, Pinv, r);
|
|
|
|
filter(p, S);
|
|
|
|
|
|
|
|
deltaNew = dot_lfvector(r, p, numverts);
|
|
|
|
|
|
|
|
delta0 = deltaNew * sqrt(conjgrad_epsilon);
|
|
|
|
|
|
|
|
// itstart();
|
|
|
|
|
|
|
|
while ((deltaNew > delta0) && (iterations < conjgrad_looplimit))
|
|
|
|
{
|
|
|
|
iterations++;
|
|
|
|
|
|
|
|
mul_bfmatrix_lfvector(s, lA, p);
|
|
|
|
filter(s, S);
|
|
|
|
|
|
|
|
alpha = deltaNew / dot_lfvector(p, s, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
|
|
|
|
|
|
|
|
mul_prevfmatrix_lfvector(h, Pinv, r);
|
|
|
|
filter(h, S);
|
|
|
|
|
|
|
|
deltaOld = deltaNew;
|
|
|
|
|
|
|
|
deltaNew = dot_lfvector(r, h, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
|
|
|
|
|
|
|
|
filter(p, S);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// itend();
|
|
|
|
// printf("cg_filtered_pre time: %f\n", (float)itval());
|
|
|
|
|
|
|
|
del_lfvector(h);
|
|
|
|
del_lfvector(s);
|
|
|
|
del_lfvector(p);
|
|
|
|
del_lfvector(r);
|
|
|
|
|
2008-02-08 00:55:48 +00:00
|
|
|
printf("iterations: %d\n", iterations);
|
|
|
|
|
|
|
|
return iterations<conjgrad_looplimit;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
// version 1.4
|
2009-09-14 16:52:06 +00:00
|
|
|
static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI)
|
2008-02-08 00:55:48 +00:00
|
|
|
{
|
|
|
|
unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
|
|
|
|
float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0, tol = 0;
|
|
|
|
lfVector *r = create_lfvector(numverts);
|
|
|
|
lfVector *p = create_lfvector(numverts);
|
|
|
|
lfVector *s = create_lfvector(numverts);
|
|
|
|
lfVector *h = create_lfvector(numverts);
|
|
|
|
lfVector *bhat = create_lfvector(numverts);
|
|
|
|
lfVector *btemp = create_lfvector(numverts);
|
|
|
|
|
|
|
|
BuildPPinv(lA, P, Pinv);
|
|
|
|
|
|
|
|
initdiag_bfmatrix(bigI, I);
|
|
|
|
sub_bfmatrix_Smatrix(bigI, bigI, S);
|
|
|
|
|
|
|
|
// x = Sx_0+(I-S)z
|
|
|
|
filter(dv, S);
|
|
|
|
add_lfvector_lfvector(dv, dv, z, numverts);
|
|
|
|
|
|
|
|
// b_hat = S(b-A(I-S)z)
|
|
|
|
mul_bfmatrix_lfvector(r, lA, z);
|
|
|
|
mul_bfmatrix_lfvector(bhat, bigI, r);
|
|
|
|
sub_lfvector_lfvector(bhat, lB, bhat, numverts);
|
|
|
|
|
|
|
|
// r = S(b-Ax)
|
|
|
|
mul_bfmatrix_lfvector(r, lA, dv);
|
|
|
|
sub_lfvector_lfvector(r, lB, r, numverts);
|
|
|
|
filter(r, S);
|
|
|
|
|
|
|
|
// p = SP^-1r
|
|
|
|
mul_prevfmatrix_lfvector(p, Pinv, r);
|
|
|
|
filter(p, S);
|
|
|
|
|
|
|
|
// delta0 = bhat^TP^-1bhat
|
|
|
|
mul_prevfmatrix_lfvector(btemp, Pinv, bhat);
|
|
|
|
delta0 = dot_lfvector(bhat, btemp, numverts);
|
|
|
|
|
|
|
|
// deltaNew = r^TP
|
|
|
|
deltaNew = dot_lfvector(r, p, numverts);
|
|
|
|
|
|
|
|
/*
|
|
|
|
filter(dv, S);
|
|
|
|
add_lfvector_lfvector(dv, dv, z, numverts);
|
|
|
|
|
|
|
|
mul_bfmatrix_lfvector(r, lA, dv);
|
|
|
|
sub_lfvector_lfvector(r, lB, r, numverts);
|
|
|
|
filter(r, S);
|
|
|
|
|
|
|
|
mul_prevfmatrix_lfvector(p, Pinv, r);
|
|
|
|
filter(p, S);
|
|
|
|
|
|
|
|
deltaNew = dot_lfvector(r, p, numverts);
|
|
|
|
|
|
|
|
delta0 = deltaNew * sqrt(conjgrad_epsilon);
|
|
|
|
*/
|
|
|
|
|
|
|
|
// itstart();
|
|
|
|
|
|
|
|
tol = (0.01*0.2);
|
|
|
|
|
|
|
|
while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit))
|
|
|
|
{
|
|
|
|
iterations++;
|
|
|
|
|
|
|
|
mul_bfmatrix_lfvector(s, lA, p);
|
|
|
|
filter(s, S);
|
|
|
|
|
|
|
|
alpha = deltaNew / dot_lfvector(p, s, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
|
|
|
|
|
|
|
|
mul_prevfmatrix_lfvector(h, Pinv, r);
|
|
|
|
filter(h, S);
|
|
|
|
|
|
|
|
deltaOld = deltaNew;
|
|
|
|
|
|
|
|
deltaNew = dot_lfvector(r, h, numverts);
|
|
|
|
|
|
|
|
add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
|
|
|
|
|
|
|
|
filter(p, S);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// itend();
|
|
|
|
// printf("cg_filtered_pre time: %f\n", (float)itval());
|
|
|
|
|
|
|
|
del_lfvector(btemp);
|
|
|
|
del_lfvector(bhat);
|
|
|
|
del_lfvector(h);
|
|
|
|
del_lfvector(s);
|
|
|
|
del_lfvector(p);
|
|
|
|
del_lfvector(r);
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
// printf("iterations: %d\n", iterations);
|
|
|
|
|
|
|
|
return iterations<conjgrad_looplimit;
|
|
|
|
}
|
2009-11-11 09:59:51 +00:00
|
|
|
#endif
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
// outer product is NOT cross product!!!
|
2008-02-03 22:37:43 +00:00
|
|
|
DO_INLINE void dfdx_spring_type1(float to[3][3], float extent[3], float length, float L, float dot, float k)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
// dir is unit length direction, rest is spring's restlength, k is spring constant.
|
2012-04-29 15:47:02 +00:00
|
|
|
// return (outerprod(dir, dir)*k + (I - outerprod(dir, dir))*(k - ((k*L)/length)));
|
2008-01-29 21:01:12 +00:00
|
|
|
float temp[3][3];
|
2008-02-03 22:37:43 +00:00
|
|
|
float temp1 = k*(1.0 - (L/length));
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
mul_fvectorT_fvectorS(temp, extent, extent, 1.0 / dot);
|
|
|
|
sub_fmatrix_fmatrix(to, I, temp);
|
|
|
|
mul_fmatrix_S(to, temp1);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
mul_fvectorT_fvectorS(temp, extent, extent, k/ dot);
|
|
|
|
add_fmatrix_fmatrix(to, to, temp);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
/*
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvectorT_fvector(temp, dir, dir);
|
|
|
|
sub_fmatrix_fmatrix(to, I, temp);
|
|
|
|
mul_fmatrix_S(to, k* (1.0f-(L/length)));
|
|
|
|
mul_fmatrix_S(temp, k);
|
|
|
|
add_fmatrix_fmatrix(to, temp, to);
|
2008-02-03 22:37:43 +00:00
|
|
|
*/
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
DO_INLINE void dfdx_spring_type2(float to[3][3], float dir[3], float length, float L, float k, float cb)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
// return outerprod(dir, dir)*fbstar_jacobi(length, L, k, cb);
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvectorT_fvectorS(to, dir, dir, fbstar_jacobi(length, L, k, cb));
|
|
|
|
}
|
|
|
|
|
2008-02-08 00:55:48 +00:00
|
|
|
DO_INLINE void dfdv_damp(float to[3][3], float dir[3], float damping)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
// derivative of force wrt velocity.
|
2008-02-08 00:55:48 +00:00
|
|
|
mul_fvectorT_fvectorS(to, dir, dir, damping);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
DO_INLINE void dfdx_spring(float to[3][3], float dir[3], float length, float L, float k)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
// dir is unit length direction, rest is spring's restlength, k is spring constant.
|
2012-04-29 15:47:02 +00:00
|
|
|
//return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvectorT_fvector(to, dir, dir);
|
|
|
|
sub_fmatrix_fmatrix(to, I, to);
|
2009-09-10 22:32:33 +00:00
|
|
|
|
|
|
|
mul_fmatrix_S(to, (L/length));
|
2008-01-29 21:01:12 +00:00
|
|
|
sub_fmatrix_fmatrix(to, to, I);
|
|
|
|
mul_fmatrix_S(to, -k);
|
|
|
|
}
|
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
// unused atm
|
2012-04-29 15:47:02 +00:00
|
|
|
DO_INLINE void dfdx_damp(float to[3][3], float dir[3], float length, const float vel[3], float rest, float damping)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
// inner spring damping vel is the relative velocity of the endpoints.
|
2012-04-29 15:47:02 +00:00
|
|
|
// return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvectorT_fvector(to, dir, dir);
|
|
|
|
sub_fmatrix_fmatrix(to, I, to);
|
2012-04-29 15:47:02 +00:00
|
|
|
mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel)/MAX2(length, rest))));
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *UNUSED(lF), lfVector *X, lfVector *V, fmatrix3x3 *UNUSED(dFdV), fmatrix3x3 *UNUSED(dFdX), float time)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2008-02-08 00:55:48 +00:00
|
|
|
Cloth *cloth = clmd->clothObject;
|
|
|
|
ClothVertex *verts = cloth->verts;
|
2008-01-29 21:01:12 +00:00
|
|
|
float extent[3];
|
2008-02-03 22:37:43 +00:00
|
|
|
float length = 0, dot = 0;
|
2012-04-29 15:47:02 +00:00
|
|
|
float dir[3] = {0, 0, 0};
|
2008-01-29 21:01:12 +00:00
|
|
|
float vel[3];
|
|
|
|
float k = 0.0f;
|
|
|
|
float L = s->restlen;
|
2011-01-12 03:41:12 +00:00
|
|
|
float cb; /* = clmd->sim_parms->structural; */ /*UNUSED*/
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
float nullf[3] = {0, 0, 0};
|
|
|
|
float stretch_force[3] = {0, 0, 0};
|
|
|
|
float bending_force[3] = {0, 0, 0};
|
|
|
|
float damping_force[3] = {0, 0, 0};
|
|
|
|
float nulldfdx[3][3]={ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
float scaling = 0.0;
|
2009-09-10 22:32:33 +00:00
|
|
|
|
|
|
|
int no_compress = clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(s->f, nullf);
|
2008-01-29 21:01:12 +00:00
|
|
|
cp_fmatrix(s->dfdx, nulldfdx);
|
|
|
|
cp_fmatrix(s->dfdv, nulldfdx);
|
|
|
|
|
|
|
|
// calculate elonglation
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(extent, X[s->kl], X[s->ij]);
|
|
|
|
sub_v3_v3v3(vel, V[s->kl], V[s->ij]);
|
|
|
|
dot = dot_v3v3(extent, extent);
|
2008-02-03 22:37:43 +00:00
|
|
|
length = sqrt(dot);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (length > ALMOST_ZERO) {
|
2008-01-29 21:01:12 +00:00
|
|
|
/*
|
2012-03-24 06:18:31 +00:00
|
|
|
if (length>L)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-21 15:11:03 +00:00
|
|
|
if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
|
|
|
|
((((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen))) // cut spring!
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
s->flags |= CSPRING_FLAG_DEACTIVATE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
mul_fvector_S(dir, extent, 1.0f/length);
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else {
|
2008-01-29 21:01:12 +00:00
|
|
|
mul_fvector_S(dir, extent, 0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate force of structural + shear springs
|
2012-04-28 06:31:57 +00:00
|
|
|
if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR)) {
|
|
|
|
if (length > L || no_compress) {
|
2008-01-29 21:01:12 +00:00
|
|
|
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
|
|
|
|
|
|
|
|
k = clmd->sim_parms->structural;
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
scaling = k + s->stiffness * ABS(clmd->sim_parms->max_struct-k);
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-02-12 11:04:58 +00:00
|
|
|
k = scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-02-03 22:37:43 +00:00
|
|
|
// TODO: verify, half verified (couldn't see error)
|
2012-07-06 23:56:59 +00:00
|
|
|
mul_fvector_S(stretch_force, dir, k*(length-L));
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
VECADD(s->f, s->f, stretch_force);
|
|
|
|
|
|
|
|
// Ascher & Boxman, p.21: Damping only during elonglation
|
2008-02-08 00:55:48 +00:00
|
|
|
// something wrong with it...
|
2012-03-09 06:04:17 +00:00
|
|
|
mul_fvector_S(damping_force, dir, clmd->sim_parms->Cdis * dot_v3v3(vel, dir));
|
2008-01-29 21:01:12 +00:00
|
|
|
VECADD(s->f, s->f, damping_force);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2008-02-08 00:55:48 +00:00
|
|
|
/* VERIFIED */
|
|
|
|
dfdx_spring(s->dfdx, dir, length, L, k);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
/* VERIFIED */
|
2008-02-08 00:55:48 +00:00
|
|
|
dfdv_damp(s->dfdv, dir, clmd->sim_parms->Cdis);
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-07 04:53:43 +00:00
|
|
|
else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
|
2008-02-08 00:55:48 +00:00
|
|
|
float tvect[3];
|
|
|
|
|
|
|
|
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
|
|
|
|
|
|
|
|
// current_position = xold + t * (newposition - xold)
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(tvect, verts[s->ij].xconst, verts[s->ij].xold);
|
2008-02-08 00:55:48 +00:00
|
|
|
mul_fvector_S(tvect, tvect, time);
|
|
|
|
VECADD(tvect, tvect, verts[s->ij].xold);
|
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(extent, X[s->ij], tvect);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2011-01-22 03:50:09 +00:00
|
|
|
// SEE MSG BELOW (these are UNUSED)
|
2012-03-09 06:04:17 +00:00
|
|
|
// dot = dot_v3v3(extent, extent);
|
2011-01-22 03:50:09 +00:00
|
|
|
// length = sqrt(dot);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
|
|
|
k = clmd->sim_parms->goalspring;
|
2008-02-28 18:57:14 +00:00
|
|
|
|
|
|
|
scaling = k + s->stiffness * ABS(clmd->sim_parms->max_struct-k);
|
|
|
|
|
|
|
|
k = verts [s->ij].goal * scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
|
|
|
|
|
|
|
|
VECADDS(s->f, s->f, extent, -k);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
mul_fvector_S(damping_force, dir, clmd->sim_parms->goalfrict * 0.01 * dot_v3v3(vel, dir));
|
2008-02-08 00:55:48 +00:00
|
|
|
VECADD(s->f, s->f, damping_force);
|
|
|
|
|
|
|
|
// HERE IS THE PROBLEM!!!!
|
|
|
|
// dfdx_spring(s->dfdx, dir, length, 0.0, k);
|
|
|
|
// dfdv_damp(s->dfdv, dir, MIN2(1.0, (clmd->sim_parms->goalfrict/100.0)));
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else { /* calculate force of bending springs */
|
|
|
|
if (length < L) {
|
2008-01-29 21:01:12 +00:00
|
|
|
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
|
|
|
|
|
|
|
|
k = clmd->sim_parms->bending;
|
|
|
|
|
|
|
|
scaling = k + s->stiffness * ABS(clmd->sim_parms->max_bend-k);
|
2008-02-12 11:04:58 +00:00
|
|
|
cb = k = scaling / (20.0*(clmd->sim_parms->avg_spring_len + FLT_EPSILON));
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
mul_fvector_S(bending_force, dir, fbstar(length, L, k, cb));
|
|
|
|
VECADD(s->f, s->f, bending_force);
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
dfdx_spring_type2(s->dfdx, dir, length, L, k, cb);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
DO_INLINE void cloth_apply_spring_force(ClothModifierData *UNUSED(clmd), ClothSpring *s, lfVector *lF, lfVector *UNUSED(X), lfVector *UNUSED(V), fmatrix3x3 *dFdV, fmatrix3x3 *dFdX)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-28 06:31:57 +00:00
|
|
|
if (s->flags & CLOTH_SPRING_FLAG_NEEDED) {
|
|
|
|
if (!(s->type & CLOTH_SPRING_TYPE_BENDING)) {
|
2008-01-29 21:01:12 +00:00
|
|
|
sub_fmatrix_fmatrix(dFdV[s->ij].m, dFdV[s->ij].m, s->dfdv);
|
|
|
|
sub_fmatrix_fmatrix(dFdV[s->kl].m, dFdV[s->kl].m, s->dfdv);
|
|
|
|
add_fmatrix_fmatrix(dFdV[s->matrix_index].m, dFdV[s->matrix_index].m, s->dfdv);
|
|
|
|
}
|
|
|
|
|
|
|
|
VECADD(lF[s->ij], lF[s->ij], s->f);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (!(s->type & CLOTH_SPRING_TYPE_GOAL))
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(lF[s->kl], lF[s->kl], s->f);
|
2008-02-08 00:55:48 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
sub_fmatrix_fmatrix(dFdX[s->kl].m, dFdX[s->kl].m, s->dfdx);
|
2008-02-08 00:55:48 +00:00
|
|
|
sub_fmatrix_fmatrix(dFdX[s->ij].m, dFdX[s->ij].m, s->dfdx);
|
2008-01-29 21:01:12 +00:00
|
|
|
add_fmatrix_fmatrix(dFdX[s->matrix_index].m, dFdX[s->matrix_index].m, s->dfdx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
|
|
|
|
static void CalcFloat( float *v1, float *v2, float *v3, float *n)
|
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
float n1[3], n2[3];
|
2008-08-18 11:09:27 +00:00
|
|
|
|
|
|
|
n1[0]= v1[0]-v2[0];
|
|
|
|
n2[0]= v2[0]-v3[0];
|
|
|
|
n1[1]= v1[1]-v2[1];
|
|
|
|
n2[1]= v2[1]-v3[1];
|
|
|
|
n1[2]= v1[2]-v2[2];
|
|
|
|
n2[2]= v2[2]-v3[2];
|
|
|
|
n[0]= n1[1]*n2[2]-n1[2]*n2[1];
|
|
|
|
n[1]= n1[2]*n2[0]-n1[0]*n2[2];
|
|
|
|
n[2]= n1[0]*n2[1]-n1[1]*n2[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CalcFloat4( float *v1, float *v2, float *v3, float *v4, float *n)
|
|
|
|
{
|
|
|
|
/* real cross! */
|
2012-04-29 15:47:02 +00:00
|
|
|
float n1[3], n2[3];
|
2008-08-18 11:09:27 +00:00
|
|
|
|
|
|
|
n1[0]= v1[0]-v3[0];
|
|
|
|
n1[1]= v1[1]-v3[1];
|
|
|
|
n1[2]= v1[2]-v3[2];
|
|
|
|
|
|
|
|
n2[0]= v2[0]-v4[0];
|
|
|
|
n2[1]= v2[1]-v4[1];
|
|
|
|
n2[2]= v2[2]-v4[2];
|
|
|
|
|
|
|
|
n[0]= n1[1]*n2[2]-n1[2]*n2[1];
|
|
|
|
n[1]= n1[2]*n2[0]-n1[0]*n2[2];
|
|
|
|
n[2]= n1[0]*n2[1]-n1[1]*n2[0];
|
|
|
|
}
|
|
|
|
|
2009-09-14 16:52:06 +00:00
|
|
|
static float calculateVertexWindForce(float wind[3], float vertexnormal[3])
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-03-09 06:04:17 +00:00
|
|
|
return dot_v3v3(wind, vertexnormal);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
2009-09-10 22:32:33 +00:00
|
|
|
typedef struct HairGridVert {
|
|
|
|
float velocity[3];
|
|
|
|
float density;
|
|
|
|
} HairGridVert;
|
2012-03-28 01:06:43 +00:00
|
|
|
#define HAIR_GRID_INDEX(vec, min, max, axis) (int)((vec[axis] - min[axis]) / (max[axis] - min[axis]) * 9.99f)
|
2009-09-10 22:32:33 +00:00
|
|
|
/* Smoothing of hair velocities:
|
|
|
|
* adapted from
|
2012-04-22 11:54:53 +00:00
|
|
|
* Volumetric Methods for Simulation and Rendering of Hair
|
|
|
|
* by Lena Petrovic, Mark Henne and John Anderson
|
|
|
|
* Pixar Technical Memo #06-08, Pixar Animation Studios
|
2009-09-10 22:32:33 +00:00
|
|
|
*/
|
2010-10-21 08:32:53 +00:00
|
|
|
static void hair_velocity_smoothing(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts)
|
2009-09-10 22:32:33 +00:00
|
|
|
{
|
2010-02-26 03:24:21 +00:00
|
|
|
/* TODO: This is an initial implementation and should be made much better in due time.
|
|
|
|
* What should at least be implemented is a grid size parameter and a smoothing kernel
|
|
|
|
* for bigger grids.
|
|
|
|
*/
|
2009-09-10 22:32:33 +00:00
|
|
|
|
|
|
|
/* 10x10x10 grid gives nice initial results */
|
|
|
|
HairGridVert grid[10][10][10];
|
2010-02-26 03:24:21 +00:00
|
|
|
HairGridVert colg[10][10][10];
|
2010-03-26 10:52:55 +00:00
|
|
|
ListBase *colliders = get_collider_cache(clmd->scene, NULL, NULL);
|
2010-02-26 03:24:21 +00:00
|
|
|
ColliderCache *col = NULL;
|
2009-09-10 22:32:33 +00:00
|
|
|
float gmin[3], gmax[3], density;
|
2010-02-26 03:24:21 +00:00
|
|
|
/* 2.0f is an experimental value that seems to give good results */
|
|
|
|
float smoothfac = 2.0f * clmd->sim_parms->velocity_smooth;
|
|
|
|
float collfac = 2.0f * clmd->sim_parms->collider_friction;
|
2010-10-21 08:32:53 +00:00
|
|
|
unsigned int v = 0;
|
|
|
|
unsigned int i = 0;
|
|
|
|
int j = 0;
|
|
|
|
int k = 0;
|
2009-09-10 22:32:33 +00:00
|
|
|
|
|
|
|
INIT_MINMAX(gmin, gmax);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < numverts; i++)
|
2009-09-10 22:32:33 +00:00
|
|
|
DO_MINMAX(lX[i], gmin, gmax);
|
|
|
|
|
|
|
|
/* initialize grid */
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
for (j = 0; j < 10; j++) {
|
|
|
|
for (k = 0; k < 10; k++) {
|
2009-09-10 22:32:33 +00:00
|
|
|
grid[i][j][k].velocity[0] = 0.0f;
|
|
|
|
grid[i][j][k].velocity[1] = 0.0f;
|
|
|
|
grid[i][j][k].velocity[2] = 0.0f;
|
|
|
|
grid[i][j][k].density = 0.0f;
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
colg[i][j][k].velocity[0] = 0.0f;
|
|
|
|
colg[i][j][k].velocity[1] = 0.0f;
|
|
|
|
colg[i][j][k].velocity[2] = 0.0f;
|
|
|
|
colg[i][j][k].density = 0.0f;
|
2009-09-10 22:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* gather velocities & density */
|
2012-03-24 07:52:14 +00:00
|
|
|
if (smoothfac > 0.0f) for (v = 0; v < numverts; v++) {
|
2010-02-26 03:24:21 +00:00
|
|
|
i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
|
|
|
|
j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
|
|
|
|
k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
|
2012-10-07 10:01:54 +00:00
|
|
|
if (i < 0 || j < 0 || k < 0 || i >= 10 || j >= 10 || k >= 10)
|
2010-05-25 13:33:59 +00:00
|
|
|
continue;
|
2009-09-10 22:32:33 +00:00
|
|
|
|
|
|
|
grid[i][j][k].velocity[0] += lV[v][0];
|
|
|
|
grid[i][j][k].velocity[1] += lV[v][1];
|
|
|
|
grid[i][j][k].velocity[2] += lV[v][2];
|
|
|
|
grid[i][j][k].density += 1.0f;
|
|
|
|
}
|
|
|
|
|
2010-02-26 03:24:21 +00:00
|
|
|
/* gather colliders */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (colliders && collfac > 0.0f) for (col = colliders->first; col; col = col->next) {
|
2010-02-26 03:24:21 +00:00
|
|
|
MVert *loc0 = col->collmd->x;
|
|
|
|
MVert *loc1 = col->collmd->xnew;
|
|
|
|
float vel[3];
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
for (v=0; v<col->collmd->numverts; v++, loc0++, loc1++) {
|
2010-02-26 03:24:21 +00:00
|
|
|
i = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 0);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (i>=0 && i<10) {
|
2010-02-26 03:24:21 +00:00
|
|
|
j = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 1);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (j>=0 && j<10) {
|
2010-02-26 03:24:21 +00:00
|
|
|
k = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 2);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (k>=0 && k<10) {
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(vel, loc1->co, loc0->co);
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
colg[i][j][k].velocity[0] += vel[0];
|
|
|
|
colg[i][j][k].velocity[1] += vel[1];
|
|
|
|
colg[i][j][k].velocity[2] += vel[2];
|
|
|
|
colg[i][j][k].density += 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-10 22:32:33 +00:00
|
|
|
/* divide velocity with density */
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
for (j = 0; j < 10; j++) {
|
|
|
|
for (k = 0; k < 10; k++) {
|
2009-09-10 22:32:33 +00:00
|
|
|
density = grid[i][j][k].density;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (density > 0.0f) {
|
2009-09-10 22:32:33 +00:00
|
|
|
grid[i][j][k].velocity[0] /= density;
|
|
|
|
grid[i][j][k].velocity[1] /= density;
|
|
|
|
grid[i][j][k].velocity[2] /= density;
|
|
|
|
}
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
density = colg[i][j][k].density;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (density > 0.0f) {
|
2010-02-26 03:24:21 +00:00
|
|
|
colg[i][j][k].velocity[0] /= density;
|
|
|
|
colg[i][j][k].velocity[1] /= density;
|
|
|
|
colg[i][j][k].velocity[2] /= density;
|
|
|
|
}
|
2009-09-10 22:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate forces */
|
2012-03-24 06:18:31 +00:00
|
|
|
for (v = 0; v < numverts; v++) {
|
2010-02-26 03:24:21 +00:00
|
|
|
i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
|
|
|
|
j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
|
|
|
|
k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
|
2010-05-25 13:33:59 +00:00
|
|
|
if (i < 0 || j < 0 || k < 0 || i > 10 || j >= 10 || k >= 10)
|
|
|
|
continue;
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
lF[v][0] += smoothfac * (grid[i][j][k].velocity[0] - lV[v][0]);
|
|
|
|
lF[v][1] += smoothfac * (grid[i][j][k].velocity[1] - lV[v][1]);
|
|
|
|
lF[v][2] += smoothfac * (grid[i][j][k].velocity[2] - lV[v][2]);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (colg[i][j][k].density > 0.0f) {
|
2010-02-26 03:24:21 +00:00
|
|
|
lF[v][0] += collfac * (colg[i][j][k].velocity[0] - lV[v][0]);
|
|
|
|
lF[v][1] += collfac * (colg[i][j][k].velocity[1] - lV[v][1]);
|
|
|
|
lF[v][2] += collfac * (colg[i][j][k].velocity[2] - lV[v][2]);
|
|
|
|
}
|
2009-09-10 22:32:33 +00:00
|
|
|
}
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
free_collider_cache(&colliders);
|
2009-09-10 22:32:33 +00:00
|
|
|
}
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2010-10-16 14:32:17 +00:00
|
|
|
static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M)
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
2012-04-29 15:47:02 +00:00
|
|
|
/* Collect forces and derivatives: F, dFdX, dFdV */
|
2008-01-29 21:01:12 +00:00
|
|
|
Cloth *cloth = clmd->clothObject;
|
2010-10-21 08:32:53 +00:00
|
|
|
unsigned int i = 0;
|
2008-01-29 21:01:12 +00:00
|
|
|
float spring_air = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
float gravity[3] = {0.0f, 0.0f, 0.0f};
|
2010-11-05 13:37:18 +00:00
|
|
|
float tm2[3][3] = {{0}};
|
2008-01-29 21:01:12 +00:00
|
|
|
MFace *mfaces = cloth->mfaces;
|
|
|
|
unsigned int numverts = cloth->numverts;
|
2011-01-12 03:41:12 +00:00
|
|
|
LinkNode *search;
|
2008-08-18 11:09:27 +00:00
|
|
|
lfVector *winvec;
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
EffectedPoint epoint;
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2010-11-05 13:37:18 +00:00
|
|
|
tm2[0][0]= tm2[1][1]= tm2[2][2]= -spring_air;
|
|
|
|
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
/* global acceleration (gravitation) */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(gravity, clmd->scene->physics_settings.gravity);
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
mul_fvector_S(gravity, gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); /* scale gravity force */
|
|
|
|
}
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
/* set dFdX jacobi matrix to zero */
|
|
|
|
init_bfmatrix(dFdX, ZERO);
|
|
|
|
/* set dFdX jacobi matrix diagonal entries to -spring_air */
|
|
|
|
initdiag_bfmatrix(dFdV, tm2);
|
|
|
|
|
|
|
|
init_lfvector(lF, gravity, numverts);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (clmd->sim_parms->velocity_smooth > 0.0f || clmd->sim_parms->collider_friction > 0.0f)
|
2010-02-26 03:24:21 +00:00
|
|
|
hair_velocity_smoothing(clmd, lF, lX, lV, numverts);
|
2009-09-10 22:32:33 +00:00
|
|
|
|
2008-04-09 16:38:26 +00:00
|
|
|
/* multiply lF with mass matrix
|
2012-04-22 11:54:53 +00:00
|
|
|
* force = mass * acceleration (in this case: gravity)
|
|
|
|
*/
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2008-02-03 22:37:43 +00:00
|
|
|
float temp[3];
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(temp, lF[i]);
|
2008-02-03 22:37:43 +00:00
|
|
|
mul_fmatrix_fvector(lF[i], M[i].m, temp);
|
|
|
|
}
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
submul_lfvectorS(lF, lV, spring_air, numverts);
|
|
|
|
|
|
|
|
/* handle external forces like wind */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (effectors) {
|
2008-08-18 11:09:27 +00:00
|
|
|
// 0 = force, 1 = normalized force
|
|
|
|
winvec = create_lfvector(cloth->numverts);
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (!winvec)
|
2008-08-18 11:09:27 +00:00
|
|
|
printf("winvec: out of memory in implicit.c\n");
|
|
|
|
|
|
|
|
// precalculate wind forces
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < cloth->numverts; i++) {
|
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons)
instead of each simulation having it's own gravity.
* Weight parameters for all effectors and an effector group
setting.
* Every effector can use noise.
* Most effectors have "shapes" point, plane, surface, every point.
- "Point" is most like the old effectors and uses the
effector location as the effector point.
- "Plane" uses the closest point on effectors local xy-plane
as the effector point.
- "Surface" uses the closest point on an effector object's
surface as the effector point.
- "Every Point" uses every point in a mesh effector object
as an effector point.
- The falloff is calculated from this point, so for example
with "surface" shape and "use only negative z axis" it's
possible to apply force only "inside" the effector object.
* Spherical effector is now renamed as "force" as it's no longer
just spherical.
* New effector parameter "flow", which makes the effector act as
surrounding air velocity, so the resulting force is
proportional to the velocity difference of the point and "air
velocity". For example a wind field with flow=1.0 results in
proper non-accelerating wind.
* New effector fields "turbulence", which creates nice random
flow paths, and "drag", which slows the points down.
* Much improved vortex field.
* Effectors can now effect particle rotation as well as location.
* Use full, or only positive/negative z-axis to apply force
(note. the z-axis is the surface normal in the case of
effector shape "surface")
* New "force field" submenu in add menu, which adds an empty
with the chosen effector (curve object for corve guides).
* Other dynamics should be quite easy to add to the effector
system too if wanted.
* "Unified" doesn't mean that force fields give the exact same results for
particles, softbody & cloth, since their final effect depends on many external
factors, like for example the surface area of the effected faces.
Code changes
* Subversion bump for correct handling of global gravity.
* Separate ui py file for common dynamics stuff.
* Particle settings updating is flushed with it's id through
DAG_id_flush_update(..).
Known issues
* Curve guides don't yet have all ui buttons in place, but they
should work none the less.
* Hair dynamics don't yet respect force fields.
Other changes
* Particle emission defaults now to frames 1-200 with life of 50
frames to fill the whole default timeline.
* Many particles drawing related crashes fixed.
* Sometimes particles didn't update on first frame properly.
* Hair with object/group visualization didn't work properly.
* Memory leaks with PointCacheID lists (Genscher, remember to
free pidlists after use :).
2009-09-30 22:10:14 +00:00
|
|
|
pd_point_from_loc(clmd->scene, (float*)lX[i], (float*)lV[i], i, &epoint);
|
|
|
|
pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
|
2008-08-18 11:09:27 +00:00
|
|
|
}
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < cloth->numfaces; i++) {
|
2012-04-29 15:47:02 +00:00
|
|
|
float trinormal[3]={0, 0, 0}; // normalized triangle normal
|
|
|
|
float triunnormal[3]={0, 0, 0}; // not-normalized-triangle normal
|
|
|
|
float tmp[3]={0, 0, 0};
|
2008-08-18 11:09:27 +00:00
|
|
|
float factor = (mfaces[i].v4) ? 0.25 : 1.0 / 3.0;
|
2008-08-18 19:32:21 +00:00
|
|
|
factor *= 0.02;
|
2008-08-18 11:09:27 +00:00
|
|
|
|
|
|
|
// calculate face normal
|
2012-03-24 06:18:31 +00:00
|
|
|
if (mfaces[i].v4)
|
2012-04-29 15:47:02 +00:00
|
|
|
CalcFloat4(lX[mfaces[i].v1], lX[mfaces[i].v2], lX[mfaces[i].v3], lX[mfaces[i].v4], triunnormal);
|
2008-03-09 22:55:49 +00:00
|
|
|
else
|
2012-04-29 15:47:02 +00:00
|
|
|
CalcFloat(lX[mfaces[i].v1], lX[mfaces[i].v2], lX[mfaces[i].v3], triunnormal);
|
2010-08-15 15:14:08 +00:00
|
|
|
|
|
|
|
normalize_v3_v3(trinormal, triunnormal);
|
2008-03-09 22:55:49 +00:00
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
// add wind from v1
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(tmp, trinormal);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v1], triunnormal));
|
2008-08-18 19:32:21 +00:00
|
|
|
VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], tmp, factor);
|
2008-03-09 22:55:49 +00:00
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
// add wind from v2
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(tmp, trinormal);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v2], triunnormal));
|
2008-08-18 19:32:21 +00:00
|
|
|
VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], tmp, factor);
|
2008-03-13 22:45:36 +00:00
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
// add wind from v3
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(tmp, trinormal);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v3], triunnormal));
|
2008-08-18 19:32:21 +00:00
|
|
|
VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], tmp, factor);
|
2008-03-09 22:55:49 +00:00
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
// add wind from v4
|
2012-04-28 06:31:57 +00:00
|
|
|
if (mfaces[i].v4) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(tmp, trinormal);
|
2009-11-10 20:43:45 +00:00
|
|
|
mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v4], triunnormal));
|
2008-08-18 19:32:21 +00:00
|
|
|
VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], tmp, factor);
|
2008-03-09 22:55:49 +00:00
|
|
|
}
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
/* Hair has only edges */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (cloth->numfaces == 0) {
|
2010-02-26 03:24:21 +00:00
|
|
|
ClothSpring *spring;
|
2012-04-29 15:47:02 +00:00
|
|
|
float edgevec[3]={0, 0, 0}; //edge vector
|
|
|
|
float edgeunnormal[3]={0, 0, 0}; // not-normalized-edge normal
|
|
|
|
float tmp[3]={0, 0, 0};
|
2010-02-26 03:24:21 +00:00
|
|
|
float factor = 0.01;
|
|
|
|
|
|
|
|
search = cloth->springs;
|
2012-03-24 06:18:31 +00:00
|
|
|
while (search) {
|
2010-02-26 03:24:21 +00:00
|
|
|
spring = search->link;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(edgevec, (float*)lX[spring->ij], (float*)lX[spring->kl]);
|
2010-02-26 03:24:21 +00:00
|
|
|
|
|
|
|
project_v3_v3v3(tmp, winvec[spring->ij], edgevec);
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(edgeunnormal, winvec[spring->ij], tmp);
|
2010-02-26 03:24:21 +00:00
|
|
|
/* hair doesn't stretch too much so we can use restlen pretty safely */
|
|
|
|
VECADDS(lF[spring->ij], lF[spring->ij], edgeunnormal, spring->restlen * factor);
|
|
|
|
|
|
|
|
project_v3_v3v3(tmp, winvec[spring->kl], edgevec);
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(edgeunnormal, winvec[spring->kl], tmp);
|
2010-02-26 03:24:21 +00:00
|
|
|
VECADDS(lF[spring->kl], lF[spring->kl], edgeunnormal, spring->restlen * factor);
|
|
|
|
}
|
|
|
|
|
|
|
|
search = search->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-18 11:09:27 +00:00
|
|
|
del_lfvector(winvec);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// calculate spring forces
|
|
|
|
search = cloth->springs;
|
2012-04-28 06:31:57 +00:00
|
|
|
while (search) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// only handle active springs
|
2012-08-10 00:04:15 +00:00
|
|
|
ClothSpring *spring = search->link;
|
|
|
|
if( !(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
|
|
|
|
cloth_calc_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX, time);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
|
|
|
search = search->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply spring forces
|
|
|
|
search = cloth->springs;
|
2012-04-28 06:31:57 +00:00
|
|
|
while (search) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// only handle active springs
|
2012-08-10 00:04:15 +00:00
|
|
|
ClothSpring *spring = search->link;
|
|
|
|
if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
|
|
|
|
cloth_apply_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX);
|
2008-01-29 21:01:12 +00:00
|
|
|
search = search->next;
|
|
|
|
}
|
|
|
|
// printf("\n");
|
|
|
|
}
|
|
|
|
|
2010-10-17 06:38:56 +00:00
|
|
|
static void simulate_implicit_euler(lfVector *Vnew, lfVector *UNUSED(lX), lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *UNUSED(P), fmatrix3x3 *UNUSED(Pinv), fmatrix3x3 *M, fmatrix3x3 *UNUSED(bigI))
|
2008-01-29 21:01:12 +00:00
|
|
|
{
|
|
|
|
unsigned int numverts = dFdV[0].vcount;
|
|
|
|
|
|
|
|
lfVector *dFdXmV = create_lfvector(numverts);
|
|
|
|
zero_lfvector(dV, numverts);
|
2008-02-03 22:37:43 +00:00
|
|
|
|
|
|
|
cp_bfmatrix(A, M);
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
subadd_bfmatrixS_bfmatrixS(A, dFdV, dt, dFdX, (dt*dt));
|
|
|
|
|
|
|
|
mul_bfmatrix_lfvector(dFdXmV, dFdX, lV);
|
|
|
|
|
|
|
|
add_lfvectorS_lfvectorS(B, lF, dt, dFdXmV, (dt*dt), numverts);
|
2012-09-15 01:52:28 +00:00
|
|
|
|
|
|
|
// itstart();
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
cg_filtered(dV, A, B, z, S); /* conjugate gradient algorithm to solve Ax=b */
|
2008-02-08 00:55:48 +00:00
|
|
|
// cg_filtered_pre(dV, A, B, z, S, P, Pinv, bigI);
|
2012-09-15 01:52:28 +00:00
|
|
|
|
|
|
|
// itend();
|
2008-01-29 21:01:12 +00:00
|
|
|
// printf("cg_filtered calc time: %f\n", (float)itval());
|
|
|
|
|
|
|
|
cp_lfvector(olddV, dV, numverts);
|
|
|
|
|
|
|
|
// advance velocities
|
|
|
|
add_lfvector_lfvector(Vnew, lV, dV, numverts);
|
|
|
|
|
|
|
|
|
|
|
|
del_lfvector(dFdXmV);
|
|
|
|
}
|
|
|
|
|
2012-04-22 11:54:53 +00:00
|
|
|
/* computes where the cloth would be if it were subject to perfectly stiff edges
|
|
|
|
* (edge distance constraints) in a lagrangian solver. then add forces to help
|
|
|
|
* guide the implicit solver to that state. this function is called after
|
|
|
|
* collisions*/
|
2012-09-15 01:52:28 +00:00
|
|
|
static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData * clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
|
2011-05-01 21:39:13 +00:00
|
|
|
{
|
|
|
|
Cloth *cloth= clmd->clothObject;
|
|
|
|
float (*cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "cos cloth_calc_helper_forces");
|
|
|
|
float *masses = MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
|
|
|
|
LinkNode *node;
|
|
|
|
ClothSpring *spring;
|
|
|
|
ClothVertex *cv;
|
|
|
|
int i, steps;
|
|
|
|
|
|
|
|
cv = cloth->verts;
|
|
|
|
for (i=0; i<cloth->numverts; i++, cv++) {
|
|
|
|
copy_v3_v3(cos[i], cv->tx);
|
|
|
|
|
|
|
|
if (cv->goal == 1.0f || len_v3v3(initial_cos[i], cv->tx) != 0.0) {
|
|
|
|
masses[i] = 1e+10;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-05-01 21:39:13 +00:00
|
|
|
masses[i] = cv->mass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
steps = 55;
|
|
|
|
for (i=0; i<steps; i++) {
|
|
|
|
for (node=cloth->springs; node; node=node->next) {
|
2011-09-29 15:28:22 +00:00
|
|
|
/* ClothVertex *cv1, *cv2; */ /* UNUSED */
|
2011-05-01 21:39:13 +00:00
|
|
|
int v1, v2;
|
|
|
|
float len, c, l, vec[3];
|
|
|
|
|
|
|
|
spring = node->link;
|
|
|
|
if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
v1 = spring->ij; v2 = spring->kl;
|
2011-09-29 15:28:22 +00:00
|
|
|
/* cv1 = cloth->verts + v1; */ /* UNUSED */
|
|
|
|
/* cv2 = cloth->verts + v2; */ /* UNUSED */
|
2011-05-01 21:39:13 +00:00
|
|
|
len = len_v3v3(cos[v1], cos[v2]);
|
|
|
|
|
|
|
|
sub_v3_v3v3(vec, cos[v1], cos[v2]);
|
|
|
|
normalize_v3(vec);
|
|
|
|
|
|
|
|
c = (len - spring->restlen);
|
|
|
|
if (c == 0.0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
l = c / ((1.0/masses[v1]) + (1.0/masses[v2]));
|
|
|
|
|
|
|
|
mul_v3_fl(vec, -(1.0/masses[v1])*l);
|
|
|
|
add_v3_v3(cos[v1], vec);
|
|
|
|
|
|
|
|
sub_v3_v3v3(vec, cos[v2], cos[v1]);
|
|
|
|
normalize_v3(vec);
|
|
|
|
|
|
|
|
mul_v3_fl(vec, -(1.0/masses[v2])*l);
|
|
|
|
add_v3_v3(cos[v2], vec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cv = cloth->verts;
|
|
|
|
for (i=0; i<cloth->numverts; i++, cv++) {
|
|
|
|
float vec[3];
|
|
|
|
|
|
|
|
/*compute forces*/
|
|
|
|
sub_v3_v3v3(vec, cos[i], cv->tx);
|
2011-11-14 05:55:50 +00:00
|
|
|
mul_v3_fl(vec, cv->mass*dt*20.0f);
|
2011-05-01 21:39:13 +00:00
|
|
|
add_v3_v3(cv->tv, vec);
|
|
|
|
//copy_v3_v3(cv->tx, cos[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(cos);
|
|
|
|
MEM_freeN(masses);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2012-04-29 17:11:40 +00:00
|
|
|
int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
|
2011-09-25 12:31:21 +00:00
|
|
|
{
|
2008-01-29 21:01:12 +00:00
|
|
|
unsigned int i=0;
|
2008-04-09 19:10:03 +00:00
|
|
|
float step=0.0f, tf=clmd->sim_parms->timescale;
|
2008-01-29 21:01:12 +00:00
|
|
|
Cloth *cloth = clmd->clothObject;
|
2011-05-01 21:39:13 +00:00
|
|
|
ClothVertex *verts = cloth->verts, *cv;
|
2008-01-29 21:01:12 +00:00
|
|
|
unsigned int numverts = cloth->numverts;
|
2008-04-09 16:38:26 +00:00
|
|
|
float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
|
2010-05-25 13:33:59 +00:00
|
|
|
float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
|
2011-05-01 21:39:13 +00:00
|
|
|
float (*initial_cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "initial_cos implicit.c");
|
2008-01-29 21:01:12 +00:00
|
|
|
Implicit_Data *id = cloth->implicit;
|
2010-05-25 13:33:59 +00:00
|
|
|
int do_extra_solve;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
|
2012-08-10 00:04:15 +00:00
|
|
|
|
|
|
|
/* Update vertex constraints for pinned vertices */
|
|
|
|
update_matrixS(verts, cloth->numverts, id->S);
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// update velocities with constrained velocities from pinned verts
|
2012-04-28 06:31:57 +00:00
|
|
|
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(id->V[i], verts[i].xconst, verts[i].xold);
|
2009-11-10 20:43:45 +00:00
|
|
|
// mul_v3_fl(id->V[i], clmd->sim_parms->stepsPerFrame);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-30 02:05:37 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
while (step < tf) {
|
2012-01-23 01:35:14 +00:00
|
|
|
// damping velocity for artistic reasons
|
|
|
|
mul_lfvectorS(id->V, id->V, clmd->sim_parms->vel_damping, numverts);
|
|
|
|
|
2008-02-28 18:57:14 +00:00
|
|
|
// calculate forces
|
2009-01-04 14:14:06 +00:00
|
|
|
cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M);
|
2008-02-28 18:57:14 +00:00
|
|
|
|
|
|
|
// calculate new velocity
|
2008-02-08 00:55:48 +00:00
|
|
|
simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2008-02-28 18:57:14 +00:00
|
|
|
// advance positions
|
2008-02-03 22:37:43 +00:00
|
|
|
add_lfvector_lfvectorS(id->Xnew, id->X, id->Vnew, dt, numverts);
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2008-02-28 18:57:14 +00:00
|
|
|
/* move pinned verts to correct position */
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
|
|
|
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
|
|
|
|
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
|
|
|
|
float tvect[3] = {0.0f, 0.0f, 0.0f};
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(tvect, verts[i].xconst, verts[i].xold);
|
2008-02-28 18:57:14 +00:00
|
|
|
mul_fvector_S(tvect, tvect, step+dt);
|
|
|
|
VECADD(tvect, tvect, verts[i].xold);
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(id->Xnew[i], tvect);
|
2008-02-28 18:57:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(verts[i].txold, id->X[i]);
|
2008-02-28 18:57:14 +00:00
|
|
|
}
|
2010-02-24 18:06:51 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED && clmd->clothObject->bvhtree) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// collisions
|
|
|
|
// itstart();
|
|
|
|
|
|
|
|
// update verts to current positions
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(verts[i].tx, id->Xnew[i]);
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
|
|
|
|
copy_v3_v3(verts[i].v, verts[i].tv);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2011-05-01 21:39:13 +00:00
|
|
|
for (i=0, cv=cloth->verts; i<cloth->numverts; i++, cv++) {
|
|
|
|
copy_v3_v3(initial_cos[i], cv->tx);
|
|
|
|
}
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
// call collision function
|
2008-07-02 20:28:49 +00:00
|
|
|
// TODO: check if "step" or "step+dt" is correct - dg
|
2010-05-25 13:33:59 +00:00
|
|
|
do_extra_solve = cloth_bvh_objcollision(ob, clmd, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
// copy corrected positions back to simulation
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2010-05-25 13:33:59 +00:00
|
|
|
// correct velocity again, just to be sure we had to change it due to adaptive collisions
|
2012-03-09 06:04:17 +00:00
|
|
|
sub_v3_v3v3(verts[i].tv, verts[i].tx, id->X[i]);
|
2011-05-01 21:39:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//if (do_extra_solve)
|
|
|
|
// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (do_extra_solve) {
|
2008-01-29 21:01:12 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
|
2008-02-28 23:12:50 +00:00
|
|
|
continue;
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(id->Xnew[i], verts[i].tx);
|
|
|
|
copy_v3_v3(id->Vnew[i], verts[i].tv);
|
2010-05-25 13:33:59 +00:00
|
|
|
mul_v3_fl(id->Vnew[i], spf);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// X = Xnew;
|
|
|
|
cp_lfvector(id->X, id->Xnew, numverts);
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
// if there were collisions, advance the velocity from v_n+1/2 to v_n+1
|
2008-02-28 18:57:14 +00:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (do_extra_solve) {
|
2008-01-29 21:01:12 +00:00
|
|
|
// V = Vnew;
|
|
|
|
cp_lfvector(id->V, id->Vnew, numverts);
|
2010-05-25 13:33:59 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
// calculate
|
2009-01-04 14:14:06 +00:00
|
|
|
cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M);
|
2008-03-09 22:55:49 +00:00
|
|
|
|
2008-02-08 00:55:48 +00:00
|
|
|
simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else {
|
2008-01-29 21:01:12 +00:00
|
|
|
// X = Xnew;
|
|
|
|
cp_lfvector(id->X, id->Xnew, numverts);
|
|
|
|
}
|
|
|
|
|
|
|
|
// itend();
|
|
|
|
// printf("collision time: %f\n", (float)itval());
|
|
|
|
|
|
|
|
// V = Vnew;
|
|
|
|
cp_lfvector(id->V, id->Vnew, numverts);
|
2008-02-28 18:57:14 +00:00
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
step += dt;
|
|
|
|
}
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
|
|
|
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(verts[i].txold, verts[i].xconst); // TODO: test --> should be .x
|
|
|
|
copy_v3_v3(verts[i].x, verts[i].xconst);
|
|
|
|
copy_v3_v3(verts[i].v, id->V[i]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2012-04-28 06:31:57 +00:00
|
|
|
else {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(verts[i].txold, id->X[i]);
|
|
|
|
copy_v3_v3(verts[i].x, id->X[i]);
|
|
|
|
copy_v3_v3(verts[i].v, id->V[i]);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-06 01:21:40 +00:00
|
|
|
|
2011-05-01 21:39:13 +00:00
|
|
|
MEM_freeN(initial_cos);
|
|
|
|
|
2008-01-29 21:01:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void implicit_set_positions(ClothModifierData *clmd)
|
2011-09-25 12:31:21 +00:00
|
|
|
{
|
2008-01-29 21:01:12 +00:00
|
|
|
Cloth *cloth = clmd->clothObject;
|
|
|
|
ClothVertex *verts = cloth->verts;
|
|
|
|
unsigned int numverts = cloth->numverts, i;
|
|
|
|
Implicit_Data *id = cloth->implicit;
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < numverts; i++) {
|
2012-03-09 06:04:17 +00:00
|
|
|
copy_v3_v3(id->X[i], verts[i].x);
|
|
|
|
copy_v3_v3(id->V[i], verts[i].v);
|
2008-01-29 21:01:12 +00:00
|
|
|
}
|
2012-08-08 18:21:54 +00:00
|
|
|
if (G.debug_value > 0)
|
2008-01-29 21:01:12 +00:00
|
|
|
printf("implicit_set_positions\n");
|
|
|
|
}
|
2008-01-29 23:13:31 +00:00
|
|
|
|