now b3World is responsable for creating or destroying b3Cloth; clean up; update tests

This commit is contained in:
Irlan 2018-05-26 00:41:41 -03:00
parent 8d2affb0b2
commit 43013ad80b
13 changed files with 218 additions and 204 deletions

View File

@ -148,7 +148,7 @@ int main(int argc, char** args)
#if defined(_WIN32) #if defined(_WIN32)
// Report memory leaks // Report memory leaks
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG));
//_CrtSetBreakAlloc(x); //_CrtSetBreakAlloc(0);
#endif #endif
if (glfwInit() == 0) if (glfwInit() == 0)

View File

@ -22,10 +22,8 @@
class ClothDragger class ClothDragger
{ {
public: public:
ClothDragger(Ray3* ray, b3Cloth* cloth) ClothDragger(Ray3* ray, b3Cloth*& cloth) : m_ray(ray), m_cloth(cloth)
{ {
m_ray = ray;
m_cloth = cloth;
m_isSelected = false; m_isSelected = false;
} }
@ -275,7 +273,7 @@ private:
Ray3* m_ray; Ray3* m_ray;
float32 m_x; float32 m_x;
b3Cloth * m_cloth; b3Cloth*& m_cloth;
u32 m_selection; u32 m_selection;
float32 m_u, m_v; float32 m_u, m_v;
b3ParticleType m_t1, m_t2, m_t3; b3ParticleType m_t1, m_t2, m_t3;
@ -284,39 +282,29 @@ private:
class ClothTest : public Test class ClothTest : public Test
{ {
public: public:
ClothTest() : m_clothDragger(&m_clothRay, &m_cloth) ClothTest() : m_clothDragger(&m_clothRay, m_cloth)
{ {
m_cloth.SetGravity(b3Vec3(0.0f, -10.0f, 0.0f)); m_world.SetGravity(b3Vec3(0.0f, -10.0f, 0.0f));
m_clothRay.origin.SetZero(); m_clothRay.origin.SetZero();
m_clothRay.direction.Set(0.0f, 0.0f, -1.0f); m_clothRay.direction.Set(0.0f, 0.0f, -1.0f);
m_clothRay.fraction = g_camera->m_zFar; m_clothRay.fraction = g_camera->m_zFar;
m_cloth = nullptr;
} }
void Step() void Step()
{ {
float32 dt = g_testSettings->inv_hertz; Test::Step();
m_cloth.Step(dt); m_cloth->Apply();
m_cloth.Apply();
b3Shape** shapes = m_cloth.GetShapeList(); m_cloth->Draw();
for (u32 i = 0; i < m_cloth.GetShapeCount(); ++i)
{
b3Shape* s = shapes[i];
b3Transform xf;
xf.SetIdentity();
g_draw->DrawSolidShape(s, b3Color_white, xf);
}
m_cloth.Draw();
extern u32 b3_clothSolverIterations; extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %u", b3_clothSolverIterations); g_draw->DrawString(b3Color_white, "Iterations = %u", b3_clothSolverIterations);
float32 E = m_cloth.GetEnergy(); float32 E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E); g_draw->DrawString(b3Color_white, "E = %f", E);
if (m_clothDragger.IsSelected() == true) if (m_clothDragger.IsSelected() == true)
@ -352,7 +340,7 @@ public:
} }
Ray3 m_clothRay; Ray3 m_clothRay;
b3Cloth m_cloth; b3Cloth* m_cloth;
ClothDragger m_clothDragger; ClothDragger m_clothDragger;
}; };

View File

@ -38,10 +38,10 @@ public:
void SetClothType(b3ParticleType type) void SetClothType(b3ParticleType type)
{ {
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i) for (u32 i = 0; i < m_cloth->GetParticleCount(); ++i)
{ {
b3Particle* p = m_cloth.GetParticle(i); b3Particle* p = m_cloth->GetParticle(i);
m_cloth.SetType(p, type); m_cloth->SetType(p, type);
} }
} }
@ -62,9 +62,9 @@ public:
SetClothType(e_dynamicParticle); SetClothType(e_dynamicParticle);
} }
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i) for (u32 i = 0; i < m_cloth->GetParticleCount(); ++i)
{ {
b3Particle* p = m_cloth.GetParticle(i); b3Particle* p = m_cloth->GetParticle(i);
b3Vec3 d; b3Vec3 d;
d.SetZero(); d.SetZero();
@ -96,7 +96,7 @@ public:
{ {
if (p->type == e_staticParticle) if (p->type == e_staticParticle)
{ {
m_cloth.Translate(p, d); m_cloth->Translate(p, d);
} }
if (p->type == e_kinematicParticle) if (p->type == e_kinematicParticle)
@ -105,14 +105,14 @@ public:
v += 5.0f * d; v += 5.0f * d;
m_cloth.SetVelocity(p, d); m_cloth->SetVelocity(p, d);
} }
if (p->type == e_dynamicParticle) if (p->type == e_dynamicParticle)
{ {
b3Vec3 f = 100.0f * d; b3Vec3 f = 100.0f * d;
m_cloth.ApplyForce(p, f); m_cloth->ApplyForce(p, f);
} }
} }
} }

View File

@ -49,18 +49,18 @@ public:
def.kd = 0.0f; def.kd = 0.0f;
def.r = 0.05f; def.r = 0.05f;
m_cloth.Initialize(def); m_cloth = m_world.CreateCloth(def);
b3AABB3 aabb; b3AABB3 aabb;
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f); aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i) for (u32 i = 0; i < m_cloth->GetParticleCount(); ++i)
{ {
b3Particle* p = m_cloth.GetParticle(i); b3Particle* p = m_cloth->GetParticle(i);
if (aabb.Contains(p->position)) if (aabb.Contains(p->position))
{ {
m_cloth.SetType(p, e_staticParticle); m_cloth->SetType(p, e_staticParticle);
} }
} }
} }

View File

@ -62,7 +62,7 @@ public:
def.r = 0.2f; def.r = 0.2f;
def.ks = 10000.0f; def.ks = 10000.0f;
m_cloth.Initialize(def); m_cloth = m_world.CreateCloth(def);
} }
static Test* Create() static Test* Create()

View File

@ -55,16 +55,26 @@ public:
def.kd = 0.0f; def.kd = 0.0f;
def.r = 0.05f; def.r = 0.05f;
m_cloth.Initialize(def); m_cloth = m_world.CreateCloth(def);
m_tableHull.SetAsCylinder(5.0f, 2.0f); {
b3BodyDef bd;
bd.type = e_staticBody;
m_tableShape.m_hull = &m_tableHull; b3Body* b = m_world.CreateBody(bd);
m_tableShape.m_radius = 0.2f;
m_tableShape.SetFriction(1.0f); m_tableHull.SetAsCylinder(5.0f, 2.0f);
m_cloth.AddShape(&m_tableShape); b3HullShape tableShape;
tableShape.m_hull = &m_tableHull;
tableShape.m_radius = 0.2f;
b3ShapeDef sd;
sd.shape = &tableShape;
sd.friction = 1.0f;
b->CreateShape(sd);
}
} }
static Test* Create() static Test* Create()
@ -77,7 +87,6 @@ public:
b3ClothMesh m_gridClothMesh; b3ClothMesh m_gridClothMesh;
b3QHull m_tableHull; b3QHull m_tableHull;
b3HullShape m_tableShape;
}; };
#endif #endif

View File

@ -85,18 +85,18 @@ public:
def.kd = 0.0f; def.kd = 0.0f;
def.r = 0.2f; def.r = 0.2f;
m_cloth.Initialize(def); m_cloth = m_world.CreateCloth(def);
b3AABB3 aabb; b3AABB3 aabb;
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f); aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f); aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
for (u32 i = 0; i < m_cloth.GetParticleCount(); ++i) for (u32 i = 0; i < m_cloth->GetParticleCount(); ++i)
{ {
b3Particle* p = m_cloth.GetParticle(i); b3Particle* p = m_cloth->GetParticle(i);
if (aabb.Contains(p->position)) if (aabb.Contains(p->position))
{ {
m_cloth.SetType(p, e_staticParticle); m_cloth->SetType(p, e_staticParticle);
} }
} }
} }
@ -105,25 +105,24 @@ public:
{ {
float32 dt = g_testSettings->inv_hertz; float32 dt = g_testSettings->inv_hertz;
m_cloth.Step(dt); m_cloth->Apply();
m_cloth.Apply();
b3StackArray<b3Vec3, 256> tension; b3StackArray<b3Vec3, 256> tension;
tension.Resize(m_cloth.GetParticleCount()); tension.Resize(m_cloth->GetParticleCount());
for (u32 i = 0; i < tension.Count(); ++i) for (u32 i = 0; i < tension.Count(); ++i)
{ {
tension[i].SetZero(); tension[i].SetZero();
} }
for (u32 i = 0; i < m_cloth.GetSpringCount(); ++i) for (u32 i = 0; i < m_cloth->GetSpringCount(); ++i)
{ {
b3Spring* s = m_cloth.GetSpring(i); b3Spring* s = m_cloth->GetSpring(i);
b3Particle* p1 = s->p1; b3Particle* p1 = s->p1;
b3Particle* p2 = s->p2; b3Particle* p2 = s->p2;
u32 i1 = m_cloth.GetParticleIndex(p1); u32 i1 = m_cloth->GetParticleIndex(p1);
u32 i2 = m_cloth.GetParticleIndex(p2); u32 i2 = m_cloth->GetParticleIndex(p2);
tension[i1] += s->tension; tension[i1] += s->tension;
tension[i2] -= s->tension; tension[i2] -= s->tension;
@ -133,9 +132,9 @@ public:
{ {
b3ClothMeshTriangle* t = m_gridClothMesh.triangles + i; b3ClothMeshTriangle* t = m_gridClothMesh.triangles + i;
b3Particle* p1 = m_cloth.GetParticle(t->v1); b3Particle* p1 = m_cloth->GetParticle(t->v1);
b3Particle* p2 = m_cloth.GetParticle(t->v2); b3Particle* p2 = m_cloth->GetParticle(t->v2);
b3Particle* p3 = m_cloth.GetParticle(t->v3); b3Particle* p3 = m_cloth->GetParticle(t->v3);
b3Vec3 v1 = p1->position; b3Vec3 v1 = p1->position;
b3Vec3 v2 = p2->position; b3Vec3 v2 = p2->position;

View File

@ -19,13 +19,11 @@
#ifndef B3_CLOTH_H #ifndef B3_CLOTH_H
#define B3_CLOTH_H #define B3_CLOTH_H
#include <bounce/common/math/mat33.h> #include <bounce/common/math/transform.h>
#include <bounce/common/template/array.h> #include <bounce/common/template/list.h>
#include <bounce/common/memory/stack_allocator.h>
// Maximum number of shapes per cloth.
#define B3_CLOTH_SHAPE_CAPACITY 32
class b3StackAllocator;
class b3World;
class b3Shape; class b3Shape;
struct b3ClothMesh; struct b3ClothMesh;
@ -157,8 +155,8 @@ struct b3Spring
void ApplyForces(const b3ClothSolverData* data); void ApplyForces(const b3ClothSolverData* data);
}; };
// Read-only contact // Read-only body contact between a particle and a solid
struct b3ParticleContact struct b3BodyContact
{ {
b3Particle* p1; b3Particle* p1;
b3Shape* s2; b3Shape* s2;
@ -173,22 +171,13 @@ struct b3ParticleContact
class b3Cloth class b3Cloth
{ {
public: public:
b3Cloth(); // Get the world the cloth belongs to.
~b3Cloth(); const b3World* GetWorld() const;
b3World* GetWorld();
// Initialize this cloth from a definition.
void Initialize(const b3ClothDef& def);
// Return the cloth mesh used to initialize this cloth. // Return the cloth mesh used to initialize this cloth.
b3ClothMesh* GetMesh() const; b3ClothMesh* GetMesh() const;
// Set the gravitational acceleration applied to this cloth.
// Units are m/s^2.
void SetGravity(const b3Vec3& gravity);
// Return the gravitational acceleration applied to this cloth.
const b3Vec3& GetGravity() const;
// Return the number of particles in this cloth. // Return the number of particles in this cloth.
u32 GetParticleCount() const; u32 GetParticleCount() const;
@ -220,26 +209,28 @@ public:
// Return the kinetic (or dynamic) energy in this system. // Return the kinetic (or dynamic) energy in this system.
float32 GetEnergy() const; float32 GetEnergy() const;
// Add a collision shape to the list of shapes in this cloth. // Get the next cloth in the world cloth list.
// The cloth will be able to respond to collisions with each shape in the list of shapes. const b3Cloth* GetNext() const;
// Current the shape will be treated as a static shape.
void AddShape(b3Shape* shape);
// Return the number of collision shapes in this cloth. // Get the next cloth in the world cloth list.
u32 GetShapeCount() const; b3Cloth* GetNext();
// 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. // Set the positions of the mesh vertices to the positions of their associated particles.
void Apply() const; void Apply() const;
// Debug draw the cloth using the associated cloth mesh. // Debug draw the cloth using the associated cloth mesh.
void Draw() const; void Draw() const;
protected: private:
friend class b3World;
friend class b3List2<b3Cloth>;
b3Cloth(const b3ClothDef& def, b3World* world);
~b3Cloth();
// Perform a time step. Called only inside b3World.
void Step(float32 dt, const b3Vec3& gravity);
// Compute mass of each particle. // Compute mass of each particle.
void ResetMass(); void ResetMass();
@ -248,11 +239,12 @@ protected:
void UpdateContacts(); void UpdateContacts();
// Solve // Solve
void Solve(float32 dt); void Solve(float32 dt, const b3Vec3& gravity);
b3StackAllocator m_allocator; b3StackAllocator* m_allocator;
b3Vec3 m_gravity; b3ClothMesh* m_mesh;
float32 m_density;
u32 m_particleCount; u32 m_particleCount;
b3Particle* m_particles; b3Particle* m_particles;
@ -260,31 +252,32 @@ protected:
u32 m_springCount; u32 m_springCount;
b3Spring* m_springs; b3Spring* m_springs;
b3ParticleContact* m_contacts; b3BodyContact* m_contacts;
//u32 m_contactCount; //u32 m_contactCount;
b3Shape* m_shapes[B3_CLOTH_SHAPE_CAPACITY]; // The parent world of this cloth.
u32 m_shapeCount; b3World* m_world;
b3ClothMesh* m_mesh; // Links to the world cloth list.
float32 m_density; b3Cloth* m_prev;
b3Cloth* m_next;
}; };
inline const b3World* b3Cloth::GetWorld() const
{
return m_world;
}
inline b3World* b3Cloth::GetWorld()
{
return m_world;
}
inline b3ClothMesh* b3Cloth::GetMesh() const inline b3ClothMesh* b3Cloth::GetMesh() const
{ {
return m_mesh; 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 inline u32 b3Cloth::GetParticleCount() const
{ {
return m_particleCount; return m_particleCount;
@ -368,14 +361,14 @@ inline float32 b3Cloth::GetEnergy() const
return 0.5f * E; return 0.5f * E;
} }
inline u32 b3Cloth::GetShapeCount() const inline const b3Cloth* b3Cloth::GetNext() const
{ {
return m_shapeCount; return m_next;
} }
inline b3Shape** b3Cloth::GetShapeList() inline b3Cloth* b3Cloth::GetNext()
{ {
return m_shapes; return m_next;
} }
#endif #endif

View File

@ -28,7 +28,7 @@ struct b3SparseMat33;
struct b3Particle; struct b3Particle;
struct b3Spring; struct b3Spring;
struct b3ParticleContact; struct b3BodyContact;
class b3Shape; class b3Shape;
class b3StackAllocator; class b3StackAllocator;
@ -65,7 +65,7 @@ public:
void Add(b3Particle* p); void Add(b3Particle* p);
void Add(b3Spring* s); void Add(b3Spring* s);
void Add(b3ParticleContact* c); void Add(b3BodyContact* c);
void Solve(float32 dt, const b3Vec3& gravity); void Solve(float32 dt, const b3Vec3& gravity);
private: private:
@ -93,7 +93,7 @@ private:
u32 m_contactCapacity; u32 m_contactCapacity;
u32 m_contactCount; u32 m_contactCount;
b3ParticleContact** m_contacts; b3BodyContact** m_contacts;
u32 m_constraintCapacity; u32 m_constraintCapacity;
u32 m_constraintCount; u32 m_constraintCount;

View File

@ -26,7 +26,10 @@
#include <bounce/dynamics/joint_manager.h> #include <bounce/dynamics/joint_manager.h>
#include <bounce/dynamics/contact_manager.h> #include <bounce/dynamics/contact_manager.h>
struct b3ClothDef;
struct b3BodyDef; struct b3BodyDef;
class b3Cloth;
class b3Body; class b3Body;
class b3QueryListener; class b3QueryListener;
class b3RayCastListener; class b3RayCastListener;
@ -67,6 +70,12 @@ public:
// The acceleration has units of m/s^2. // The acceleration has units of m/s^2.
void SetGravity(const b3Vec3& gravity); void SetGravity(const b3Vec3& gravity);
// Create a new deformable cloth.
b3Cloth* CreateCloth(const b3ClothDef& def);
// Destroy an existing deformable cloth.
void DestroyCloth(b3Cloth* cloth);
// Create a new rigid body. // Create a new rigid body.
b3Body* CreateBody(const b3BodyDef& def); b3Body* CreateBody(const b3BodyDef& def);
@ -129,6 +138,7 @@ private :
e_clearForcesFlag = 0x0002, e_clearForcesFlag = 0x0002,
}; };
friend class b3Cloth;
friend class b3Body; friend class b3Body;
friend class b3Shape; friend class b3Shape;
friend class b3Contact; friend class b3Contact;
@ -138,14 +148,20 @@ private :
void Solve(float32 dt, u32 velocityIterations, u32 positionIterations); void Solve(float32 dt, u32 velocityIterations, u32 positionIterations);
void StepCloth(float32 dt);
bool m_sleeping; bool m_sleeping;
bool m_warmStarting; bool m_warmStarting;
u32 m_flags; u32 m_flags;
b3Vec3 m_gravity; b3Vec3 m_gravity;
b3StackAllocator m_stackAllocator; b3StackAllocator m_stackAllocator;
b3BlockPool m_clothBlocks;
b3BlockPool m_bodyBlocks; b3BlockPool m_bodyBlocks;
// List of clothes
b3List2<b3Cloth> m_clothList;
// List of bodies // List of bodies
b3List2<b3Body> m_bodyList; b3List2<b3Body> m_bodyList;

View File

@ -22,6 +22,8 @@
#include <bounce/dynamics/cloth/sparse_mat33.h> #include <bounce/dynamics/cloth/sparse_mat33.h>
#include <bounce/dynamics/cloth/cloth_mesh.h> #include <bounce/dynamics/cloth/cloth_mesh.h>
#include <bounce/dynamics/shapes/shape.h> #include <bounce/dynamics/shapes/shape.h>
#include <bounce/dynamics/body.h>
#include <bounce/dynamics/world.h>
#include <bounce/common/memory/stack_allocator.h> #include <bounce/common/memory/stack_allocator.h>
#include <bounce/common/draw.h> #include <bounce/common/draw.h>
@ -82,34 +84,6 @@ void b3Spring::ApplyForces(const b3ClothSolverData* data)
Jv = -kd * I; Jv = -kd * I;
} }
// b3Cloth
b3Cloth::b3Cloth()
{
m_gravity.SetZero();
m_particleCount = 0;
m_particles = nullptr;
m_springs = nullptr;
m_springCount = 0;
m_contacts = nullptr;
//m_contactCount = 0;
m_shapeCount = 0;
m_mesh = nullptr;
m_gravity.SetZero();
}
b3Cloth::~b3Cloth()
{
b3Free(m_particles);
b3Free(m_springs);
b3Free(m_contacts);
}
static B3_FORCE_INLINE u32 b3NextIndex(u32 i) static B3_FORCE_INLINE u32 b3NextIndex(u32 i)
{ {
return i + 1 < 3 ? i + 1 : 0; return i + 1 < 3 ? i + 1 : 0;
@ -228,20 +202,22 @@ static u32 b3FindSharedEdges(b3SharedEdge* sharedEdges, const b3ClothMesh* m)
return sharedCount; return sharedCount;
} }
void b3Cloth::Initialize(const b3ClothDef& def) b3Cloth::b3Cloth(const b3ClothDef& def, b3World* world)
{ {
B3_ASSERT(def.mesh); B3_ASSERT(def.mesh);
B3_ASSERT(def.density > 0.0f); B3_ASSERT(def.density > 0.0f);
m_world = world;
m_allocator = &m_world->m_stackAllocator;
m_mesh = def.mesh; m_mesh = def.mesh;
m_density = def.density; m_density = def.density;
const b3ClothMesh* m = m_mesh; b3ClothMesh* m = m_mesh;
// Create particles // Create particles
m_particleCount = m->vertexCount; m_particleCount = m->vertexCount;
m_particles = (b3Particle*)b3Alloc(m_particleCount * sizeof(b3Particle)); m_particles = (b3Particle*)b3Alloc(m_particleCount * sizeof(b3Particle));
m_contacts = (b3ParticleContact*)b3Alloc(m_particleCount * sizeof(b3ParticleContact)); m_contacts = (b3BodyContact*)b3Alloc(m_particleCount * sizeof(b3BodyContact));
for (u32 i = 0; i < m_particleCount; ++i) for (u32 i = 0; i < m_particleCount; ++i)
{ {
@ -258,7 +234,7 @@ void b3Cloth::Initialize(const b3ClothDef& def)
p->translation.SetZero(); p->translation.SetZero();
p->x.SetZero(); p->x.SetZero();
b3ParticleContact* c = m_contacts + i; b3BodyContact* c = m_contacts + i;
c->n_active = false; c->n_active = false;
c->t1_active = false; c->t1_active = false;
c->t2_active = false; c->t2_active = false;
@ -268,16 +244,18 @@ void b3Cloth::Initialize(const b3ClothDef& def)
ResetMass(); ResetMass();
// Create springs // Create springs
m_springCount = 0;
u32 edgeCount = 3 * m->triangleCount; u32 edgeCount = 3 * m->triangleCount;
b3UniqueEdge* uniqueEdges = (b3UniqueEdge*)m_allocator.Allocate(edgeCount * sizeof(b3UniqueEdge)); b3UniqueEdge* uniqueEdges = (b3UniqueEdge*)m_allocator->Allocate(edgeCount * sizeof(b3UniqueEdge));
u32 uniqueCount = b3FindUniqueEdges(uniqueEdges, m); u32 uniqueCount = b3FindUniqueEdges(uniqueEdges, m);
u32 springCapacity = uniqueCount; u32 springCapacity = uniqueCount;
#if B3_CLOTH_BENDING #if B3_CLOTH_BENDING
b3SharedEdge* sharedEdges = (b3SharedEdge*)m_allocator.Allocate(edgeCount * sizeof(b3SharedEdge)); b3SharedEdge* sharedEdges = (b3SharedEdge*)m_allocator->Allocate(edgeCount * sizeof(b3SharedEdge));
u32 sharedCount = b3FindSharedEdges(sharedEdges, m); u32 sharedCount = b3FindSharedEdges(sharedEdges, m);
springCapacity += sharedCount; springCapacity += sharedCount;
@ -332,10 +310,10 @@ void b3Cloth::Initialize(const b3ClothDef& def)
s->tension.SetZero(); s->tension.SetZero();
} }
m_allocator.Free(sharedEdges); m_allocator->Free(sharedEdges);
#endif #endif
m_allocator.Free(uniqueEdges); m_allocator->Free(uniqueEdges);
// Sewing // Sewing
for (u32 i = 0; i < m->sewingLineCount; ++i) for (u32 i = 0; i < m->sewingLineCount; ++i)
@ -358,6 +336,13 @@ void b3Cloth::Initialize(const b3ClothDef& def)
B3_ASSERT(m_springCount <= springCapacity); B3_ASSERT(m_springCount <= springCapacity);
} }
b3Cloth::~b3Cloth()
{
b3Free(m_particles);
b3Free(m_springs);
b3Free(m_contacts);
}
void b3Cloth::ResetMass() void b3Cloth::ResetMass()
{ {
for (u32 i = 0; i < m_particleCount; ++i) for (u32 i = 0; i < m_particleCount; ++i)
@ -399,18 +384,6 @@ void b3Cloth::ResetMass()
} }
} }
void b3Cloth::AddShape(b3Shape* shape)
{
B3_ASSERT(m_shapeCount < B3_CLOTH_SHAPE_CAPACITY);
if (m_shapeCount == B3_CLOTH_SHAPE_CAPACITY)
{
return;
}
m_shapes[m_shapeCount++] = shape;
}
void b3Cloth::UpdateContacts() void b3Cloth::UpdateContacts()
{ {
B3_PROFILE("Update Contacts"); B3_PROFILE("Update Contacts");
@ -428,16 +401,16 @@ void b3Cloth::UpdateContacts()
{ {
b3Particle* p = m_particles + i; b3Particle* p = m_particles + i;
// Static particles can't participate in collisions. // Static particles can't participate in unilateral collisions.
if (p->type == e_staticParticle) if (p->type == e_staticParticle)
{ {
continue; continue;
} }
b3ParticleContact* c = m_contacts + i; b3BodyContact* c = m_contacts + i;
// Save the old contact // Save the old contact
b3ParticleContact c0 = *c; b3BodyContact c0 = *c;
b3Sphere s1; b3Sphere s1;
s1.vertex = p->position; s1.vertex = p->position;
@ -446,39 +419,34 @@ void b3Cloth::UpdateContacts()
// Find the deepest penetration // Find the deepest penetration
float32 bestSeparation = 0.0f; float32 bestSeparation = 0.0f;
b3Vec3 bestNormal(0.0f, 0.0f, 0.0f); b3Vec3 bestNormal(0.0f, 0.0f, 0.0f);
u32 bestIndex = ~0; b3Shape* bestShape = nullptr;
for (u32 j = 0; j < m_shapeCount; ++j) for (b3Body* body = m_world->GetBodyList().m_head; body; body = body->GetNext())
{ {
b3Shape* s2 = m_shapes[j]; b3Transform xf = body->GetTransform();
for (b3Shape* shape = body->GetShapeList().m_head; shape; shape = shape->GetNext())
b3Transform xf2;
xf2.SetIdentity();
b3TestSphereOutput output;
if (s2->TestSphere(&output, s1, xf2) == false)
{ {
continue; b3TestSphereOutput output;
} if (shape->TestSphere(&output, s1, xf))
{
if (output.separation < bestSeparation) if (output.separation < bestSeparation)
{ {
bestSeparation = output.separation; bestSeparation = output.separation;
bestNormal = output.normal; bestNormal = output.normal;
bestIndex = j; bestShape = shape;
}
}
} }
} }
if (bestIndex != ~0) if (bestShape != nullptr)
{ {
B3_ASSERT(bestSeparation <= 0.0f); b3Shape* shape = bestShape;
b3Shape* shape = m_shapes[bestIndex];
float32 s = bestSeparation; float32 s = bestSeparation;
b3Vec3 n = bestNormal; b3Vec3 n = bestNormal;
// Update contact manifold // Store the contact manifold
// Remember the normal points from shape 2 to shape 1 (mass) // Here the normal points from shape 2 to shape 1 (mass)
c->n_active = true; c->n_active = true;
c->p1 = p; c->p1 = p;
c->s2 = shape; c->s2 = shape;
@ -606,13 +574,13 @@ void b3Cloth::UpdateContacts()
} }
void b3Cloth::Solve(float32 dt) void b3Cloth::Solve(float32 dt, const b3Vec3& gravity)
{ {
B3_PROFILE("Solve"); B3_PROFILE("Solve");
// Solve // Solve
b3ClothSolverDef solverDef; b3ClothSolverDef solverDef;
solverDef.stack = &m_allocator; solverDef.stack = m_allocator;
solverDef.particleCapacity = m_particleCount; solverDef.particleCapacity = m_particleCount;
solverDef.springCapacity = m_springCount; solverDef.springCapacity = m_springCount;
solverDef.contactCapacity = m_particleCount; solverDef.contactCapacity = m_particleCount;
@ -638,7 +606,7 @@ void b3Cloth::Solve(float32 dt)
} }
// Solve // Solve
solver.Solve(dt, m_gravity); solver.Solve(dt, gravity);
// Clear external applied forces // Clear external applied forces
for (u32 i = 0; i < m_particleCount; ++i) for (u32 i = 0; i < m_particleCount; ++i)
@ -653,7 +621,7 @@ void b3Cloth::Solve(float32 dt)
} }
} }
void b3Cloth::Step(float32 dt) void b3Cloth::Step(float32 dt, const b3Vec3& gravity)
{ {
B3_PROFILE("Step"); B3_PROFILE("Step");
@ -663,7 +631,7 @@ void b3Cloth::Step(float32 dt)
// Solve constraints, integrate state, clear forces and translations. // Solve constraints, integrate state, clear forces and translations.
if (dt > 0.0f) if (dt > 0.0f)
{ {
Solve(dt); Solve(dt, gravity);
} }
} }
@ -696,7 +664,7 @@ void b3Cloth::Draw() const
b3Draw_draw->DrawPoint(p->position, 4.0f, b3Color_green); b3Draw_draw->DrawPoint(p->position, 4.0f, b3Color_green);
} }
b3ParticleContact* c = m_contacts + i; b3BodyContact* c = m_contacts + i;
if (c->n_active) if (c->n_active)
{ {

View File

@ -47,7 +47,7 @@ b3ClothSolver::b3ClothSolver(const b3ClothSolverDef& def)
m_contactCapacity = def.contactCapacity; m_contactCapacity = def.contactCapacity;
m_contactCount = 0; m_contactCount = 0;
m_contacts = (b3ParticleContact**)m_allocator->Allocate(m_contactCapacity * sizeof(b3ParticleContact*)); m_contacts = (b3BodyContact**)m_allocator->Allocate(m_contactCapacity * sizeof(b3BodyContact*));
m_constraintCapacity = def.particleCapacity; m_constraintCapacity = def.particleCapacity;
m_constraintCount = 0; m_constraintCount = 0;
@ -68,7 +68,7 @@ void b3ClothSolver::Add(b3Particle* p)
m_particles[m_particleCount++] = p; m_particles[m_particleCount++] = p;
} }
void b3ClothSolver::Add(b3ParticleContact* c) void b3ClothSolver::Add(b3BodyContact* c)
{ {
m_contacts[m_contactCount++] = c; m_contacts[m_contactCount++] = c;
} }
@ -95,7 +95,7 @@ void b3ClothSolver::InitializeConstraints()
for (u32 i = 0; i < m_contactCount; ++i) for (u32 i = 0; i < m_contactCount; ++i)
{ {
b3ParticleContact* pc = m_contacts[i]; b3BodyContact* pc = m_contacts[i];
b3Particle* p = pc->p1; b3Particle* p = pc->p1;
B3_ASSERT(p->type != e_staticParticle); B3_ASSERT(p->type != e_staticParticle);
@ -179,10 +179,10 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity)
sx0[i] = p->x; sx0[i] = p->x;
} }
// Apply contact position corrections // Apply contact position correction
for (u32 i = 0; i < m_contactCount; ++i) for (u32 i = 0; i < m_contactCount; ++i)
{ {
b3ParticleContact* c = m_contacts[i]; b3BodyContact* c = m_contacts[i];
b3Particle* p = c->p1; b3Particle* p = c->p1;
sy[p->solverId] -= c->s * c->n; sy[p->solverId] -= c->s * c->n;
} }
@ -265,7 +265,7 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity)
// These forces can be used in contact constraint logic. // These forces can be used in contact constraint logic.
for (u32 i = 0; i < m_contactCount; ++i) for (u32 i = 0; i < m_contactCount; ++i)
{ {
b3ParticleContact* c = m_contacts[i]; b3BodyContact* c = m_contacts[i];
b3Particle* p = c->p1; b3Particle* p = c->p1;
b3Vec3 force = f[p->solverId]; b3Vec3 force = f[p->solverId];

View File

@ -17,6 +17,7 @@
*/ */
#include <bounce/dynamics/world.h> #include <bounce/dynamics/world.h>
#include <bounce/dynamics/cloth/cloth.h>
#include <bounce/dynamics/body.h> #include <bounce/dynamics/body.h>
#include <bounce/dynamics/island.h> #include <bounce/dynamics/island.h>
#include <bounce/dynamics/world_listeners.h> #include <bounce/dynamics/world_listeners.h>
@ -30,7 +31,9 @@ extern u32 b3_convexCalls, b3_convexCacheHits;
extern u32 b3_gjkCalls, b3_gjkIters, b3_gjkMaxIters; extern u32 b3_gjkCalls, b3_gjkIters, b3_gjkMaxIters;
extern bool b3_convexCache; extern bool b3_convexCache;
b3World::b3World() : m_bodyBlocks(sizeof(b3Body)) b3World::b3World() :
m_clothBlocks(sizeof(b3Cloth)),
m_bodyBlocks(sizeof(b3Body))
{ {
b3_allocCalls = 0; b3_allocCalls = 0;
b3_maxAllocCalls = 0; b3_maxAllocCalls = 0;
@ -51,6 +54,14 @@ b3World::b3World() : m_bodyBlocks(sizeof(b3Body))
b3World::~b3World() b3World::~b3World()
{ {
b3Cloth* c = m_clothList.m_head;
while (c)
{
b3Cloth* c0 = c;
c = c->m_next;
c0->~b3Cloth();
}
b3Body* b = m_bodyList.m_head; b3Body* b = m_bodyList.m_head;
while (b) while (b)
{ {
@ -82,6 +93,21 @@ void b3World::SetSleeping(bool flag)
} }
} }
b3Cloth* b3World::CreateCloth(const b3ClothDef& def)
{
void* mem = m_clothBlocks.Allocate();
b3Cloth* c = new(mem) b3Cloth(def, this);
m_clothList.PushFront(c);
return c;
}
void b3World::DestroyCloth(b3Cloth* c)
{
m_clothList.Remove(c);
c->~b3Cloth();
m_clothBlocks.Free(c);
}
b3Body* b3World::CreateBody(const b3BodyDef& def) b3Body* b3World::CreateBody(const b3BodyDef& def)
{ {
void* mem = m_bodyBlocks.Allocate(); void* mem = m_bodyBlocks.Allocate();
@ -142,6 +168,9 @@ void b3World::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
} }
//SolveTOI //SolveTOI
// Step cloth dynamics
StepCloth(dt);
} }
void b3World::Solve(float32 dt, u32 velocityIterations, u32 positionIterations) void b3World::Solve(float32 dt, u32 velocityIterations, u32 positionIterations)
@ -337,6 +366,18 @@ void b3World::Solve(float32 dt, u32 velocityIterations, u32 positionIterations)
} }
} }
void b3World::StepCloth(float32 dt)
{
B3_PROFILE("Step Cloth");
b3Cloth* c = m_clothList.m_head;
while (c)
{
c->Step(dt, m_gravity);
c = c->GetNext();
}
}
struct b3RayCastCallback struct b3RayCastCallback
{ {
float32 Report(const b3RayCastInput& input, u32 proxyId) float32 Report(const b3RayCastInput& input, u32 proxyId)