Bugfix for wrong springs (resulted in weird behaviour), Implemented two speedups: One for small bending/wrinkle values (1/3 speedup), another speedup is that cloth get automatically in sleep mode but wakes up every frame ([quality-1]/quality speedup)
This commit is contained in:
@@ -86,7 +86,9 @@ typedef enum
|
||||
CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ), // object is only collision object, no cloth simulation is done
|
||||
CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled
|
||||
CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ), // true if tearing is enabled
|
||||
CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ), // true if tearing is enabled
|
||||
CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ),
|
||||
CLOTH_SIMSETTINGS_FLAG_BIG_FORCE = ( 1 << 6 ), // true if we have big spring force for bending
|
||||
CLOTH_SIMSETTINGS_FLAG_SLEEP = ( 1 << 7 ), // true if we let the cloth go to sleep
|
||||
} CLOTH_SIMSETTINGS_FLAGS;
|
||||
|
||||
/* SPRING FLAGS */
|
||||
|
||||
@@ -114,7 +114,7 @@ double tval()
|
||||
static CM_SOLVER_DEF solvers [] =
|
||||
{
|
||||
{ "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free },
|
||||
{ "Verlet", CM_VERLET, verlet_init, verlet_solver, verlet_free },
|
||||
// { "Verlet", CM_VERLET, verlet_init, verlet_solver, verlet_free },
|
||||
};
|
||||
|
||||
/* ********** cloth engine ******* */
|
||||
@@ -504,8 +504,9 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *d
|
||||
// if(!cloth_cache_search_frame(clmd, framenr))
|
||||
{
|
||||
verts = cloth->verts;
|
||||
/*
|
||||
|
||||
// Force any pinned verts to their constrained location.
|
||||
// has to be commented for verlet
|
||||
for ( i = 0; i < clmd->clothObject->numverts; i++, verts++ )
|
||||
{
|
||||
// Save the previous position.
|
||||
@@ -515,7 +516,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *d
|
||||
VECCOPY ( verts->xconst, mvert[i].co );
|
||||
Mat4MulVecfl ( ob->obmat, verts->xconst );
|
||||
}
|
||||
*/
|
||||
|
||||
tstart();
|
||||
|
||||
/* Call the solver. */
|
||||
@@ -1031,8 +1032,8 @@ int cloth_build_springs ( Cloth *cloth, DerivedMesh *dm )
|
||||
{
|
||||
spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
|
||||
|
||||
spring->ij = mface[i].v1;
|
||||
spring->kl = mface[i].v3;
|
||||
spring->ij = mface[i].v2;
|
||||
spring->kl = mface[i].v4;
|
||||
VECSUB ( temp, mvert[spring->kl].co, mvert[spring->ij].co );
|
||||
spring->restlen = sqrt ( INPR ( temp, temp ) );
|
||||
spring->type = CLOTH_SPRING_TYPE_SHEAR;
|
||||
@@ -1045,7 +1046,7 @@ int cloth_build_springs ( Cloth *cloth, DerivedMesh *dm )
|
||||
node = node2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// bending springs
|
||||
search2 = cloth->springs;
|
||||
for ( i = struct_springs; i < struct_springs+shear_springs; i++ )
|
||||
@@ -1083,9 +1084,10 @@ int cloth_build_springs ( Cloth *cloth, DerivedMesh *dm )
|
||||
}
|
||||
search2 = search2->next;
|
||||
}
|
||||
|
||||
cloth->numsprings = struct_springs + shear_springs + bend_springs;
|
||||
|
||||
|
||||
cloth->numspringssave = cloth->numsprings = struct_springs + shear_springs + bend_springs;
|
||||
cloth->numothersprings = struct_springs + shear_springs;
|
||||
|
||||
for ( i = 0; i < numverts; i++ )
|
||||
{
|
||||
BLI_linklist_free ( edgelist[i],NULL );
|
||||
|
||||
@@ -812,6 +812,31 @@ int implicit_free (ClothModifierData *clmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cloth_bending_mode(ClothModifierData *clmd, int enabled)
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
Implicit_Data *id;
|
||||
|
||||
if(cloth)
|
||||
{
|
||||
id = cloth->implicit;
|
||||
|
||||
if(id)
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
cloth->numsprings = cloth->numspringssave;
|
||||
}
|
||||
else
|
||||
{
|
||||
cloth->numsprings = cloth->numothersprings;
|
||||
}
|
||||
|
||||
id->A[0].scount = id->dFdV[0].scount = id->dFdX[0].scount = id->P[0].scount = id->Pinv[0].scount = id->bigI[0].scount = cloth->numsprings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DO_INLINE float fb(float length, float L)
|
||||
{
|
||||
float x = length/L;
|
||||
@@ -1223,37 +1248,48 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
|
||||
{
|
||||
if(length < L)
|
||||
{
|
||||
// clmd->sim_parms.flags |= CLOTH_SIMSETTINGS_FLAG_BIG_FORCE;
|
||||
|
||||
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
|
||||
|
||||
k = clmd->sim_parms.bending;
|
||||
|
||||
mul_fvector_S(bending_force, dir, fbstar(length, L, k, cb));
|
||||
VECADD(s->f, s->f, bending_force);
|
||||
|
||||
|
||||
if(INPR(bending_force,bending_force) > 0.13*0.13)
|
||||
{
|
||||
clmd->sim_parms.flags |= CLOTH_SIMSETTINGS_FLAG_BIG_FORCE;
|
||||
}
|
||||
|
||||
dfdx_spring_type2(s->dfdx, dir,length,L,k, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DO_INLINE void cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *lF, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX)
|
||||
DO_INLINE int cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *lF, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX)
|
||||
{
|
||||
if(s->flags & CLOTH_SPRING_FLAG_NEEDED)
|
||||
{
|
||||
VECADD(lF[s->ij], lF[s->ij], s->f);
|
||||
VECSUB(lF[s->kl], lF[s->kl], s->f);
|
||||
|
||||
if(s->type != CLOTH_SPRING_TYPE_BENDING)
|
||||
{
|
||||
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);
|
||||
VECSUB(lF[s->kl], lF[s->kl], s->f);
|
||||
|
||||
else if(!(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_BIG_FORCE))
|
||||
return 0;
|
||||
|
||||
sub_fmatrix_fmatrix(dFdX[s->ij].m, dFdX[s->ij].m, s->dfdx);
|
||||
sub_fmatrix_fmatrix(dFdX[s->kl].m, dFdX[s->kl].m, s->dfdx);
|
||||
|
||||
add_fmatrix_fmatrix(dFdX[s->matrix_index].m, dFdX[s->matrix_index].m, s->dfdx);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
DO_INLINE void calculateTriangleNormal(float to[3], lfVector *X, MFace mface)
|
||||
@@ -1386,15 +1422,34 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec
|
||||
search = search->next;
|
||||
}
|
||||
|
||||
if(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_BIG_FORCE)
|
||||
{
|
||||
if(cloth->numspringssave != cloth->numsprings)
|
||||
{
|
||||
cloth_bending_mode(clmd, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cloth->numspringssave == cloth->numsprings)
|
||||
{
|
||||
cloth_bending_mode(clmd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// apply spring forces
|
||||
search = cloth->springs;
|
||||
while(search)
|
||||
{
|
||||
// only handle active springs
|
||||
// if(((clmd->sim_parms.flags & CSIMSETT_FLAG_TEARING_ENABLED) && !(springs[i].flags & CSPRING_FLAG_DEACTIVATE))|| !(clmd->sim_parms.flags & CSIMSETT_FLAG_TEARING_ENABLED))
|
||||
cloth_apply_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX);
|
||||
if(!cloth_apply_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX))
|
||||
break;
|
||||
search = search->next;
|
||||
}
|
||||
|
||||
clmd->sim_parms.flags &= ~CLOTH_SIMSETTINGS_FLAG_BIG_FORCE;
|
||||
|
||||
}
|
||||
|
||||
void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *P, fmatrix3x3 *Pinv)
|
||||
@@ -1438,6 +1493,8 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
|
||||
float dt = 1.0f / clmd->sim_parms.stepsPerFrame;
|
||||
Implicit_Data *id = cloth->implicit;
|
||||
int result = 0;
|
||||
float force = 0, lastforce = 0;
|
||||
lfVector *dx;
|
||||
|
||||
if(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL) /* do goal stuff */
|
||||
{
|
||||
@@ -1457,10 +1514,27 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
|
||||
effectors= pdInitEffectors(ob,NULL);
|
||||
|
||||
// calculate
|
||||
cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step );
|
||||
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);
|
||||
cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step );
|
||||
|
||||
add_lfvector_lfvectorS(id->Xnew, id->X, id->Vnew, dt, numverts);
|
||||
// check for sleeping
|
||||
if(!(clmd->coll_parms.flags & CLOTH_SIMSETTINGS_FLAG_SLEEP))
|
||||
{
|
||||
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);
|
||||
|
||||
add_lfvector_lfvectorS(id->Xnew, id->X, id->Vnew, dt, numverts);
|
||||
}
|
||||
|
||||
dx = create_lfvector(numverts);
|
||||
sub_lfvector_lfvector(dx, id->Xnew, id->X, numverts);
|
||||
force = dot_lfvector(dx, dx, numverts);
|
||||
del_lfvector(dx);
|
||||
|
||||
if((force < 0.00001) && (lastforce >= force))
|
||||
clmd->coll_parms.flags |= CLOTH_SIMSETTINGS_FLAG_SLEEP;
|
||||
else if((lastforce*2 < force))
|
||||
clmd->coll_parms.flags &= ~CLOTH_SIMSETTINGS_FLAG_SLEEP;
|
||||
|
||||
lastforce = force;
|
||||
|
||||
if(clmd->coll_parms.flags & CLOTH_COLLISIONSETTINGS_FLAG_ENABLED)
|
||||
{
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
/* implicit.c
|
||||
*
|
||||
*
|
||||
* ***** BEGIN GPL/BL DUAL 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. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* about this.
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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/BL DUAL LICENSE BLOCK *****
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "MEM_guardedalloc.h"
|
||||
/* types */
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_object_force.h"
|
||||
#include "DNA_cloth_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BKE_collisions.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_displist.h"
|
||||
#include "BKE_effect.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_cloth.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BIF_editdeform.h"
|
||||
|
||||
struct Cloth;
|
||||
|
||||
int verlet_init ( Object *ob, ClothModifierData *clmd )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int verlet_free ( ClothModifierData *clmd )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void integrate ( ClothModifierData *clmd, float dt )
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
unsigned int i = 0;
|
||||
|
||||
// temporary vectors
|
||||
float temp[3], velocity[3], force[3];
|
||||
|
||||
mul_fvector_S( force, clmd->sim_parms.gravity, dt*dt );
|
||||
|
||||
// iterate through all control points
|
||||
for(i = 0; i < cloth->numverts; i++)
|
||||
{
|
||||
if(((clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (cloth->verts [i].goal < SOFTGOALSNAP)) || !(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL))
|
||||
{
|
||||
// save current control point location
|
||||
VECCOPY ( temp, cloth->x[i] );
|
||||
|
||||
// update control point by the formula
|
||||
// x += (x - old_x)*dampingFactor + force*timeStep^2
|
||||
VECSUB ( velocity, cloth->x[i], cloth->xold[i] );
|
||||
VECSUBMUL( force, velocity, -clmd->sim_parms.Cvi * 0.01f* dt * dt);
|
||||
VecMulf(velocity, 0.99);
|
||||
VECADD ( cloth->x[i], cloth->x[i], velocity );
|
||||
VECADD ( cloth->x[i], cloth->x[i], force );
|
||||
|
||||
// store old control point location
|
||||
VECCOPY ( cloth->xold[i], temp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void satisfyconstraints(ClothModifierData *clmd)
|
||||
{
|
||||
float delta[3];
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
unsigned int i = 0;
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
// calculate spring forces
|
||||
LinkNode *search = cloth->springs;
|
||||
while(search)
|
||||
{
|
||||
ClothSpring *spring = search->link;
|
||||
float temp = 0;
|
||||
float restlen2 = spring->restlen * spring->restlen;
|
||||
float len2 = 0, len = 0;
|
||||
|
||||
VECSUB(delta, cloth->x[spring->kl], cloth->x[spring->ij]);
|
||||
len = sqrt(INPR(delta, delta));
|
||||
|
||||
if(spring->type != CLOTH_SPRING_TYPE_BENDING)
|
||||
{
|
||||
temp = (len - spring->restlen)/len;
|
||||
|
||||
mul_fvector_S(delta, delta, temp*0.5);
|
||||
|
||||
// check if vertex is pinned
|
||||
if(((clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (cloth->verts [spring->ij].goal < SOFTGOALSNAP)) || !(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL))
|
||||
VECADD(cloth->x[spring->ij], cloth->x[spring->ij], delta);
|
||||
|
||||
// check if vertex is pinned
|
||||
if(((clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (cloth->verts [spring->kl].goal < SOFTGOALSNAP)) || !(clmd->sim_parms.flags & CLOTH_SIMSETTINGS_FLAG_GOAL))
|
||||
VECSUB(cloth->x[spring->kl], cloth->x[spring->kl], delta);
|
||||
}
|
||||
|
||||
search = search->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int verlet_solver ( Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors )
|
||||
{
|
||||
float dt = 0.01;
|
||||
float step = 0;
|
||||
|
||||
while(step < 1.0f)
|
||||
{
|
||||
integrate(clmd, dt);
|
||||
satisfyconstraints(clmd);
|
||||
|
||||
step+= dt;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ typedef struct Cloth
|
||||
float (*v)[3]; /* the current velocity of all vertices */
|
||||
float (*current_v)[3];
|
||||
struct EdgeHash *edgehash; // used for fast checking adjacent points
|
||||
unsigned int numothersprings;
|
||||
unsigned int numspringssave;
|
||||
}
|
||||
Cloth;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user