maintain the upper triangle of A, external particle/force creation/destruction, particle force abstraction, testbed update

This commit is contained in:
Irlan
2018-05-30 11:34:41 -03:00
parent dba5ffbe06
commit caef3fede8
21 changed files with 1657 additions and 1088 deletions

View File

@ -58,18 +58,17 @@
#include <bounce/dynamics/rope/rope.h>
#include <bounce/garment/sewing_pattern.h>
#include <bounce/garment/garment.h>
#include <bounce/garment/garment_mesh.h>
#include <bounce/dynamics/cloth/cloth_mesh.h>
#include <bounce/dynamics/cloth/cloth.h>
#include <bounce/dynamics/cloth/particle.h>
#include <bounce/dynamics/cloth/spring_force.h>
#include <bounce/dynamics/body.h>
//#include <bounce/dynamics/tree/joints/tree_weld_joint.h>
//#include <bounce/dynamics/tree/joints/tree_prismatic_joint.h>
//#include <bounce/dynamics/tree/joints/tree_revolute_joint.h>
//#include <bounce/dynamics/tree/joints/tree_spherical_joint.h>
//#include <bounce/dynamics/tree/tree_body.h>
//#include <bounce/dynamics/tree/body_tree.h>
#include <bounce/dynamics/world.h>
#include <bounce/dynamics/world_listeners.h>

View File

@ -21,153 +21,66 @@
#include <bounce/common/math/transform.h>
#include <bounce/common/template/list.h>
#include <bounce/common/memory/block_pool.h>
class b3StackAllocator;
class b3World;
class b3Shape;
class b3Particle;
class b3Force;
struct b3ParticleDef;
struct b3ForceDef;
struct b3ClothMesh;
// Cloth mesh definition
struct b3RayCastInput;
struct b3ClothRayCastOutput
{
u32 triangle; // intersected triangle
b3Vec3 point; // intersection point on surface
b3Vec3 normal; // surface normal of intersection
float32 fraction; // time of intersection on segment
};
// Cloth definition
// This requires defining a cloth mesh which is typically bound to a render mesh
struct b3ClothDef
{
b3ClothDef()
{
mesh = nullptr;
density = 0.0f;
r = 0.05f;
ks = 0.0f;
kb = 0.0f;
kd = 0.0f;
radius = 0.05f;
structural = 0.0f;
bending = 0.0f;
damping = 0.0f;
}
// Cloth proxy mesh
// Cloth mesh
b3ClothMesh* mesh;
// 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;
float32 radius;
// Cloth density in kg/m^3
float32 density;
// Streching stiffness
float32 ks;
// Structural stiffness
float32 structural;
// Bending stiffness
float32 kb;
float32 bending;
// Damping stiffness
float32 kd;
float32 damping;
};
// Static particle: Has zero mass, can be moved manually.
// Kinematic particle: Has zero mass, non-zero velocity, can be moved by the solver.
// Dynamic particle: Has non-zero mass, non-zero velocity determined by force, can be moved by the solver.
enum b3ParticleType
{
e_staticParticle,
e_kinematicParticle,
e_dynamicParticle
};
// Read-only particle
struct b3Particle
{
// Type
b3ParticleType type;
// Position
b3Vec3 position;
// Velocity
b3Vec3 velocity;
// Applied external force
b3Vec3 force;
// Mass
float32 mass;
// Inverse mass
float32 invMass;
// Radius
float32 radius;
// User data.
void* userData;
// Applied external translation
b3Vec3 translation;
// Solver temp
// Identifier
u32 solverId;
// Solution
b3Vec3 x;
};
// Spring types
enum b3SpringType
{
e_strechSpring,
e_bendSpring,
};
struct b3ClothSolverData;
// Read-only spring
struct b3Spring
{
// Solver shared
// Spring type
b3SpringType type;
// Particle 1
b3Particle* p1;
// Particle 2
b3Particle* p2;
// Rest length
float32 L0;
// Structural stiffness
float32 ks;
// Damping stiffness
float32 kd;
// Solver temp
// Force (f_i entry)
b3Vec3 f;
// Jacobian (J_ii entry)
b3Mat33 Jx, Jv;
// Initialize forces and its derivatives.
void InitializeForces(const b3ClothSolverData* data);
};
// Read-only body contact between a particle and a solid
struct b3BodyContact
{
b3Particle* p1;
b3Shape* s2;
float32 s;
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.
// A cloth represents a deformable surface as a collection of particles.
// Particles may be connected with each other.
class b3Cloth
{
public:
@ -175,37 +88,33 @@ public:
const b3World* GetWorld() const;
b3World* GetWorld();
// Return the cloth mesh used to initialize this cloth.
// Create a particle.
b3Particle* CreateParticle(const b3ParticleDef& def);
// Destroy a particle
void DestroyParticle(b3Particle* particle);
// Create a force.
b3Force* CreateForce(const b3ForceDef& def);
// Destroy a force.
void DestroyForce(b3Force* force);
// Perform a ray cast with the cloth.
bool RayCast(b3ClothRayCastOutput* output, const b3RayCastInput* input) const;
// Perform a ray cast with a given cloth mesh triangle.
bool RayCast(b3ClothRayCastOutput* output, const b3RayCastInput* input, u32 triangleIndex) const;
// Return the cloth mesh proxy.
b3ClothMesh* GetMesh() const;
// Return the number of particles in this cloth.
u32 GetParticleCount() const;
// Return the list of particles in this cloth.
const b3List2<b3Particle>& GetParticleList() const;
// Return the particle at a given index in this cloth.
b3Particle* GetParticle(u32 i) const;
// Convenience function.
// Return the index of a given particle.
u32 GetParticleIndex(const b3Particle* p) const;
// Return the list of forces in this cloth.
const b3List2<b3Force>& GetForceList() const;
// Set the type of a given particle.
void SetType(b3Particle* p, b3ParticleType type);
// 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);
// Apply a translation to a given particle.
void ApplyTranslation(b3Particle* p, const b3Vec3& translation);
// Return the number of springs in this cloth.
u32 GetSpringCount() const;
// Return the spring at a given index in this cloth.
b3Spring* GetSpring(u32 i) const;
// Return the kinetic (or dynamic) energy in this system.
float32 GetEnergy() const;
@ -228,11 +137,12 @@ private:
b3Cloth(const b3ClothDef& def, b3World* world);
~b3Cloth();
// Perform a time step. Called only inside b3World.
// Perform a time step.
// Called only inside b3World.
void Step(float32 dt, const b3Vec3& gravity);
// Compute mass of each particle.
void ResetMass();
void ComputeMass();
// Update contacts.
// This is where some contacts might be initiated or terminated.
@ -241,19 +151,18 @@ private:
// Solve
void Solve(float32 dt, const b3Vec3& gravity);
b3StackAllocator* m_allocator;
// Proxy mesh
b3ClothMesh* m_mesh;
float32 m_density;
u32 m_particleCount;
b3Particle* m_particles;
// Particle pool
b3BlockPool m_particleBlocks;
u32 m_springCount;
b3Spring* m_springs;
b3BodyContact* m_contacts;
//u32 m_contactCount;
// List of particles
b3List2<b3Particle> m_particleList;
// List of forces
b3List2<b3Force> m_forceList;
// The parent world of this cloth.
b3World* m_world;
@ -278,87 +187,14 @@ inline b3ClothMesh* b3Cloth::GetMesh() const
return m_mesh;
}
inline u32 b3Cloth::GetParticleCount() const
inline const b3List2<b3Particle>& b3Cloth::GetParticleList() const
{
return m_particleCount;
return m_particleList;
}
inline b3Particle* b3Cloth::GetParticle(u32 i) const
inline const b3List2<b3Force>& b3Cloth::GetForceList() const
{
B3_ASSERT(i < m_particleCount);
return m_particles + i;
}
inline u32 b3Cloth::GetParticleIndex(const b3Particle* p) const
{
return u32(p - m_particles);
}
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::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 void b3Cloth::ApplyTranslation(b3Particle* p, const b3Vec3& translation)
{
p->translation += translation;
}
inline u32 b3Cloth::GetSpringCount() const
{
return m_springCount;
}
inline b3Spring* b3Cloth::GetSpring(u32 i) const
{
B3_ASSERT(i < m_springCount);
return m_springs + i;
}
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;
return m_forceList;
}
inline const b3Cloth* b3Cloth::GetNext() const

View File

@ -41,10 +41,13 @@ struct b3ClothMeshSewingLine
u32 v1, v2;
};
class b3Particle;
struct b3ClothMesh
{
u32 vertexCount;
b3Vec3* vertices;
b3Particle** particles;
u32 triangleCount;
b3ClothMeshTriangle* triangles;
u32 meshCount;
@ -61,8 +64,7 @@ struct b3GarmentClothMesh : public b3ClothMesh
b3GarmentClothMesh();
~b3GarmentClothMesh();
// Maps a given garment mesh to this mesh.
// This garment mesh must be empty.
// Set this mesh from a 2D garment mesh.
void Set(const b3GarmentMesh* garment);
};

View File

@ -22,23 +22,22 @@
#include <bounce/common/math/vec3.h>
#include <bounce/common/math/mat33.h>
class b3StackAllocator;
struct b3DenseVec3;
struct b3DiagMat33;
struct b3SparseMat33;
struct b3SolverSparseMat33;
struct b3SparseSymMat33;
struct b3SymMat33;
struct b3Particle;
struct b3Spring;
class b3Particle;
class b3Force;
struct b3BodyContact;
class b3Shape;
class b3StackAllocator;
struct b3ClothSolverDef
{
b3StackAllocator* stack;
u32 particleCapacity;
u32 springCapacity;
u32 forceCapacity;
u32 contactCapacity;
};
@ -47,17 +46,12 @@ struct b3ClothSolverData
b3Vec3* x;
b3Vec3* v;
b3Vec3* f;
b3SymMat33* dfdx;
b3SymMat33* dfdv;
float32 dt;
float32 invdt;
};
struct b3SpringForce
{
u32 i1, i2;
b3Vec3 f;
b3Mat33 Jx, Jv;
};
struct b3AccelerationConstraint
{
u32 i1;
@ -65,6 +59,45 @@ struct b3AccelerationConstraint
b3Vec3 p, q, z;
};
struct b3SymMat33
{
b3SymMat33(b3StackAllocator* a, u32 m, u32 n)
{
allocator = a;
M = m;
N = n;
values = (b3Mat33*)b3Alloc(M * N * sizeof(b3Mat33));
}
~b3SymMat33()
{
b3Free(values);
}
b3Mat33& operator()(u32 i, u32 j)
{
return values[i * N + j];
}
const b3Mat33& operator()(u32 i, u32 j) const
{
return values[i * N + j];
}
void SetZero()
{
for (u32 v = 0; v < M * N; ++v)
{
values[v].SetZero();
}
}
u32 M;
u32 N;
b3Mat33* values;
b3StackAllocator* allocator;
};
class b3ClothSolver
{
public:
@ -72,7 +105,7 @@ public:
~b3ClothSolver();
void Add(b3Particle* p);
void Add(b3Spring* s);
void Add(b3Force* f);
void Add(b3BodyContact* c);
void Solve(float32 dt, const b3Vec3& gravity);
@ -80,17 +113,20 @@ private:
// Initialize forces.
void InitializeForces();
// Apply forces.
void ApplyForces();
// Initialize constraints.
void InitializeConstraints();
// Compute A and b in Ax = b
void Compute_A_b(b3SolverSparseMat33& A, b3DenseVec3& b, const b3DenseVec3& f, const b3DenseVec3& x, const b3DenseVec3& v, const b3DenseVec3& y) const;
void Compute_A_b(b3SparseSymMat33& A, b3DenseVec3& b, const b3DenseVec3& f, const b3DenseVec3& x, const b3DenseVec3& v, const b3DenseVec3& y) const;
// Compute S and z.
void Compute_S_z(b3DiagMat33& S, b3DenseVec3& z);
// Solve Ax = b.
void Solve(b3DenseVec3& x, u32& iterations, const b3SparseMat33& A, const b3DenseVec3& b, const b3DiagMat33& S, const b3DenseVec3& z, const b3DenseVec3& y) const;
void Solve(b3DenseVec3& x, u32& iterations, const b3SparseSymMat33& A, const b3DenseVec3& b, const b3DiagMat33& S, const b3DenseVec3& z, const b3DenseVec3& y) const;
b3StackAllocator* m_allocator;
@ -98,9 +134,9 @@ private:
u32 m_particleCount;
b3Particle** m_particles;
u32 m_springCapacity;
u32 m_springCount;
b3Spring** m_springs;
u32 m_forceCapacity;
u32 m_forceCount;
b3Force** m_forces;
u32 m_contactCapacity;
u32 m_contactCount;

View File

@ -0,0 +1,87 @@
/*
* 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_FORCE_H
#define B3_FORCE_H
#include <bounce/common/math/transform.h>
#include <bounce/common/template/list.h>
struct b3ClothSolverData;
class b3Particle;
// Force types
enum b3ForceType
{
e_springForce,
};
struct b3ForceDef
{
b3ForceType type;
};
//
class b3Force
{
public:
//
b3ForceType GetType() const;
//
b3Force* GetNext();
protected:
friend class b3List2<b3Force>;
friend class b3Cloth;
friend class b3ClothSolver;
friend class b3Particle;
friend class b3Force;
static b3Force* Create(const b3ForceDef* def);
static void Destroy(b3Force* f);
b3Force() { }
virtual ~b3Force() { }
virtual void Initialize(const b3ClothSolverData* data) = 0;
virtual void Apply(const b3ClothSolverData* data) = 0;
// Solver shared
// Force type
b3ForceType m_type;
//
b3Force* m_prev;
//
b3Force* m_next;
};
inline b3ForceType b3Force::GetType() const
{
return m_type;
}
inline b3Force* b3Force::GetNext()
{
return m_next;
}
#endif

View File

@ -0,0 +1,226 @@
/*
* 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_PARTICLE_H
#define B3_PARTICLE_H
#include <bounce/common/math/transform.h>
#include <bounce/common/template/list.h>
class b3Shape;
class b3Cloth;
class b3Particle;
// Static particle: Can be moved manually.
// Kinematic particle: Non-zero velocity, can be moved by the solver.
// Dynamic particle: Non-zero velocity determined by force, can be moved by the solver.
enum b3ParticleType
{
e_staticParticle,
e_kinematicParticle,
e_dynamicParticle
};
//
struct b3ParticleDef
{
b3ParticleDef()
{
type = e_staticParticle;
position.SetZero();
velocity.SetZero();
force.SetZero();
radius = 0.0f;
userData = nullptr;
}
b3ParticleType type;
b3Vec3 position;
b3Vec3 velocity;
b3Vec3 force;
float32 radius;
void* userData;
};
// A contact between a particle and a solid
struct b3BodyContact
{
b3Particle* p1;
b3Shape* s2;
float32 s;
b3Vec3 n, t1, t2;
float32 Fn, Ft1, Ft2;
bool n_active, t1_active, t2_active;
};
// A cloth particle.
class b3Particle
{
public:
// Set the particle type.
void SetType(b3ParticleType type);
// Get the particle type.
b3ParticleType GetType() const;
// Get the vertex index.
u32 GetVertex() const;
// Get the particle position.
const b3Vec3& GetPosition() const;
// Set the particle velocity.
void SetVelocity(const b3Vec3& velocity);
// Get the particle velocity.
const b3Vec3& GetVelocity() const;
// Get the particle mass.
float32 GetMass() const;
// Get the particle radius;
float32 GetRadius() const;
// Apply a force.
void ApplyForce(const b3Vec3& force);
// Apply a translation.
void ApplyTranslation(const b3Vec3& translation);
// Get the next particle.
b3Particle* GetNext();
private:
friend class b3List2<b3Particle>;
friend class b3Cloth;
friend class b3ClothSolver;
friend class b3Force;
friend class b3SpringForce;
b3Particle(const b3ParticleDef& def, b3Cloth* cloth);
~b3Particle();
// Type
b3ParticleType m_type;
// Position
b3Vec3 m_position;
// Velocity
b3Vec3 m_velocity;
// Applied external force
b3Vec3 m_force;
// Mass
float32 m_mass;
// Inverse mass
float32 m_invMass;
// Radius
float32 m_radius;
// User data.
void* m_userData;
// Cloth mesh vertex index.
u32 m_vertex;
// Applied external translation
b3Vec3 m_translation;
// Contact
b3BodyContact m_contact;
// Solver temp
// Identifier
u32 m_solverId;
// Solution
b3Vec3 m_x;
//
b3Cloth* m_cloth;
//
b3Particle* m_prev;
//
b3Particle* m_next;
};
inline b3ParticleType b3Particle::GetType() const
{
return m_type;
}
inline u32 b3Particle::GetVertex() const
{
return m_vertex;
}
inline const b3Vec3& b3Particle::GetPosition() const
{
return m_position;
}
inline void b3Particle::SetVelocity(const b3Vec3& velocity)
{
if (m_type == e_staticParticle)
{
return;
}
m_velocity = velocity;
}
inline const b3Vec3& b3Particle::GetVelocity() const
{
return m_velocity;
}
inline float32 b3Particle::GetMass() const
{
return m_mass;
}
inline float32 b3Particle::GetRadius() const
{
return m_radius;
}
inline void b3Particle::ApplyForce(const b3Vec3& force)
{
if (m_type != e_dynamicParticle)
{
return;
}
m_force += force;
}
inline void b3Particle::ApplyTranslation(const b3Vec3& translation)
{
m_translation += translation;
}
inline b3Particle* b3Particle::GetNext()
{
return m_next;
}
#endif

View File

@ -1,154 +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_SPARSE_MAT_33_H
#define B3_SPARSE_MAT_33_H
#include <bounce/common/math/mat33.h>
#include <bounce/dynamics/cloth/diag_mat33.h>
#include <bounce/dynamics/cloth/dense_vec3.h>
// A static sparse matrix stored in Compressed Sparse Row (CSR) format.
// It's efficient when using in iterative solvers such as CG method, where
// the coefficient matrix must be multiplied with a vector at each iteration.
// See https://en.wikipedia.org/wiki/Sparse_matrix
struct b3SparseMat33
{
b3SparseMat33() { }
b3SparseMat33(u32 _M, u32 _N,
u32 _valueCount, b3Mat33* _values,
u32* _row_ptrs, u32* _cols)
{
M = _M;
N = _N;
values = _values;
valueCount = _valueCount;
row_ptrs = _row_ptrs;
cols = _cols;
}
~b3SparseMat33()
{
}
// Output any given row of the original matrix.
// The given buffer must have size of greater or equal than M.
void AssembleRow(b3Mat33* out, u32 row) const;
// Decompresses this matrix into its original form.
// The output matrix is stored in row-major order.
// The given buffer must have size of greater or equal than M * N.
void AssembleMatrix(b3Mat33* out) const;
// Output the block diagonal part of the original matrix.
// This matrix must be a square matrix.
// The given buffer must have size of greater or equal than M.
void AssembleDiagonal(b3DiagMat33& out) const;
// Dimensions of the original 2D matrix
u32 M;
u32 N;
// Non-zero values
b3Mat33* values;
u32 valueCount;
// Sparsity structure
u32* row_ptrs; // pointers to the first non-zero value of each row (size is M + 1)
u32* cols; // column indices for each non-zero value (size is valueCount)
};
inline void b3SparseMat33::AssembleRow(b3Mat33* out, u32 row) const
{
B3_ASSERT(row < M + 1);
// Start with zero row
for (u32 i = 0; i < N; ++i)
{
out[i].SetZero();
}
for (u32 i = row_ptrs[row]; i < row_ptrs[row + 1]; ++i)
{
u32 col = cols[i];
out[col] = values[i];
}
}
inline void b3SparseMat33::AssembleMatrix(b3Mat33* out) const
{
for (u32 i = 0; i < M; ++i)
{
AssembleRow(out + i * N, i);
}
}
inline void b3SparseMat33::AssembleDiagonal(b3DiagMat33& out) const
{
B3_ASSERT(M == N);
for (u32 row = 0; row < M; ++row)
{
out[row].SetZero();
for (u32 row_ptr = row_ptrs[row]; row_ptr < row_ptrs[row + 1]; ++row_ptr)
{
if (cols[row_ptr] > row)
{
break;
}
if (cols[row_ptr] == row)
{
out[row] = values[row_ptr];
break;
}
}
}
}
inline void b3Mul(b3DenseVec3& out, const b3SparseMat33& A, const b3DenseVec3& v)
{
B3_ASSERT(A.N == out.n);
for (u32 row = 0; row < A.N; ++row)
{
out[row].SetZero();
for (u32 j = A.row_ptrs[row]; j < A.row_ptrs[row + 1]; ++j)
{
u32 col = A.cols[j];
out[row] += A.values[j] * v[col];
}
}
}
inline b3DenseVec3 operator*(const b3SparseMat33& A, const b3DenseVec3& v)
{
b3DenseVec3 result(v.n);
b3Mul(result, A, v);
return result;
}
#endif

View File

@ -0,0 +1,236 @@
/*
* 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_SPARSE_SYM_MAT_33_H
#define B3_SPARSE_SYM_MAT_33_H
#include <bounce/common/memory/stack_allocator.h>
#include <bounce/common/math/mat33.h>
#include <bounce/dynamics/cloth/diag_mat33.h>
#include <bounce/dynamics/cloth/dense_vec3.h>
struct b3SparseSymMat33
{
//
b3SparseSymMat33(b3StackAllocator* a, u32 m, u32 n);
//
~b3SparseSymMat33();
//
b3Mat33& operator()(u32 i, u32 j);
//
const b3Mat33& operator()(u32 i, u32 j) const;
//
void Diagonal(b3DiagMat33& out) const;
//
b3StackAllocator* allocator;
u32 M;
u32 N;
u32* row_ptrs;
u32 value_capacity;
u32 value_count;
b3Mat33* values;
u32* value_columns;
};
inline b3SparseSymMat33::b3SparseSymMat33(b3StackAllocator* a, u32 m, u32 n)
{
B3_ASSERT(m == n);
allocator = a;
M = m;
N = n;
row_ptrs = (u32*)allocator->Allocate((M + 1) * sizeof(u32));
memset(row_ptrs, 0, (M + 1) * sizeof(u32));
value_count = 0;
value_capacity = n * (n + 1) / 2;
values = (b3Mat33*)allocator->Allocate(value_capacity * sizeof(b3Mat33));
value_columns = (u32*)allocator->Allocate(value_capacity * sizeof(u32));
}
inline b3SparseSymMat33::~b3SparseSymMat33()
{
allocator->Free(value_columns);
allocator->Free(values);
allocator->Free(row_ptrs);
}
inline const b3Mat33& b3SparseSymMat33::operator()(u32 i, u32 j) const
{
B3_ASSERT(i < M);
B3_ASSERT(j < N);
// Ensure i, and j is on the upper triangle
if (i > j)
{
b3Swap(i, j);
}
u32 row_value_begin = row_ptrs[i];
u32 row_value_count = row_ptrs[i + 1] - row_value_begin;
for (u32 row_value = 0; row_value < row_value_count; ++row_value)
{
u32 row_value_index = row_value_begin + row_value;
u32 row_value_column = value_columns[row_value_index];
if (row_value_column == j)
{
return values[row_value_index];
}
}
return b3Mat33_zero;
}
inline b3Mat33& b3SparseSymMat33::operator()(u32 i, u32 j)
{
B3_ASSERT(i < M);
B3_ASSERT(j < N);
// Ensure i, and j is on the upper triangle
if (i > j)
{
b3Swap(i, j);
}
u32 row_value_begin = row_ptrs[i];
u32 row_value_count = row_ptrs[i + 1] - row_value_begin;
for (u32 row_value = 0; row_value < row_value_count; ++row_value)
{
u32 row_value_index = row_value_begin + row_value;
u32 row_value_column = value_columns[row_value_index];
if (row_value_column == j)
{
return values[row_value_index];
}
}
// Insert sorted by column
u32 max_column_row_value = 0;
for (u32 row_value = 0; row_value < row_value_count; ++row_value)
{
u32 row_value_index = row_value_begin + row_value;
u32 row_value_column = value_columns[row_value_index];
if (row_value_column >= j)
{
max_column_row_value = row_value;
break;
}
}
u32 max_column_row_value_index = row_value_begin + max_column_row_value;
// Copy the values to be shifted
u32 shift_count = value_count - max_column_row_value_index;
b3Mat33* shift_values = (b3Mat33*)allocator->Allocate(shift_count * sizeof(b3Mat33));
memcpy(shift_values, values + max_column_row_value_index, shift_count * sizeof(b3Mat33));
u32* shift_value_columns = (u32*)allocator->Allocate(shift_count * sizeof(u32));
memcpy(shift_value_columns, value_columns + max_column_row_value_index, shift_count * sizeof(u32));
// Insert the new value
B3_ASSERT(value_count < value_capacity);
value_columns[max_column_row_value_index] = j;
++value_count;
// Shift the old values
memcpy(values + max_column_row_value_index + 1, shift_values, shift_count * sizeof(b3Mat33));
memcpy(value_columns + max_column_row_value_index + 1, shift_value_columns, shift_count * sizeof(u32));
allocator->Free(shift_value_columns);
allocator->Free(shift_values);
// Shift the old row pointers as well
for (u32 row_ptr_index = i + 1; row_ptr_index < M + 1; ++row_ptr_index)
{
++row_ptrs[row_ptr_index];
}
return values[max_column_row_value_index];
}
inline void b3SparseSymMat33::Diagonal(b3DiagMat33& out) const
{
B3_ASSERT(N == out.n);
for (u32 row = 0; row < M; ++row)
{
out[row].SetZero();
u32 row_value_begin = row_ptrs[row];
u32 row_value_count = row_ptrs[row + 1] - row_value_begin;
for (u32 row_value = 0; row_value < row_value_count; ++row_value)
{
u32 row_value_index = row_value_begin + row_value;
u32 row_value_column = value_columns[row_value_index];
if (row == row_value_column)
{
out[row] = values[row_value_index];
break;
}
}
}
}
inline void b3Mul(b3DenseVec3& out, const b3SparseSymMat33& A, const b3DenseVec3& v)
{
B3_ASSERT(A.N == out.n);
out.SetZero();
for (u32 row = 0; row < A.N; ++row)
{
u32 row_value_begin = A.row_ptrs[row];
u32 row_value_count = A.row_ptrs[row + 1] - row_value_begin;
for (u32 row_value = 0; row_value < row_value_count; ++row_value)
{
u32 row_value_index = row_value_begin + row_value;
u32 row_value_column = A.value_columns[row_value_index];
out[row] += A.values[row_value_index] * v[row_value_column];
if (row != row_value_column)
{
// A(i, j) == A(j, i)
out[row_value_column] += A.values[row_value_index] * v[row];
}
}
}
}
inline b3DenseVec3 operator*(const b3SparseSymMat33& A, const b3DenseVec3& v)
{
b3DenseVec3 result(v.n);
b3Mul(result, A, v);
return result;
}
#endif

View File

@ -0,0 +1,140 @@
/*
* 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_FORCE_H
#define B3_SPRING_FORCE_H
#include <bounce/dynamics/cloth/force.h>
struct b3SpringForceDef : public b3ForceDef
{
b3SpringForceDef()
{
type = e_springForce;
p1 = nullptr;
p2 = nullptr;
restLength = 0.0f;
structural = 0.0f;
damping = 0.0f;
}
//
void Initialize(b3Particle* particle1, b3Particle* particle2, float32 structuralStiffness, float32 dampingStiffness);
// Particle 1
b3Particle* p1;
// Particle 2
b3Particle* p2;
// Rest length
float32 restLength;
// Structural stiffness
float32 structural;
// Damping stiffness
float32 damping;
};
//
class b3SpringForce : public b3Force
{
public:
b3Particle* GetParticle1();
b3Particle* GetParticle2();
float32 GetRestLenght() const;
float32 GetStructuralStiffness() const;
float32 GetDampingStiffness() const;
b3Vec3 GetActionForce() const;
private:
friend class b3Force;
friend class b3Cloth;
b3SpringForce(const b3SpringForceDef* def);
~b3SpringForce();
void Initialize(const b3ClothSolverData* data);
void Apply(const b3ClothSolverData* data);
// Solver shared
// Particle 1
b3Particle* m_p1;
// Particle 2
b3Particle* m_p2;
// Rest length
float32 m_L0;
// Structural stiffness
float32 m_ks;
// Damping stiffness
float32 m_kd;
// Solver temp
// Force (f_1 entry)
b3Vec3 m_f;
// Jacobian (J_11 entry)
b3Mat33 m_Jx;
// Jacobian (J_11 entry)
b3Mat33 m_Jv;
};
inline b3Particle * b3SpringForce::GetParticle1()
{
return m_p1;
}
inline b3Particle* b3SpringForce::GetParticle2()
{
return m_p2;
}
inline float32 b3SpringForce::GetRestLenght() const
{
return m_L0;
}
inline float32 b3SpringForce::GetStructuralStiffness() const
{
return m_ks;
}
inline float32 b3SpringForce::GetDampingStiffness() const
{
return m_kd;
}
inline b3Vec3 b3SpringForce::GetActionForce() const
{
return m_f;
}
#endif