/** * ***** 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) 2006 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): Daniel Genrich (Genscher) * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #include #include #include // For time() #include // For srand() and rand() #include "cloth_extern.h" #include "vec3n.h" #include "vecmath.h" #include "LinearMath/btVector3.h" #include "LinearMath/btScalar.h" #include "LinearMath/btMatrix3x3.h" #include "LinearMath/btTransform.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btPointCollector.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa.h" #include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "LinearMath/btStackAlloc.h" /* #include #include "MT_Point3.h" #include "MT_Vector3.h" */ // #include "vclip.h" #include #include #define SPRING_STRUCT (0) #define SPRING_SHEAR (1) #define SPRING_BEND (2) static const float3x3 I(1,0,0,0,1,0,0,0,1); #define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);} #define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);} #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);} #define VECCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);} #define INPR(v1, v2) ( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] ) float Normalise(float *n) { float d; d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; /* A larger value causes normalise errors in a scaled down models with camera xtreme close */ if(d>1.0e-35F) { d= (float)sqrt(d); n[0]/=d; n[1]/=d; n[2]/=d; } else { n[0]=n[1]=n[2]= 0.0; d= 0.0; } return d; } void VecMulf(float *v1, float f) { v1[0]*= f; v1[1]*= f; v1[2]*= f; } using namespace std; inline float3x3 dfdx_spring(const float3 &dir,float length,float rest,float k) { // dir is unit length direction, rest is spring's restlength, k is spring constant. return ( (I-outerprod(dir,dir))*Min(1.0f,rest/length) - I) * -k; } inline float3x3 dfdx_damp(const float3 &dir,float length,const float3& vel,float rest,float damping) { // inner spring damping vel is the relative velocity of the endpoints. return (I-outerprod(dir,dir)) * (-damping * -(dot(dir,vel)/Max(length,rest))); } inline float3x3 dfdv_damp(const float3 &dir,float damping) { // derivative of force wrt velocity. return outerprod(dir,dir) * damping; } SpringNetwork::SpringNetwork(int _n):X(_n),V(_n),Xold(_n),Vold(_n),Xold2(_n),Vold2(_n),F(_n),dX(_n),z(_n),olddV(_n),A(_n),dFdX(_n),dFdV(_n),M(_n) { assert(SPRING_STRUCT==0); assert(&spring_shear == &spring_struct +SPRING_SHEAR); assert(&spring_bend == &spring_struct +SPRING_BEND); assert(&spring_struct== &spring_k[SPRING_STRUCT]); assert(&spring_shear == &spring_k[SPRING_SHEAR ]); assert(&spring_bend == &spring_k[SPRING_BEND ]); spring_struct=1000.0f; spring_shear=100.0f; spring_bend=25.0f; spring_damp=5.0f; spring_air=1.0f; cb = 200 * spring_bend; cf = 0.01; csf = 0.01; cloth_gravity=float3(0,0,-9.81); // gravity is meters per sec^2 step = 1; dtold = 0; } SpringNetwork::Spring &SpringNetwork::AddBlocks(Spring &s) { /* if(s.type==SPRING_BEND) return s; */ // Called during initial creation of springs in our spring network. // Sets up the sparse matrices corresponding to connections. // Note the indices (s.iab,s.iba) are also stored with spring to avoid looking them up each time a spring is applied // All 3 matrices A,dFdX, and dFdV are contstructed identically so the block array layout will be the same for each. s.iab = A.blocks.count; // added 'ab' blocks will have this index. A.blocks.Add(Block(s.a,s.b)); dFdX.blocks.Add(Block(s.a,s.b)); dFdV.blocks.Add(Block(s.a,s.b)); s.iba = A.blocks.count; // added 'ba' blocks will have this index. A.blocks.Add(Block(s.b,s.a)); dFdX.blocks.Add(Block(s.b,s.a)); dFdV.blocks.Add(Block(s.b,s.a)); return s; } void Zero(float3x3 &m) { m.x.x = m.y.y = m.z.z = m.x.y = m.x.z = m.y.x = m.y.z = m.z.x = m.z.y = 0; } void SpringNetwork::PreSolveSpring(const SpringNetwork::Spring &s, float3N &cX, float3N &cV) { // DO IT HERE } void SpringNetwork::CalcForces(ClothVertex *extforce, float3N &cX, float3N &cV) { // Collect forces and derivatives: F,dFdX,dFdV dFdX.Zero(); dFdV.InitDiagonal(-spring_air); F.Init(cloth_gravity); if(extforce) { for(int i=0;i=0 ; i--) { while((ispring_damp = simsettings->Cdis * 0.01; // mechanical spring damping cloth->spring_air = simsettings->Cvi * 0.01; // viscous spring damping cloth->cloth_gravity[0] = simsettings->gravity[0]; cloth->cloth_gravity[1] = simsettings->gravity[1]; cloth->cloth_gravity[2] = simsettings->gravity[2]; // gravity cloth->spring_struct = simsettings->structural; // spring_struct=1000.0f; cloth->spring_shear = simsettings->shear; // spring_shear=100.0f; cloth->spring_bend = simsettings->flexion; // spring_bend=25.0f; cloth->cb = 20000 * cloth->spring_bend; // bei 2000 * bending => 500 - 1000 struct/shear = viele Falten, 3000 = wenig/keine Falten cloth->weight = simsettings->mass; cloth->epsilon = collsettings->epsilon; cloth->cf = collsettings->friction * 0.01; // friction cloth->csf = collsettings->self_friction * 0.01; // selffriction // 2. copy cloth positions for(int i = 0; i < numberV; i++) { cloth->X[i] = float3(source[i].v[0], source[i].v[1], source[i].v[2]); cloth->Xold[i] = float3(source[i].v[0], source[i].v[1], source[i].v[2]); if(source [i].flags & CVERT_FLAG_PINNED) { cloth->S.blocks.Add(Block(i,i)).m=float3x3(0,0,0,0,0,0,0,0,0); cloth->S.blocks[cloth->S.blocks.count-1].ndof = 0; cloth->S.blocks[cloth->S.blocks.count-1].pinned = 1; } } // 3. copy springs for (int i = 0; i < numberS; i++) { switch (springs [i].type) { case STRUCTURAL: cloth->CreateSpring(SPRING_STRUCT,springs [i].ij,springs [i].kl); break; case SHEAR: cloth->CreateSpring(SPRING_SHEAR,springs [i].ij,springs [i].kl); break; case FLEXION: cloth->CreateSpring(SPRING_BEND,springs [i].ij,springs [i].kl); break; } } cloth-> BuildM(numberV); return cloth; } extern "C" void setupzOfClothNetwork(SpringNetwork *cloth, ClothVertex *source, int numberV, float dt) { // apply velocity of the pinned verteces for(int i = 0; i < numberV; i++) { if(source [i].flags & CVERT_FLAG_PINNED) { float3 tempa(source [i].v[0], source [i].v[1], source [i].v[2]); float3 tempb(source [i].prevV[0], source [i].prevV[1], source [i].prevV[2]); cloth->z[i]= (tempa - tempb) * dt; } } } extern "C" void copyToClothNetwork(SpringNetwork *cloth, ClothVertex *source, int numberV, ClothSpring *springs, int numberS) { if(!cloth) return; // TODO // check if width*height == numberV // 1. copy cloth positions for(int i = 0; i < numberV; i++) { cloth->X[i] = float3(source[i].v[0], source[i].v[1], source[i].v[2]); cloth->Xold[i] = float3(source[i].v[0], source[i].v[1], source[i].v[2]); } // 2. copy springs for (int i = 0; i < numberS; i++) { switch (springs [i].type) { case STRUCTURAL: cloth->CreateSpring(SPRING_STRUCT,springs [i].ij,springs [i].kl); break; case SHEAR: cloth->CreateSpring(SPRING_SHEAR,springs [i].ij,springs [i].kl); break; case FLEXION: cloth->CreateSpring(SPRING_BEND,springs [i].ij,springs [i].kl); break; } } // 3. copy settings // TODO } extern "C" void copyFromClothNetwork(SpringNetwork *cloth, ClothVertex *source, int numberV) { if(!cloth) return; // 1. copy cloth positions for(int i = 0; i < numberV; i++) { source[i].v[0] = (cloth->X[i])[0]; source[i].v[1] = (cloth->X[i])[1]; source[i].v[2] = (cloth->X[i])[2]; } } extern "C" void deleteClothNetwork(SpringNetwork *cloth) { if(cloth) { delete cloth; cloth = NULL; } } extern "C" void simulateClothNetwork(SpringNetwork *clothNetwork, float timestep, ClothVertex *extforce, ClothModifierData *clmd, CM_COLLISION_SELF self_collision, CM_COLLISION_OBJ obj_collision, ClothVertex *source) { if(!clothNetwork) return; clothNetwork->advanceStep(timestep, extforce, clmd, self_collision, obj_collision, source); } extern "C" int getStepFromClothNetwork(SpringNetwork *cloth) { if(!cloth) return -1; return cloth->step; } extern "C" void setStepFromClothNetwork(SpringNetwork *cloth, int step) { if(!cloth) return; cloth->step = step; }