Use a particle tree for cloth
This commit is contained in:
parent
17bddf5426
commit
92cdb42dca
@ -23,6 +23,7 @@
|
|||||||
#include <bounce/common/template/list.h>
|
#include <bounce/common/template/list.h>
|
||||||
#include <bounce/common/memory/stack_allocator.h>
|
#include <bounce/common/memory/stack_allocator.h>
|
||||||
#include <bounce/common/memory/block_pool.h>
|
#include <bounce/common/memory/block_pool.h>
|
||||||
|
#include <bounce/collision/trees/dynamic_tree.h>
|
||||||
|
|
||||||
class b3World;
|
class b3World;
|
||||||
class b3Shape;
|
class b3Shape;
|
||||||
@ -138,12 +139,11 @@ public:
|
|||||||
// Debug draw the cloth using the associated cloth mesh.
|
// Debug draw the cloth using the associated cloth mesh.
|
||||||
void Draw() const;
|
void Draw() const;
|
||||||
private:
|
private:
|
||||||
|
friend class b3Particle;
|
||||||
|
|
||||||
// Compute mass of each particle.
|
// Compute mass of each particle.
|
||||||
void ComputeMass();
|
void ComputeMass();
|
||||||
|
|
||||||
// Update body contacts.
|
|
||||||
void UpdateBodyContacts();
|
|
||||||
|
|
||||||
// Update contacts
|
// Update contacts
|
||||||
void UpdateContacts();
|
void UpdateContacts();
|
||||||
|
|
||||||
@ -174,6 +174,9 @@ private:
|
|||||||
// List of particles
|
// List of particles
|
||||||
b3List2<b3Particle> m_particleList;
|
b3List2<b3Particle> m_particleList;
|
||||||
|
|
||||||
|
// Particle tree
|
||||||
|
b3DynamicTree m_particleTree;
|
||||||
|
|
||||||
// List of forces
|
// List of forces
|
||||||
b3List2<b3Force> m_forceList;
|
b3List2<b3Force> m_forceList;
|
||||||
};
|
};
|
||||||
|
@ -152,6 +152,9 @@ private:
|
|||||||
b3Particle(const b3ParticleDef& def, b3Cloth* cloth);
|
b3Particle(const b3ParticleDef& def, b3Cloth* cloth);
|
||||||
~b3Particle();
|
~b3Particle();
|
||||||
|
|
||||||
|
// Synchronize AABB
|
||||||
|
void Synchronize();
|
||||||
|
|
||||||
// Type
|
// Type
|
||||||
b3ParticleType m_type;
|
b3ParticleType m_type;
|
||||||
|
|
||||||
@ -193,12 +196,15 @@ private:
|
|||||||
// Solution
|
// Solution
|
||||||
b3Vec3 m_x;
|
b3Vec3 m_x;
|
||||||
|
|
||||||
//
|
// Parent cloth
|
||||||
b3Cloth* m_cloth;
|
b3Cloth* m_cloth;
|
||||||
|
|
||||||
// Contact
|
// Contact
|
||||||
b3ParticleBodyContact m_bodyContact;
|
b3ParticleBodyContact m_bodyContact;
|
||||||
|
|
||||||
|
// Particle tree identifier
|
||||||
|
u32 m_treeId;
|
||||||
|
|
||||||
//
|
//
|
||||||
b3Particle* m_prev;
|
b3Particle* m_prev;
|
||||||
|
|
||||||
@ -220,6 +226,8 @@ inline void b3Particle::SetPosition(const b3Vec3& position)
|
|||||||
{
|
{
|
||||||
m_position = position;
|
m_position = position;
|
||||||
m_translation.SetZero();
|
m_translation.SetZero();
|
||||||
|
|
||||||
|
Synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const b3Vec3& b3Particle::GetPosition() const
|
inline const b3Vec3& b3Particle::GetPosition() const
|
||||||
@ -249,6 +257,8 @@ inline float32 b3Particle::GetMass() const
|
|||||||
inline void b3Particle::SetRadius(float32 radius)
|
inline void b3Particle::SetRadius(float32 radius)
|
||||||
{
|
{
|
||||||
m_radius = radius;
|
m_radius = radius;
|
||||||
|
|
||||||
|
Synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float32 b3Particle::GetRadius() const
|
inline float32 b3Particle::GetRadius() const
|
||||||
|
@ -22,10 +22,14 @@
|
|||||||
#include <bounce/cloth/force.h>
|
#include <bounce/cloth/force.h>
|
||||||
#include <bounce/cloth/spring_force.h>
|
#include <bounce/cloth/spring_force.h>
|
||||||
#include <bounce/cloth/cloth_solver.h>
|
#include <bounce/cloth/cloth_solver.h>
|
||||||
|
|
||||||
#include <bounce/dynamics/world.h>
|
#include <bounce/dynamics/world.h>
|
||||||
|
#include <bounce/dynamics/world_listeners.h>
|
||||||
#include <bounce/dynamics/body.h>
|
#include <bounce/dynamics/body.h>
|
||||||
#include <bounce/dynamics/shapes/shape.h>
|
#include <bounce/dynamics/shapes/shape.h>
|
||||||
|
|
||||||
#include <bounce/collision/collision.h>
|
#include <bounce/collision/collision.h>
|
||||||
|
|
||||||
#include <bounce/common/draw.h>
|
#include <bounce/common/draw.h>
|
||||||
|
|
||||||
static B3_FORCE_INLINE u32 b3NextIndex(u32 i)
|
static B3_FORCE_INLINE u32 b3NextIndex(u32 i)
|
||||||
@ -157,9 +161,8 @@ b3Cloth::b3Cloth(const b3ClothDef& def) :
|
|||||||
|
|
||||||
const b3ClothMesh* m = m_mesh;
|
const b3ClothMesh* m = m_mesh;
|
||||||
|
|
||||||
m_vertexParticles = (b3Particle**)b3Alloc(m->vertexCount * sizeof(b3Particle*));
|
|
||||||
|
|
||||||
// Create particles
|
// Create particles
|
||||||
|
m_vertexParticles = (b3Particle**)b3Alloc(m->vertexCount * sizeof(b3Particle*));
|
||||||
for (u32 i = 0; i < m->vertexCount; ++i)
|
for (u32 i = 0; i < m->vertexCount; ++i)
|
||||||
{
|
{
|
||||||
b3ParticleDef pd;
|
b3ParticleDef pd;
|
||||||
@ -170,6 +173,11 @@ b3Cloth::b3Cloth(const b3ClothDef& def) :
|
|||||||
|
|
||||||
p->m_vertex = i;
|
p->m_vertex = i;
|
||||||
|
|
||||||
|
b3AABB3 aabb;
|
||||||
|
aabb.Set(p->m_position, p->m_radius);
|
||||||
|
|
||||||
|
p->m_treeId = m_particleTree.InsertNode(aabb, p);
|
||||||
|
|
||||||
m_vertexParticles[i] = p;
|
m_vertexParticles[i] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +253,9 @@ b3Cloth::~b3Cloth()
|
|||||||
{
|
{
|
||||||
b3Particle* p0 = p;
|
b3Particle* p0 = p;
|
||||||
p = p->m_next;
|
p = p->m_next;
|
||||||
|
|
||||||
|
m_particleTree.RemoveNode(p0->m_treeId);
|
||||||
|
|
||||||
p0->~b3Particle();
|
p0->~b3Particle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +275,14 @@ b3Particle* b3Cloth::CreateParticle(const b3ParticleDef& def)
|
|||||||
{
|
{
|
||||||
void* mem = m_particleBlocks.Allocate();
|
void* mem = m_particleBlocks.Allocate();
|
||||||
b3Particle* p = new(mem) b3Particle(def, this);
|
b3Particle* p = new(mem) b3Particle(def, this);
|
||||||
|
|
||||||
|
b3AABB3 aabb;
|
||||||
|
aabb.Set(p->m_position, p->m_radius);
|
||||||
|
|
||||||
|
p->m_treeId = m_particleTree.InsertNode(aabb, p);
|
||||||
|
|
||||||
m_particleList.PushFront(p);
|
m_particleList.PushFront(p);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +293,8 @@ void b3Cloth::DestroyParticle(b3Particle* particle)
|
|||||||
m_vertexParticles[particle->m_vertex] = NULL;
|
m_vertexParticles[particle->m_vertex] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_particleTree.RemoveNode(particle->m_treeId);
|
||||||
|
|
||||||
m_particleList.Remove(particle);
|
m_particleList.Remove(particle);
|
||||||
particle->~b3Particle();
|
particle->~b3Particle();
|
||||||
m_particleBlocks.Free(particle);
|
m_particleBlocks.Free(particle);
|
||||||
@ -399,46 +419,22 @@ bool b3Cloth::RayCast(b3RayCastOutput* output, const b3RayCastInput* input, u32
|
|||||||
return b3RayCast(output, input, v1, v2, v3);
|
return b3RayCast(output, input, v1, v2, v3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3Cloth::UpdateBodyContacts()
|
class b3ClothUpdateContactsQueryListener : public b3QueryListener
|
||||||
{
|
{
|
||||||
B3_PROFILE("Cloth Update Body Contacts");
|
public:
|
||||||
|
bool ReportShape(b3Shape* shape)
|
||||||
// Is there a world attached to this cloth?
|
|
||||||
if (m_world == nullptr)
|
|
||||||
{
|
{
|
||||||
return;
|
b3Body* body = shape->GetBody();
|
||||||
}
|
|
||||||
|
|
||||||
// Create contacts
|
|
||||||
for (b3Particle* p = m_particleList.m_head; p; p = p->m_next)
|
|
||||||
{
|
|
||||||
b3Sphere s1;
|
|
||||||
s1.vertex = p->m_position;
|
|
||||||
s1.radius = p->m_radius;
|
|
||||||
|
|
||||||
// Find the deepest penetration
|
|
||||||
b3Shape* bestShape = nullptr;
|
|
||||||
float32 bestSeparation = 0.0f;
|
|
||||||
b3Vec3 bestPoint(0.0f, 0.0f, 0.0f);
|
|
||||||
b3Vec3 bestNormal(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
for (b3Body* body = m_world->GetBodyList().m_head; body; body = body->GetNext())
|
|
||||||
{
|
|
||||||
if (p->m_type != e_dynamicParticle)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body->GetType() != e_staticBody)
|
if (body->GetType() != e_staticBody)
|
||||||
{
|
{
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
b3Transform xf = body->GetTransform();
|
b3Transform xf = body->GetTransform();
|
||||||
for (b3Shape* shape = body->GetShapeList().m_head; shape; shape = shape->GetNext())
|
|
||||||
{
|
|
||||||
b3TestSphereOutput output;
|
b3TestSphereOutput output;
|
||||||
if (shape->TestSphere(&output, s1, xf))
|
if (shape->TestSphere(&output, sphere, xf))
|
||||||
{
|
{
|
||||||
if (output.separation < bestSeparation)
|
if (output.separation < bestSeparation)
|
||||||
{
|
{
|
||||||
@ -449,20 +445,53 @@ void b3Cloth::UpdateBodyContacts()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b3Sphere sphere;
|
||||||
|
b3Shape* bestShape;
|
||||||
|
float32 bestSeparation;
|
||||||
|
b3Vec3 bestPoint;
|
||||||
|
b3Vec3 bestNormal;
|
||||||
|
};
|
||||||
|
|
||||||
|
void b3Cloth::UpdateContacts()
|
||||||
|
{
|
||||||
|
B3_PROFILE("Cloth Update Contacts");
|
||||||
|
|
||||||
|
// Is there a world attached to this cloth?
|
||||||
|
if (m_world == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestShape == nullptr)
|
// Create contacts
|
||||||
|
for (b3Particle* p = m_particleList.m_head; p; p = p->m_next)
|
||||||
|
{
|
||||||
|
if (p->m_type != e_dynamicParticle)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3AABB3 aabb = m_particleTree.GetAABB(p->m_treeId);
|
||||||
|
|
||||||
|
b3ClothUpdateContactsQueryListener listener;
|
||||||
|
listener.sphere.vertex = p->m_position;
|
||||||
|
listener.sphere.radius = p->m_radius;
|
||||||
|
listener.bestShape = nullptr;
|
||||||
|
listener.bestSeparation = 0.0f;
|
||||||
|
|
||||||
|
m_world->QueryAABB(&listener, aabb);
|
||||||
|
|
||||||
|
if (listener.bestShape == nullptr)
|
||||||
{
|
{
|
||||||
p->m_bodyContact.active = false;
|
p->m_bodyContact.active = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the the normal points from the particle 1 to shape 2
|
b3Shape* shape = listener.bestShape;
|
||||||
b3Shape* shape = bestShape;
|
|
||||||
b3Body* body = shape->GetBody();
|
b3Body* body = shape->GetBody();
|
||||||
float32 separation = bestSeparation;
|
float32 separation = listener.bestSeparation;
|
||||||
b3Vec3 point = bestPoint;
|
b3Vec3 point = listener.bestPoint;
|
||||||
b3Vec3 normal = -bestNormal;
|
b3Vec3 normal = -listener.bestNormal;
|
||||||
|
|
||||||
b3ParticleBodyContact* c = &p->m_bodyContact;
|
b3ParticleBodyContact* c = &p->m_bodyContact;
|
||||||
|
|
||||||
@ -522,12 +551,6 @@ void b3Cloth::Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterations, u
|
|||||||
solver.Solve(dt, gravity, velocityIterations, positionIterations);
|
solver.Solve(dt, gravity, velocityIterations, positionIterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3Cloth::UpdateContacts()
|
|
||||||
{
|
|
||||||
// Update body contacts
|
|
||||||
UpdateBodyContacts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
|
void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
|
||||||
{
|
{
|
||||||
B3_PROFILE("Cloth Step");
|
B3_PROFILE("Cloth Step");
|
||||||
@ -535,7 +558,7 @@ void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
|
|||||||
// Update contacts
|
// Update contacts
|
||||||
UpdateContacts();
|
UpdateContacts();
|
||||||
|
|
||||||
// Solve constraints, integrate state, clear forces and translations.
|
// Integrate state, solve constraints.
|
||||||
if (dt > 0.0f)
|
if (dt > 0.0f)
|
||||||
{
|
{
|
||||||
Solve(dt, m_gravity, velocityIterations, positionIterations);
|
Solve(dt, m_gravity, velocityIterations, positionIterations);
|
||||||
@ -547,6 +570,17 @@ void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
|
|||||||
p->m_force.SetZero();
|
p->m_force.SetZero();
|
||||||
p->m_translation.SetZero();
|
p->m_translation.SetZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synchronize particles
|
||||||
|
for (b3Particle* p = m_particleList.m_head; p; p = p->m_next)
|
||||||
|
{
|
||||||
|
if (p->m_type == e_staticParticle)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->Synchronize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3Cloth::Draw() const
|
void b3Cloth::Draw() const
|
||||||
|
@ -379,7 +379,7 @@ void b3ClothSolver::SolveMPCG(b3DenseVec3& x,
|
|||||||
u32 iteration = 0;
|
u32 iteration = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (iteration >= maxIterations)
|
if (iteration == maxIterations)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,6 @@
|
|||||||
|
|
||||||
#include <bounce/cloth/particle.h>
|
#include <bounce/cloth/particle.h>
|
||||||
#include <bounce/cloth/cloth.h>
|
#include <bounce/cloth/cloth.h>
|
||||||
#include <bounce/cloth/cloth_solver.h>
|
|
||||||
#include <bounce/cloth/dense_vec3.h>
|
|
||||||
#include <bounce/cloth/sparse_sym_mat33.h>
|
|
||||||
|
|
||||||
void b3ParticleBodyContactWorldPoint::Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB)
|
void b3ParticleBodyContactWorldPoint::Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB)
|
||||||
{
|
{
|
||||||
@ -60,6 +57,14 @@ b3Particle::~b3Particle()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void b3Particle::Synchronize()
|
||||||
|
{
|
||||||
|
b3AABB3 aabb;
|
||||||
|
aabb.Set(m_position, m_radius);
|
||||||
|
|
||||||
|
m_cloth->m_particleTree.UpdateNode(m_treeId, aabb);
|
||||||
|
}
|
||||||
|
|
||||||
void b3Particle::SetType(b3ParticleType type)
|
void b3Particle::SetType(b3ParticleType type)
|
||||||
{
|
{
|
||||||
if (m_type == type)
|
if (m_type == type)
|
||||||
@ -74,6 +79,8 @@ void b3Particle::SetType(b3ParticleType type)
|
|||||||
{
|
{
|
||||||
m_velocity.SetZero();
|
m_velocity.SetZero();
|
||||||
m_translation.SetZero();
|
m_translation.SetZero();
|
||||||
|
|
||||||
|
Synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bodyContact.active = false;
|
m_bodyContact.active = false;
|
||||||
|
@ -717,7 +717,7 @@ public:
|
|||||||
|
|
||||||
if (body->GetType() != e_staticBody)
|
if (body->GetType() != e_staticBody)
|
||||||
{
|
{
|
||||||
//continue;
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
b3Transform xf = body->GetTransform();
|
b3Transform xf = body->GetTransform();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user