refactor cloth

This commit is contained in:
Irlan
2018-05-24 05:35:16 -03:00
parent 47a2c12160
commit 4ae3b7cc79
17 changed files with 1993 additions and 2635 deletions

View File

@ -60,7 +60,6 @@
#include <bounce/dynamics/cloth/cloth_mesh.h>
#include <bounce/dynamics/cloth/cloth.h>
#include <bounce/dynamics/cloth/spring_cloth.h>
#include <bounce/dynamics/body.h>

View File

@ -19,117 +19,324 @@
#ifndef B3_CLOTH_H
#define B3_CLOTH_H
#include <bounce/common/math/vec3.h>
#include <bounce/collision/collision.h>
#include <bounce/common/math/mat33.h>
#include <bounce/common/template/array.h>
#include <bounce/common/memory/stack_allocator.h>
struct b3Mesh;
// Maximum number of shapes per cloth.
#define B3_CLOTH_SHAPE_CAPACITY 32
class b3Shape;
struct b3ClothMesh;
// Cloth mesh definition
struct b3ClothDef
{
b3ClothDef()
{
mesh = NULL;
mesh = nullptr;
density = 0.0f;
gravity.SetZero();
k1 = 0.9f;
k2 = 0.2f;
kd = 0.1f;
r = 0.0f;
r = 0.05f;
ks = 0.0f;
kb = 0.0f;
kd = 0.0f;
}
// Cloth mesh
// Each edge must be shared by at most two triangles (manifold)
const b3Mesh* mesh;
// Cloth proxy mesh
b3ClothMesh* mesh;
// Cloth density in kilograms per meter squared
// Radius
// This should be a small value. It can be used for correcting visual artifacts when
// the masses are colliding against a solid.
float32 r;
// Cloth density in kg/m^3
float32 density;
// Gravity force
b3Vec3 gravity;
// Streching stiffness
float32 k1;
float32 ks;
// Bending stiffness
float32 k2;
// Damping
float32 kd;
float32 kb;
// Cloth thickness
float32 r;
// Damping stiffness
float32 kd;
};
// Static particles have zero mass and velocity, and therefore they can't move.
// Kinematic particles are't moved by external and internal forces but can be moved by contact forces.
// Dynamic particles have non-zero mass and can move due to internal and external forces.
enum b3ParticleType
{
e_staticParticle,
e_kinematicParticle,
e_dynamicParticle
};
// Read-only particle
struct b3Particle
{
float32 im;
b3Vec3 p0;
b3Vec3 p;
b3Vec3 v;
// Particle type
b3ParticleType type;
// Mass position
b3Vec3 position;
// Mass velocity
b3Vec3 velocity;
// Mass force
b3Vec3 force;
// Mass tension force for visualization
b3Vec3 tension;
// Mass
float32 mass;
// Inverse mass
float32 invMass;
// Radius
float32 radius;
// User data
void* userData;
// Translation used for direct position manipulation
b3Vec3 translation;
// Solver temp
// Identifier
u32 solverId;
// Solution
b3Vec3 x;
};
struct b3C1
// Spring types
enum b3SpringType
{
float32 L;
u32 i1;
u32 i2;
e_strechSpring,
e_bendSpring,
};
struct b3C2
// Read-only spring
struct b3Spring
{
float32 angle;
u32 i1;
u32 i2;
u32 i3;
u32 i4;
// Spring type
b3SpringType type;
// Particle 1
b3Particle* p1;
// Particle 2
b3Particle* p2;
// Rest length
float32 L0;
// Structural stiffness
float32 ks;
// Damping stiffness
float32 kd;
};
// Read-only contact
struct b3ParticleContact
{
b3Particle* p1;
b3Shape* s2;
b3Vec3 n, t1, t2;
float32 Fn, Ft1, Ft2;
bool n_active, t1_active, t2_active;
};
// A cloth represents a deformable surface/mesh.
// b3Cloth simulates this surface motion using particles and springs.
class b3Cloth
{
public:
b3Cloth();
~b3Cloth();
// Initialize this cloth from a definition.
void Initialize(const b3ClothDef& def);
void Step(float32 dt, u32 iterations);
// Return the cloth mesh used to initialize this cloth.
b3ClothMesh* GetMesh() const;
u32 GetVertexCount() const
{
return m_pCount;
}
// Set the gravitational acceleration applied to this cloth.
// Units are m/s^2.
void SetGravity(const b3Vec3& gravity);
const b3Particle* GetVertices() const
{
return m_ps;
}
// Return the gravitational acceleration applied to this cloth.
const b3Vec3& GetGravity() const;
b3Particle* GetVertices()
{
return m_ps;
}
// Return the number of particles in this cloth.
u32 GetParticleCount() const;
// Return the particle at a given index in this cloth.
b3Particle* GetParticle(u32 i) const;
// Set the type of a given particle.
void SetType(b3Particle* p, b3ParticleType type);
// Translate a particle in the next time step.
void Translate(b3Particle* p, const b3Vec3& translation);
// Set the velocity of a given particle.
void SetVelocity(b3Particle* p, const b3Vec3& velocity);
// Apply a force to a given particle.
void ApplyForce(b3Particle* p, const b3Vec3& force);
// Return the kinetic (or dynamic) energy in this system.
float32 GetEnergy() const;
// Add a collision shape to the list of shapes in this cloth.
// The cloth will be able to respond to collisions with each shape in the list of shapes.
// Current the shape will be treated as a static shape.
void AddShape(b3Shape* shape);
// Return the number of collision shapes in this cloth.
u32 GetShapeCount() const;
// Return the list of collision shapes added to this cloth.
b3Shape** GetShapeList();
// Perform a time step.
void Step(float32 dt);
// Set the positions of the mesh vertices to the positions of their associated particles.
void Apply() const;
// Debug draw the cloth using the associated cloth mesh.
void Draw() const;
private:
void SolveC1();
void SolveC2();
protected:
// Compute mass of each particle.
void ResetMass();
b3Particle* m_ps;
u32 m_pCount;
b3C1* m_c1s;
u32 m_c1Count;
b3C2* m_c2s;
u32 m_c2Count;
// Update contacts.
// This is where some contacts might be initiated or terminated.
void UpdateContacts();
// Solve
void Solve(float32 dt);
b3StackAllocator m_allocator;
float32 m_k1;
float32 m_k2;
float32 m_kd;
float32 m_r;
b3Vec3 m_gravity;
const b3Mesh* m_mesh;
u32 m_particleCount;
b3Particle* m_particles;
b3Spring* m_springs;
u32 m_springCount;
b3ParticleContact* m_contacts;
//u32 m_contactCount;
b3Shape* m_shapes[B3_CLOTH_SHAPE_CAPACITY];
u32 m_shapeCount;
b3ClothMesh* m_mesh;
float32 m_density;
};
inline b3ClothMesh* b3Cloth::GetMesh() const
{
return m_mesh;
}
inline const b3Vec3& b3Cloth::GetGravity() const
{
return m_gravity;
}
inline void b3Cloth::SetGravity(const b3Vec3& gravity)
{
m_gravity = gravity;
}
inline u32 b3Cloth::GetParticleCount() const
{
return m_particleCount;
}
inline b3Particle* b3Cloth::GetParticle(u32 i) const
{
B3_ASSERT(i < m_particleCount);
return m_particles + i;
}
inline void b3Cloth::SetType(b3Particle* p, b3ParticleType type)
{
if (p->type == type)
{
return;
}
p->type = type;
p->force.SetZero();
if (type == e_staticParticle)
{
p->velocity.SetZero();
p->translation.SetZero();
u32 ip = u32(p - m_particles);
m_contacts[ip].n_active = false;
m_contacts[ip].t1_active = false;
m_contacts[ip].t2_active = false;
}
}
inline void b3Cloth::Translate(b3Particle* p, const b3Vec3& translation)
{
p->translation += translation;
}
inline void b3Cloth::SetVelocity(b3Particle* p, const b3Vec3& velocity)
{
if (p->type == e_staticParticle)
{
return;
}
p->velocity = velocity;
}
inline void b3Cloth::ApplyForce(b3Particle* p, const b3Vec3& force)
{
if (p->type != e_dynamicParticle)
{
return;
}
p->force += force;
}
inline float32 b3Cloth::GetEnergy() const
{
float32 E = 0.0f;
for (u32 i = 0; i < m_particleCount; ++i)
{
E += m_particles[i].mass * b3Dot(m_particles[i].velocity, m_particles[i].velocity);
}
return 0.5f * E;
}
inline u32 b3Cloth::GetShapeCount() const
{
return m_shapeCount;
}
inline b3Shape** b3Cloth::GetShapeList()
{
return m_shapes;
}
#endif

View File

@ -16,48 +16,48 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_SPRING_SOLVER_H
#define B3_SPRING_SOLVER_H
#ifndef B3_CLOTH_SOLVER_H
#define B3_CLOTH_SOLVER_H
#include <bounce/common/math/vec3.h>
#include <bounce/common/math/mat33.h>
class b3Shape;
class b3SpringCloth;
class b3StackAllocator;
struct b3DenseVec3;
struct b3DiagMat33;
struct b3SparseMat33;
struct b3MassContact;
struct b3Particle;
struct b3Spring;
struct b3ParticleContact;
enum class b3MassType : u32;
class b3Shape;
class b3StackAllocator;
struct b3SpringSolverDef
struct b3ClothSolverDef
{
b3SpringCloth* cloth;
float32 dt;
b3StackAllocator* stack;
u32 particleCapacity;
u32 springCapacity;
u32 contactCapacity;
};
class b3SpringSolver
class b3ClothSolver
{
public:
b3SpringSolver(const b3SpringSolverDef& def);
b3ClothSolver(const b3ClothSolverDef& def);
~b3ClothSolver();
void Add(b3Particle* p);
void Add(b3Spring* s);
void Add(b3ParticleContact* c);
~b3SpringSolver();
void Solve(b3DenseVec3& extraForces);
u32 GetIterations() const;
void Solve(float32 dt, const b3Vec3& gravity);
private:
// Apply internal forces and store their unique derivatives.
void ApplySpringForces();
// Compute forces.
void Compute_f(b3DenseVec3& f, const b3DenseVec3& x, const b3DenseVec3& v, const b3Vec3& gravity);
// Compute A and b in Ax = b
void Compute_A_b(b3SparseMat33& A, b3DenseVec3& b) const;
void Compute_A_b(b3SparseMat33& A, b3DenseVec3& b, const b3DenseVec3& f, const b3DenseVec3& x, const b3DenseVec3& v, const b3DenseVec3& y) const;
// Compute S.
void Compute_S(b3DiagMat33& S);
@ -67,38 +67,25 @@ private:
// Solve Ax = b.
// Output x and the residual error f = Ax - b ~ 0.
void Solve(b3DenseVec3& x, b3DenseVec3& f, u32& iterations, const b3SparseMat33& A, const b3DenseVec3& b, const b3DiagMat33& S, const b3DenseVec3& z, const b3DenseVec3& y) const;
b3SpringCloth * m_cloth;
float32 m_h;
b3Mat33* m_Jx;
b3Mat33* m_Jv;
u32 m_iterations;
void Solve(b3DenseVec3& x, u32& iterations, const b3SparseMat33& A, const b3DenseVec3& b, const b3DiagMat33& S, const b3DenseVec3& z, const b3DenseVec3& y) const;
b3StackAllocator* m_allocator;
b3Vec3* m_x;
b3Vec3* m_v;
b3Vec3* m_f;
float32* m_m;
float32* m_inv_m;
b3Vec3* m_y;
b3Vec3* m_z;
b3Vec3* m_x0;
b3MassType* m_types;
u32 m_massCount;
float32 m_h;
u32 m_particleCapacity;
u32 m_particleCount;
b3Particle** m_particles;
b3MassContact* m_contacts;
b3Spring* m_springs;
u32 m_springCapacity;
u32 m_springCount;
b3Shape** m_shapes;
b3Spring** m_springs;
b3Mat33* m_Jx;
b3Mat33* m_Jv;
u32 m_contactCapacity;
u32 m_contactCount;
b3ParticleContact** m_contacts;
};
inline u32 b3SpringSolver::GetIterations() const
{
return m_iterations;
}
#endif

View File

@ -1,356 +0,0 @@
/*
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_SPRING_CLOTH_H
#define B3_SPRING_CLOTH_H
#include <bounce/common/math/mat33.h>
#include <bounce/common/template/array.h>
// Maximum number of shapes per cloth.
#define B3_CLOTH_SHAPE_CAPACITY 32
class b3StackAllocator;
class b3Shape;
struct b3ClothMesh;
struct b3SpringClothDef
{
b3SpringClothDef()
{
allocator = nullptr;
mesh = nullptr;
density = 0.0f;
ks = 0.0f;
kb = 0.0f;
kd = 0.0f;
r = 0.05f;
gravity.SetZero();
}
// Stack allocator
b3StackAllocator* allocator;
// Cloth mesh
b3ClothMesh* mesh;
// Cloth density in kg/m^3
float32 density;
// Streching stiffness
float32 ks;
// Bending stiffness
float32 kb;
// Damping stiffness
float32 kd;
// Mass radius
// This should be a small value. It can be used for correcting visual artifacts when
// the masses are colliding against a solid.
float32 r;
// Acceleration due to gravity (m/s^2)
b3Vec3 gravity;
};
enum b3SpringType
{
e_strechSpring,
e_bendSpring,
// e_sewingSpring
};
struct b3Spring
{
// Spring type
b3SpringType type;
// Mass 1
u32 i1;
// Mass 2
u32 i2;
// Rest length
float32 L0;
// Structural stiffness
float32 ks;
// Damping stiffness
float32 kd;
};
// Static masses have zero mass and velocity, and therefore they can't move.
// Kinematic masses are't moved by external and internal forces but can be moved by contact forces.
// Dynamic masses have non-zero mass and can move due to internal and external forces.
enum class b3MassType : u32
{
e_staticMass,
e_kinematicMass,
e_dynamicMass
};
//
struct b3MassContact
{
u32 j;
b3Vec3 n, t1, t2;
float32 Fn, Ft1, Ft2;
bool lockN, lockT1, lockT2;
};
// Time step statistics
struct b3SpringClothStep
{
u32 iterations;
};
// A cloth it treats cloth as a collection of masses connected by springs.
// Large time steps can be taken.
// If accuracy and stability are required, not performance,
// you can use this class instead of using b3Cloth.
class b3SpringCloth
{
public:
b3SpringCloth();
~b3SpringCloth();
// Initialize this cloth from a definition.
void Initialize(const b3SpringClothDef& def);
// Return the cloth mesh used to initialize this cloth.
b3ClothMesh* GetMesh() const;
// Set the gravitational acceleration applied to this cloth.
// Units are m/s^2.
void SetGravity(const b3Vec3& gravity);
// Return the number of masses in this cloth.
u32 GetMassCount() const;
// Return the gravitational acceleration applied to this cloth.
const b3Vec3& GetGravity() const;
// Set the type of a given point mass.
void SetType(u32 i, b3MassType type);
// Return the type of a given point mass.
b3MassType GetType(u32 i) const;
// Set the position of a given point mass.
// This function will have effect on the position of the point mass
// after performing a time step.
void SetPosition(u32 i, const b3Vec3& position);
// Return the position of a given point mass.
const b3Vec3& GetPosition(u32 i) const;
// Set the velocity of a given point mass.
void SetVelocity(u32 i, const b3Vec3& velocity);
// Return the velocity of a given point mass.
const b3Vec3& GetVelocity(u32 i) const;
// Apply a force to a given point mass.
void ApplyForce(u32 i, const b3Vec3& force);
// Return the kinetic (or dynamic) energy in this system.
float32 GetEnergy() const;
// Return the tension forces (due to springs) acting at each point mass.
// Units are kg * m / s^2
void GetTension(b3Array<b3Vec3>& tensions) const;
// Add a shape to the list of shapes in this cloth.
// The cloth will be able to respond to collisions with each shape in the list of shapes.
void AddShape(b3Shape* shape);
// Return the number of shapes added to this cloth.
u32 GetShapeCount() const;
// Return the list of shapes added to this cloth.
b3Shape** GetShapes();
// Return the statistics of the last time step.
const b3SpringClothStep& GetStep() const;
// Perform a time step (marches time forward).
void Step(float32 dt);
// Set the positions of the mesh vertices to the positions of their associated point masses.
void Apply() const;
// Debug draw the cloth mesh.
void Draw() const;
protected:
friend class b3SpringSolver;
// Update contacts.
// This is where some contacts might be initiated or terminated.
void UpdateContacts();
b3StackAllocator* m_allocator;
b3ClothMesh* m_mesh;
float32 m_r;
b3Vec3 m_gravity;
b3Vec3* m_x;
b3Vec3* m_v;
b3Vec3* m_f;
float32* m_m;
float32* m_inv_m;
b3Vec3* m_y;
b3Vec3* m_z;
b3Vec3* m_x0;
b3MassType* m_types;
u32 m_massCount;
b3MassContact* m_contacts;
b3Spring* m_springs;
u32 m_springCount;
b3Shape* m_shapes[B3_CLOTH_SHAPE_CAPACITY];
u32 m_shapeCount;
b3SpringClothStep m_step;
};
inline b3ClothMesh* b3SpringCloth::GetMesh() const
{
return m_mesh;
}
inline const b3Vec3& b3SpringCloth::GetGravity() const
{
return m_gravity;
}
inline void b3SpringCloth::SetGravity(const b3Vec3& gravity)
{
m_gravity = gravity;
}
inline u32 b3SpringCloth::GetMassCount() const
{
return m_massCount;
}
inline b3MassType b3SpringCloth::GetType(u32 i) const
{
B3_ASSERT(i < m_massCount);
return m_types[i];
}
inline void b3SpringCloth::SetType(u32 i, b3MassType type)
{
B3_ASSERT(i < m_massCount);
if (m_types[i] == type)
{
return;
}
m_types[i] = type;
m_f[i].SetZero();
if (type == b3MassType::e_staticMass)
{
m_v[i].SetZero();
m_y[i].SetZero();
m_contacts[i].lockN = false;
}
}
inline void b3SpringCloth::SetPosition(u32 i, const b3Vec3& position)
{
B3_ASSERT(i < m_massCount);
m_y[i] += position - m_x[i];
}
inline const b3Vec3& b3SpringCloth::GetPosition(u32 i) const
{
B3_ASSERT(i < m_massCount);
return m_x[i];
}
inline void b3SpringCloth::SetVelocity(u32 i, const b3Vec3& velocity)
{
B3_ASSERT(i < m_massCount);
if (m_types[i] == b3MassType::e_staticMass)
{
return;
}
m_v[i] = velocity;
}
inline const b3Vec3& b3SpringCloth::GetVelocity(u32 i) const
{
B3_ASSERT(i < m_massCount);
return m_v[i];
}
inline void b3SpringCloth::ApplyForce(u32 i, const b3Vec3& force)
{
B3_ASSERT(i < m_massCount);
if (m_types[i] != b3MassType::e_dynamicMass)
{
return;
}
m_f[i] += force;
}
inline float32 b3SpringCloth::GetEnergy() const
{
float32 E = 0.0f;
for (u32 i = 0; i < m_massCount; ++i)
{
E += m_m[i] * b3Dot(m_v[i], m_v[i]);
}
return 0.5f * E;
}
inline u32 b3SpringCloth::GetShapeCount() const
{
return m_shapeCount;
}
inline b3Shape** b3SpringCloth::GetShapes()
{
return m_shapes;
}
inline const b3SpringClothStep& b3SpringCloth::GetStep() const
{
return m_step;
}
#endif