Small refactor. Allow cloth particle to collide with multiple shapes. This is a more general solution.

This commit is contained in:
Irlan 2019-06-23 10:52:41 -03:00
parent 39b27c86d2
commit 13eab5d00d
19 changed files with 426 additions and 247 deletions

View File

@ -26,16 +26,14 @@
#include <bounce/cloth/cloth_contact_manager.h>
class b3World;
class b3Shape;
class b3Particle;
class b3ClothTriangle;
class b3Force;
struct b3ParticleBodyContact;
struct b3ParticleDef;
class b3Particle;
struct b3ForceDef;
class b3Force;
class b3ClothTriangle;
struct b3ClothMesh;
@ -44,8 +42,6 @@ class b3RayCastListener;
struct b3RayCastInput;
struct b3RayCastOutput;
struct b3ClothAABBProxy;
struct b3ClothRayCastSingleOutput
{
u32 triangle;
@ -161,9 +157,6 @@ private:
// Compute mass of each particle.
void ComputeMass();
// Update particle-body contacts
void UpdateParticleBodyContacts();
// Solve
void Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterations, u32 positionIterations);

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* 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_CLOTH_COLLISION_H
#define B3_CLOTH_COLLISION_H
#include <bounce/common/math/vec3.h>
// Cloth primitive type
enum b3ClothAABBProxyType
{
e_particleProxy,
e_triangleProxy
};
// Cloth primitive broadphase proxy
struct b3ClothAABBProxy
{
b3ClothAABBProxyType type;
void* owner;
};
#endif

View File

@ -19,7 +19,8 @@
#ifndef B3_CLOTH_CONTACT_MANAGER_H
#define B3_CLOTH_CONTACT_MANAGER_H
#include <bounce/cloth/cloth_contact.h>
#include <bounce/cloth/cloth_particle_body_contact.h>
#include <bounce/cloth/cloth_particle_triangle_contact.h>
#include <bounce/collision/broad_phase.h>
#include <bounce/common/memory/block_pool.h>
#include <bounce/common/template/list.h>
@ -32,21 +33,31 @@ class b3ClothContactManager
public:
b3ClothContactManager();
// The broad-phase callback.
void AddPair(void* data1, void* data2);
void FindNewContacts();
void AddPair(void* data1, void* data2);
void FindNewClothContacts();
void AddPSPair(b3Particle* p1, b3Shape* s2);
void FindNewBodyContacts();
void UpdateContacts();
void UpdateClothContacts();
void UpdateBodyContacts();
b3ParticleTriangleContact* CreateParticleTriangleContact();
void Destroy(b3ParticleTriangleContact* c);
b3ParticleBodyContact* CreateParticleBodyContact();
void Destroy(b3ParticleBodyContact* c);
b3BlockPool m_particleTriangleContactBlocks;
b3BlockPool m_particleBodyContactBlocks;
b3Cloth* m_cloth;
b3BroadPhase m_broadPhase;
b3List2<b3ParticleTriangleContact> m_particleTriangleContactList;
b3List2<b3ParticleBodyContact> m_particleBodyContactList;
};
#endif

View File

@ -27,7 +27,7 @@ class b3StackAllocator;
class b3Particle;
class b3Body;
struct b3ParticleBodyContact;
class b3ParticleBodyContact;
class b3ParticleTriangleContact;
struct b3ClothSolverBodyContactVelocityConstraint

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* 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_CLOTH_PARTICLE_BODY_CONTACT_H
#define B3_CLOTH_PARTICLE_BODY_CONTACT_H
#include <bounce/common/template/list.h>
#include <bounce/common/math/vec2.h>
#include <bounce/common/math/vec3.h>
#include <bounce/common/math/transform.h>
class b3Particle;
class b3Shape;
// A contact between a particle and a body
class b3ParticleBodyContact
{
public:
private:
friend class b3List2<b3ParticleBodyContact>;
friend class b3Cloth;
friend class b3Particle;
friend class b3ClothContactManager;
friend class b3ClothSolver;
friend class b3ClothContactSolver;
friend struct b3ParticleBodyContactWorldPoint;
b3ParticleBodyContact() { }
~b3ParticleBodyContact() { }
void Update();
b3Particle* m_p1;
b3Shape* m_s2;
bool m_active;
// Contact constraint
b3Vec3 m_normal1;
b3Vec3 m_localPoint1;
b3Vec3 m_localPoint2;
float32 m_normalImpulse;
// Friction constraint
b3Vec3 m_tangent1, m_tangent2;
b3Vec2 m_tangentImpulse;
b3ParticleBodyContact* m_prev;
b3ParticleBodyContact* m_next;
};
struct b3ParticleBodyContactWorldPoint
{
void Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB);
b3Vec3 point;
b3Vec3 normal;
float32 separation;
};
#endif

View File

@ -16,8 +16,8 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_CLOTH_CONTACT_H
#define B3_CLOTH_CONTACT_H
#ifndef B3_CLOTH_PARTICLE_TRIANGLE_CONTACT_H
#define B3_CLOTH_PARTICLE_TRIANGLE_CONTACT_H
#include <bounce/common/template/list.h>
@ -29,11 +29,11 @@ class b3ParticleTriangleContact
{
public:
private:
friend class b3List2<b3ParticleTriangleContact>;
friend class b3Cloth;
friend class b3Particle;
friend class b3ClothTriangle;
friend class b3ClothContactManager;
friend class b3List2<b3ParticleTriangleContact>;
friend class b3ClothContactSolver;
b3ParticleTriangleContact() { }

View File

@ -26,7 +26,7 @@ class b3StackAllocator;
class b3Particle;
class b3Force;
struct b3ParticleBodyContact;
class b3ParticleBodyContact;
class b3ParticleTriangleContact;
struct b3ClothSolverDef

View File

@ -19,7 +19,7 @@
#ifndef B3_CLOTH_TRIANGLE_H
#define B3_CLOTH_TRIANGLE_H
#include <bounce/cloth/particle.h>
#include <bounce/cloth/cloth_collision.h>
// A cloth triangle
class b3ClothTriangle

View File

@ -19,14 +19,10 @@
#ifndef B3_PARTICLE_H
#define B3_PARTICLE_H
#include <bounce/cloth/force.h>
#include <bounce/common/math/transform.h>
#include <bounce/common/math/vec2.h>
#include <bounce/cloth/cloth_collision.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.
@ -38,7 +34,7 @@ enum b3ParticleType
e_dynamicParticle
};
//
// Particle definition
struct b3ParticleDef
{
b3ParticleDef()
@ -63,48 +59,6 @@ struct b3ParticleDef
void* userData;
};
// A contact between a particle and a solid
struct b3ParticleBodyContact
{
b3Particle* p1;
b3Shape* s2;
// Contact constraint
b3Vec3 normal1;
b3Vec3 localPoint1;
b3Vec3 localPoint2;
float32 normalImpulse;
// Friction constraint
b3Vec3 t1, t2;
b3Vec2 tangentImpulse;
bool active;
};
struct b3ParticleBodyContactWorldPoint
{
void Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB);
b3Vec3 point;
b3Vec3 normal;
float32 separation;
};
// Cloth primitive type
enum b3ClothAABBProxyType
{
e_particleProxy,
e_triangleProxy
};
// Cloth primitive broadphase proxy
struct b3ClothAABBProxy
{
b3ClothAABBProxyType type;
void* owner;
};
// A cloth particle.
class b3Particle
{
@ -162,6 +116,7 @@ private:
friend class b3ClothSolver;
friend class b3ClothForceSolver;
friend class b3ClothContactManager;
friend class b3ParticleBodyContact;
friend class b3ParticleTriangleContact;
friend class b3ClothContactSolver;
friend class b3Force;
@ -223,9 +178,6 @@ private:
// Parent cloth
b3Cloth* m_cloth;
// Contact
b3ParticleBodyContact m_bodyContact;
// AABB Proxy
b3ClothAABBProxy m_aabbProxy;

View File

@ -140,6 +140,9 @@ public:
// Set the user data associated with this shape.
void SetUserData(void* data);
// Get broadphase AABB
const b3AABB3& GetAABB() const;
// Dump this shape to the log file.
void Dump(u32 bodyIndex) const;

View File

@ -23,14 +23,6 @@
#include <bounce/cloth/force.h>
#include <bounce/cloth/spring_force.h>
#include <bounce/cloth/cloth_solver.h>
#include <bounce/dynamics/world.h>
#include <bounce/dynamics/world_listeners.h>
#include <bounce/dynamics/body.h>
#include <bounce/dynamics/shapes/shape.h>
#include <bounce/collision/collision.h>
#include <bounce/common/draw.h>
static B3_FORCE_INLINE u32 b3NextIndex(u32 i)
@ -501,105 +493,6 @@ bool b3Cloth::RayCast(b3RayCastOutput* output, const b3RayCastInput* input, u32
return b3RayCast(output, input, v1, v2, v3);
}
class b3ClothUpdateContactsQueryListener : public b3QueryListener
{
public:
bool ReportShape(b3Shape* shape)
{
b3Body* body = shape->GetBody();
if (body->GetType() != e_staticBody)
{
return true;
}
b3Transform xf = body->GetTransform();
b3TestSphereOutput output;
if (shape->TestSphere(&output, sphere, xf))
{
if (output.separation < bestSeparation)
{
bestShape = shape;
bestSeparation = output.separation;
bestPoint = output.point;
bestNormal = output.normal;
}
}
return true;
}
b3Sphere sphere;
b3Shape* bestShape;
float32 bestSeparation;
b3Vec3 bestPoint;
b3Vec3 bestNormal;
};
void b3Cloth::UpdateParticleBodyContacts()
{
B3_PROFILE("Cloth Update Particle Body Contacts");
// Is there a world attached to this cloth?
if (m_world == nullptr)
{
return;
}
// Create contacts
for (b3Particle* p = m_particleList.m_head; p; p = p->m_next)
{
if (p->m_type != e_dynamicParticle)
{
continue;
}
b3AABB3 aabb = m_contactManager.m_broadPhase.GetAABB(p->m_broadPhaseId);
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;
continue;
}
b3Shape* shape = listener.bestShape;
b3Body* body = shape->GetBody();
float32 separation = listener.bestSeparation;
b3Vec3 point = listener.bestPoint;
b3Vec3 normal = -listener.bestNormal;
b3ParticleBodyContact* c = &p->m_bodyContact;
b3ParticleBodyContact c0 = *c;
c->active = true;
c->p1 = p;
c->s2 = shape;
c->normal1 = normal;
c->localPoint1.SetZero();
c->localPoint2 = body->GetLocalPoint(point);
c->t1 = b3Perp(normal);
c->t2 = b3Cross(c->t1, normal);
c->normalImpulse = 0.0f;
c->tangentImpulse.SetZero();
if (c0.active == true)
{
c->normalImpulse = c0.normalImpulse;
c->tangentImpulse = c0.tangentImpulse;
}
}
}
void b3Cloth::Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterations, u32 positionIterations)
{
B3_PROFILE("Cloth Solve");
@ -624,14 +517,6 @@ void b3Cloth::Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterations, u
solver.Add(f);
}
for (b3Particle* p = m_particleList.m_head; p; p = p->m_next)
{
if (p->m_bodyContact.active)
{
solver.Add(&p->m_bodyContact);
}
}
for (b3ParticleTriangleContact* c = m_contactManager.m_particleTriangleContactList.m_head; c; c = c->m_next)
{
if (c->m_active)
@ -640,6 +525,14 @@ void b3Cloth::Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterations, u
}
}
for (b3ParticleBodyContact* c = m_contactManager.m_particleBodyContactList.m_head; c; c = c->m_next)
{
if (c->m_active)
{
solver.Add(c);
}
}
// Solve
solver.Solve(dt, gravity, velocityIterations, positionIterations);
}
@ -648,10 +541,7 @@ void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
{
B3_PROFILE("Cloth Step");
// Update particle-body contacts
UpdateParticleBodyContacts();
// Update self-contacts
// Update contacts
m_contactManager.UpdateContacts();
// Integrate state, solve constraints.
@ -695,7 +585,7 @@ void b3Cloth::Step(float32 dt, u32 velocityIterations, u32 positionIterations)
m_triangles[i].Synchronize(displacement);
}
// Find new self-contacts
// Find new contacts
m_contactManager.FindNewContacts();
}

View File

@ -21,20 +21,107 @@
#include <bounce/cloth/cloth_mesh.h>
#include <bounce/cloth/particle.h>
#include <bounce/cloth/cloth_triangle.h>
#include <bounce/dynamics/world.h>
#include <bounce/dynamics/world_listeners.h>
#include <bounce/dynamics/shapes/shape.h>
#include <bounce/dynamics/body.h>
b3ClothContactManager::b3ClothContactManager() :
m_particleTriangleContactBlocks(sizeof(b3ParticleTriangleContact))
m_particleTriangleContactBlocks(sizeof(b3ParticleTriangleContact)),
m_particleBodyContactBlocks(sizeof(b3ParticleBodyContact))
{
}
void b3ClothContactManager::FindNewContacts()
{
B3_PROFILE("Cloth Find New Contacts");
FindNewClothContacts();
FindNewBodyContacts();
}
void b3ClothContactManager::FindNewClothContacts()
{
B3_PROFILE("Cloth Find New Cloth Contacts");
m_broadPhase.FindPairs(this);
}
class b3ClothContactManagerFindNewBodyContactsQueryListener : public b3QueryListener
{
public:
virtual bool ReportShape(b3Shape* s2)
{
cm->AddPSPair(p1, s2);
// Keep looking for overlaps
return true;
}
b3ClothContactManager* cm;
b3Particle* p1;
};
void b3ClothContactManager::FindNewBodyContacts()
{
B3_PROFILE("Cloth Find New Body Contacts");
// Is there a world attached to this cloth?
if (m_cloth->m_world == nullptr)
{
return;
}
for (b3Particle* p = m_cloth->m_particleList.m_head; p; p = p->m_next)
{
if (p->m_type != e_dynamicParticle)
{
continue;
}
b3AABB3 aabb = m_broadPhase.GetAABB(p->m_broadPhaseId);
b3ClothContactManagerFindNewBodyContactsQueryListener listener;
listener.cm = this;
listener.p1 = p;
m_cloth->m_world->QueryAABB(&listener, aabb);
}
}
void b3ClothContactManager::AddPSPair(b3Particle* p1, b3Shape* s2)
{
// Check if there is a contact between the two entities.
for (b3ParticleBodyContact* c = m_particleBodyContactList.m_head; c; c = c->m_next)
{
if (c->m_p1 == p1 && c->m_s2 == s2)
{
// A contact already exists.
return;
}
}
bool isntDynamic1 = p1->m_type != e_dynamicParticle;
bool isntDynamic2 = s2->GetBody()->GetType() != e_dynamicBody;
if (isntDynamic1 && isntDynamic2)
{
// The entities must not collide with each other.
return;
}
// Create a new contact.
b3ParticleBodyContact* c = CreateParticleBodyContact();
c->m_p1 = p1;
c->m_s2 = s2;
c->m_active = false;
c->m_normalImpulse = 0.0f;
c->m_tangentImpulse.SetZero();
// Add the contact to the body contact list.
m_particleBodyContactList.PushFront(c);
}
void b3ClothContactManager::AddPair(void* data1, void* data2)
{
b3ClothAABBProxy* proxy1 = (b3ClothAABBProxy*)data1;
@ -126,9 +213,30 @@ void b3ClothContactManager::Destroy(b3ParticleTriangleContact* c)
m_particleTriangleContactBlocks.Free(c);
}
b3ParticleBodyContact* b3ClothContactManager::CreateParticleBodyContact()
{
void* block = m_particleBodyContactBlocks.Allocate();
return new(block) b3ParticleBodyContact();
}
void b3ClothContactManager::Destroy(b3ParticleBodyContact* c)
{
m_particleBodyContactList.Remove(c);
c->~b3ParticleBodyContact();
m_particleBodyContactBlocks.Free(c);
}
void b3ClothContactManager::UpdateContacts()
{
B3_PROFILE("Cloth Update Contacts");
UpdateClothContacts();
UpdateBodyContacts();
}
void b3ClothContactManager::UpdateClothContacts()
{
B3_PROFILE("Cloth Update Cloth Contacts");
// Update the state of particle-triangle contacts.
b3ParticleTriangleContact* c = m_particleTriangleContactList.m_head;
@ -162,6 +270,46 @@ void b3ClothContactManager::UpdateContacts()
// The contact persists.
c->Update();
c = c->m_next;
}
}
void b3ClothContactManager::UpdateBodyContacts()
{
B3_PROFILE("Cloth Update Body Contacts");
// Update the state of particle-body contacts.
b3ParticleBodyContact* c = m_particleBodyContactList.m_head;
while (c)
{
bool isntDynamic1 = c->m_p1->m_type != e_dynamicParticle;
bool isntDynamic2 = c->m_s2->GetType() != e_dynamicBody;
// Cease the contact if entities must not collide with each other.
if (isntDynamic1 && isntDynamic2)
{
b3ParticleBodyContact* quack = c;
c = c->m_next;
Destroy(quack);
continue;
}
b3AABB3 aabb1 = m_broadPhase.GetAABB(c->m_p1->m_broadPhaseId);
b3AABB3 aabb2 = c->m_s2->GetAABB();
// Destroy the contact if entities AABBs are not overlapping.
bool overlap = b3TestOverlap(aabb1, aabb2);
if (overlap == false)
{
b3ParticleBodyContact* quack = c;
c = c->m_next;
Destroy(quack);
continue;
}
// The contact persists.
c->Update();
c = c->m_next;
}
}

View File

@ -59,35 +59,35 @@ void b3ClothContactSolver::InitializeBodyContactConstraints()
b3ClothSolverBodyContactVelocityConstraint* vc = m_bodyVelocityConstraints + i;
b3ClothSolverBodyContactPositionConstraint* pc = m_bodyPositionConstraints + i;
vc->indexA = c->p1->m_solverId;
vc->bodyB = c->s2->GetBody();
vc->indexA = c->m_p1->m_solverId;
vc->bodyB = c->m_s2->GetBody();
vc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
vc->invMassA = c->m_p1->m_type == e_staticParticle ? 0.0f : c->m_p1->m_invMass;
vc->invMassB = vc->bodyB->GetInverseMass();
vc->invIA.SetZero();
vc->invIB = vc->bodyB->GetWorldInverseInertia();
vc->friction = b3MixFriction(c->p1->m_friction, c->s2->GetFriction());
vc->friction = b3MixFriction(c->m_p1->m_friction, c->m_s2->GetFriction());
pc->indexA = c->p1->m_solverId;
pc->indexA = c->m_p1->m_solverId;
pc->bodyB = vc->bodyB;
pc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
pc->invMassA = c->m_p1->m_type == e_staticParticle ? 0.0f : c->m_p1->m_invMass;
pc->invMassB = vc->bodyB->m_invMass;
pc->invIA.SetZero();
pc->invIB = vc->bodyB->m_worldInvI;
pc->radiusA = c->p1->m_radius;
pc->radiusB = c->s2->m_radius;
pc->radiusA = c->m_p1->m_radius;
pc->radiusB = c->m_s2->m_radius;
pc->localCenterA.SetZero();
pc->localCenterB = pc->bodyB->m_sweep.localCenter;
pc->normalA = c->normal1;
pc->localPointA = c->localPoint1;
pc->localPointB = c->localPoint2;
pc->normalA = c->m_normal1;
pc->localPointA = c->m_localPoint1;
pc->localPointB = c->m_localPoint2;
}
for (u32 i = 0; i < m_bodyContactCount; ++i)
@ -126,8 +126,8 @@ void b3ClothContactSolver::InitializeBodyContactConstraints()
wp.Initialize(c, pc->radiusA, xfA, pc->radiusB, xfB);
vc->normal = wp.normal;
vc->tangent1 = c->t1;
vc->tangent2 = c->t2;
vc->tangent1 = c->m_tangent1;
vc->tangent2 = c->m_tangent2;
vc->point = wp.point;
b3Vec3 point = vc->point;
@ -138,8 +138,8 @@ void b3ClothContactSolver::InitializeBodyContactConstraints()
vc->rA = rA;
vc->rB = rB;
vc->normalImpulse = c->normalImpulse;
vc->tangentImpulse = c->tangentImpulse;
vc->normalImpulse = c->m_normalImpulse;
vc->tangentImpulse = c->m_tangentImpulse;
{
b3Vec3 n = vc->normal;
@ -602,8 +602,8 @@ void b3ClothContactSolver::StoreImpulses()
b3ParticleBodyContact* c = m_bodyContacts[i];
b3ClothSolverBodyContactVelocityConstraint* vc = m_bodyVelocityConstraints + i;
c->normalImpulse = vc->normalImpulse;
c->tangentImpulse = vc->tangentImpulse;
c->m_normalImpulse = vc->normalImpulse;
c->m_tangentImpulse = vc->tangentImpulse;
}
for (u32 i = 0; i < m_triangleContactCount; ++i)

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* 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.
*/
#include <bounce/cloth/cloth_particle_body_contact.h>
#include <bounce/cloth/particle.h>
#include <bounce/dynamics/shapes/shape.h>
#include <bounce/dynamics/body.h>
void b3ParticleBodyContact::Update()
{
b3Sphere sphere;
sphere.radius = m_p1->m_radius;
sphere.vertex = m_p1->m_position;
b3Shape* shape = m_s2;
b3Body* body = shape->GetBody();
b3Transform xf = body->GetTransform();
b3TestSphereOutput out;
if (shape->TestSphere(&out, sphere, xf) == false)
{
m_active = false;
return;
}
m_active = true;
m_normal1 = -out.normal;
m_localPoint1.SetZero();
m_localPoint2 = body->GetLocalPoint(out.point);
m_tangent1 = b3Perp(m_normal1);
m_tangent2 = b3Cross(m_tangent1, m_normal1);
}
void b3ParticleBodyContactWorldPoint::Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB)
{
b3Vec3 nA = c->m_normal1;
b3Vec3 cA = xfA * c->m_localPoint1;
b3Vec3 cB = xfB * c->m_localPoint2;
b3Vec3 pA = cA + rA * nA;
b3Vec3 pB = cB - rB * nA;
point = 0.5f * (pA + pB);
normal = nA;
separation = b3Dot(cB - cA, nA) - rA - rB;
}

View File

@ -16,7 +16,7 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <bounce/cloth/cloth_contact.h>
#include <bounce/cloth/cloth_particle_triangle_contact.h>
#include <bounce/cloth/cloth_mesh.h>
#include <bounce/cloth/particle.h>
#include <bounce/cloth/cloth_triangle.h>

View File

@ -167,7 +167,7 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity, u32 velocityIterati
// Synchronize bodies
for (u32 i = 0; i < m_bodyContactCount; ++i)
{
b3Body* body = m_bodyContacts[i]->s2->GetBody();
b3Body* body = m_bodyContacts[i]->m_s2->GetBody();
body->SynchronizeTransform();

View File

@ -18,6 +18,7 @@
#include <bounce/cloth/cloth_triangle.h>
#include <bounce/cloth/cloth.h>
#include <bounce/cloth/particle.h>
#include <bounce/cloth/cloth_mesh.h>
void b3ClothTriangle::Synchronize(const b3Vec3& displacement)

View File

@ -21,21 +21,6 @@
#include <bounce/cloth/cloth_mesh.h>
#include <bounce/cloth/cloth_triangle.h>
void b3ParticleBodyContactWorldPoint::Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB)
{
b3Vec3 nA = c->normal1;
b3Vec3 cA = b3Mul(xfA, c->localPoint1);
b3Vec3 cB = b3Mul(xfB, c->localPoint2);
b3Vec3 pA = cA + rA * nA;
b3Vec3 pB = cB - rB * nA;
point = 0.5f * (pA + pB);
normal = nA;
separation = b3Dot(cB - cA, nA) - rA - rB;
}
b3Particle::b3Particle(const b3ParticleDef& def, b3Cloth* cloth)
{
m_cloth = cloth;
@ -63,7 +48,6 @@ b3Particle::b3Particle(const b3ParticleDef& def, b3Cloth* cloth)
m_userData = nullptr;
m_x.SetZero();
m_vertex = ~0;
m_bodyContact.active = false;
}
b3Particle::~b3Particle()
@ -99,22 +83,38 @@ void b3Particle::SynchronizeTriangles()
void b3Particle::DestroyContacts()
{
// Destroy body contacts
m_bodyContact.active = false;
// Destroy triangle contacts
b3ParticleTriangleContact* c = m_cloth->m_contactManager.m_particleTriangleContactList.m_head;
while (c)
{
if (c->m_p1 == this)
// Destroy body contacts
b3ParticleBodyContact* c = m_cloth->m_contactManager.m_particleBodyContactList.m_head;
while (c)
{
b3ParticleTriangleContact* quack = c;
c = c->m_next;
m_cloth->m_contactManager.Destroy(quack);
continue;
}
if (c->m_p1 == this)
{
b3ParticleBodyContact* quack = c;
c = c->m_next;
m_cloth->m_contactManager.Destroy(quack);
continue;
}
c = c->m_next;
c = c->m_next;
}
}
{
// Destroy triangle contacts
b3ParticleTriangleContact* c = m_cloth->m_contactManager.m_particleTriangleContactList.m_head;
while (c)
{
if (c->m_p1 == this)
{
b3ParticleTriangleContact* quack = c;
c = c->m_next;
m_cloth->m_contactManager.Destroy(quack);
continue;
}
c = c->m_next;
}
}
}
@ -132,13 +132,13 @@ void b3Particle::SetType(b3ParticleType type)
{
m_velocity.SetZero();
m_translation.SetZero();
Synchronize(b3Vec3_zero);
SynchronizeTriangles();
}
DestroyContacts();
// Move the proxy so new contacts can be created.
m_cloth->m_contactManager.m_broadPhase.TouchProxy(m_broadPhaseId);
}

View File

@ -65,6 +65,11 @@ void b3Shape::DestroyContacts()
}
}
const b3AABB3& b3Shape::GetAABB() const
{
return m_body->GetWorld()->m_contactMan.m_broadPhase.GetAABB(m_broadPhaseID);
}
void b3Shape::Dump(u32 bodyIndex) const
{
switch (m_type)