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:
Daniel Genrich
2007-11-06 02:30:53 +00:00
parent 873a26ff84
commit 47c62453db
5 changed files with 101 additions and 191 deletions

View File

@@ -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 */

View File

@@ -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 );

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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;