Organize cloth contacts

This commit is contained in:
Irlan 2019-06-13 10:13:15 -03:00
parent 6b92664c1e
commit f7becc7ee7
5 changed files with 264 additions and 214 deletions

View File

@ -0,0 +1,64 @@
/*
* 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_CONTACT_H
#define B3_CLOTH_CONTACT_H
#include <bounce/common/template/list.h>
class b3Particle;
struct b3ClothMeshTriangle;
struct b3ClothAABBProxy;
// Contact between particle and a triangle
class b3ParticleTriangleContact
{
public:
private:
friend class b3Cloth;
friend class b3Particle;
friend class b3ClothContactManager;
friend class b3List2<b3ParticleTriangleContact>;
friend class b3ClothContactSolver;
b3ParticleTriangleContact() { }
~b3ParticleTriangleContact() { }
void Update();
// Particle
b3Particle* m_p1;
// Triangle
b3ClothMeshTriangle* m_triangle;
b3ClothAABBProxy* m_triangleProxy;
b3Particle* m_p2;
b3Particle* m_p3;
b3Particle* m_p4;
float32 m_normalImpulse;
bool m_front;
bool m_active;
b3ParticleTriangleContact* m_prev;
b3ParticleTriangleContact* m_next;
};
#endif

View File

@ -19,36 +19,12 @@
#ifndef B3_CLOTH_CONTACT_MANAGER_H
#define B3_CLOTH_CONTACT_MANAGER_H
#include <bounce/cloth/cloth_contact.h>
#include <bounce/collision/broad_phase.h>
#include <bounce/common/memory/block_pool.h>
#include <bounce/common/template/list.h>
#include <bounce/collision/broad_phase.h>
class b3Cloth;
class b3Particle;
struct b3ClothMeshTriangle;
struct b3ClothAABBProxy;
// Contact between particle and a triangle
class b3ParticleTriangleContact
{
public:
b3Particle* m_p1;
b3ClothMeshTriangle* m_triangle;
b3ClothAABBProxy* m_triangleProxy;
b3Particle* m_p2;
b3Particle* m_p3;
b3Particle* m_p4;
bool m_front;
bool m_active;
float32 m_normalImpulse;
b3ParticleTriangleContact* m_prev;
b3ParticleTriangleContact* m_next;
};
// Contact delegator for b3Cloth.
class b3ClothContactManager
@ -62,19 +38,14 @@ public:
void FindNewContacts();
void UpdateContacts();
b3ParticleTriangleContact* Create();
b3ParticleTriangleContact* CreateParticleTriangleContact();
void Destroy(b3ParticleTriangleContact* c);
void Update(b3ParticleTriangleContact* c);
b3Cloth* m_cloth;
b3BlockPool m_particleTriangleContactBlocks;
b3Cloth* m_cloth;
b3BroadPhase m_broadPhase;
b3List2<b3ParticleTriangleContact> m_particleTriangleContactList;
};

View File

@ -19,10 +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/common/template/list.h>
#include <bounce/cloth/force.h>
class b3Shape;
class b3Cloth;
@ -91,12 +91,14 @@ struct b3ParticleBodyContactWorldPoint
float32 separation;
};
// Cloth primitive type
enum b3ClothAABBProxyType
{
e_particleProxy,
e_triangleProxy
};
// Cloth primitive broadphase proxy
struct b3ClothAABBProxy
{
b3ClothAABBProxyType type;
@ -160,6 +162,7 @@ private:
friend class b3Cloth;
friend class b3ClothSolver;
friend class b3ClothContactManager;
friend class b3ParticleTriangleContact;
friend class b3ClothContactSolver;
friend class b3Force;
friend class b3SpringForce;
@ -226,10 +229,8 @@ private:
// AABB Proxy
b3ClothAABBProxy m_aabbProxy;
//
// Links to the cloth particle list.
b3Particle* m_prev;
//
b3Particle* m_next;
};

View File

@ -0,0 +1,183 @@
/*
* 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_contact.h>
#include <bounce/cloth/cloth_mesh.h>
#include <bounce/cloth/particle.h>
#include <bounce/common/geometry.h>
//
static void b3Solve3(float32 out[3],
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C,
const b3Vec3& Q)
{
// Test vertex regions
float32 wAB[3], wBC[3], wCA[3];
b3BarycentricCoordinates(wAB, A, B, Q);
b3BarycentricCoordinates(wBC, B, C, Q);
b3BarycentricCoordinates(wCA, C, A, Q);
// R A
if (wAB[1] <= 0.0f && wCA[0] <= 0.0f)
{
out[0] = 1.0f;
out[1] = 0.0f;
out[2] = 0.0f;
return;
}
// R B
if (wAB[0] <= 0.0f && wBC[1] <= 0.0f)
{
out[0] = 0.0f;
out[1] = 1.0f;
out[2] = 0.0f;
return;
}
// R C
if (wBC[0] <= 0.0f && wCA[1] <= 0.0f)
{
out[0] = 0.0f;
out[1] = 0.0f;
out[2] = 1.0f;
return;
}
// Test edge regions
float32 wABC[4];
b3BarycentricCoordinates(wABC, A, B, C, Q);
// R AB
if (wAB[0] > 0.0f && wAB[1] > 0.0f && wABC[3] * wABC[2] <= 0.0f)
{
float32 divisor = wAB[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wAB[0];
out[1] = s * wAB[1];
out[2] = 0.0f;
return;
}
// R BC
if (wBC[0] > 0.0f && wBC[1] > 0.0f && wABC[3] * wABC[0] <= 0.0f)
{
float32 divisor = wBC[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = 0.0f;
out[1] = s * wBC[0];
out[2] = s * wBC[1];
return;
}
// R CA
if (wCA[0] > 0.0f && wCA[1] > 0.0f && wABC[3] * wABC[1] <= 0.0f)
{
float32 divisor = wCA[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wCA[1];
out[1] = 0.0f;
out[2] = s * wCA[0];
return;
}
// R ABC/ACB
float32 divisor = wABC[3];
if (divisor == 0.0f)
{
float32 s = 1.0f / 3.0f;
out[0] = s;
out[1] = s;
out[2] = s;
return;
}
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wABC[0];
out[1] = s * wABC[1];
out[2] = s * wABC[2];
}
void b3ParticleTriangleContact::Update()
{
b3Vec3 A = m_p2->m_position;
b3Vec3 B = m_p3->m_position;
b3Vec3 C = m_p4->m_position;
b3Vec3 N = b3Cross(B - A, C - A);
float32 len = N.Normalize();
// Is ABC degenerate?
if (len == 0.0f)
{
m_active = false;
return;
}
float32 r1 = m_p1->m_radius;
float32 r2 = 0.0f;
float32 totalRadius = r1 + r2;
b3Vec3 P1 = m_p1->m_position;
float32 distance = b3Dot(N, P1 - A);
// Is P1 below the plane?
if (distance < -totalRadius)
{
m_active = false;
return;
}
// Is P1 above the plane?
if (distance > totalRadius)
{
m_active = false;
return;
}
// Closest point on ABC to P1
float32 wABC[3];
b3Solve3(wABC, A, B, C, P1);
b3Vec3 P2 = wABC[0] * A + wABC[1] * B + wABC[2] * C;
if (b3DistanceSquared(P1, P2) > totalRadius * totalRadius)
{
m_active = false;
return;
}
// Activate the contact
m_active = true;
// Is P1 in front or back of the plane?
if (distance >= 0.0f)
{
m_front = true;
}
else
{
m_front = false;
}
}

View File

@ -93,26 +93,23 @@ void b3ClothContactManager::AddPair(void* data1, void* data2)
}
// Create a new contact.
b3ParticleTriangleContact* c = Create();
b3ParticleTriangleContact* c = CreateParticleTriangleContact();
c->m_p1 = p1;
c->m_triangle = triangle;
c->m_triangleProxy = proxy2;
c->m_p2 = p2;
c->m_p3 = p3;
c->m_p4 = p4;
c->m_triangle = triangle;
c->m_triangleProxy = proxy2;
c->m_normalImpulse = 0.0f;
c->m_front = false;
c->m_active = false;
c->m_normalImpulse = 0.0f;
// Add the contact to the cloth contact list.
m_particleTriangleContactList.PushFront(c);
}
b3ParticleTriangleContact* b3ClothContactManager::Create()
b3ParticleTriangleContact* b3ClothContactManager::CreateParticleTriangleContact()
{
void* block = m_particleTriangleContactBlocks.Allocate();
return new(block) b3ParticleTriangleContact();
@ -127,177 +124,11 @@ void b3ClothContactManager::Destroy(b3ParticleTriangleContact* c)
m_particleTriangleContactBlocks.Free(c);
}
static void b3Solve3(float32 out[3],
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C,
const b3Vec3& Q)
{
// Test vertex regions
float32 wAB[3], wBC[3], wCA[3];
b3BarycentricCoordinates(wAB, A, B, Q);
b3BarycentricCoordinates(wBC, B, C, Q);
b3BarycentricCoordinates(wCA, C, A, Q);
// R A
if (wAB[1] <= 0.0f && wCA[0] <= 0.0f)
{
out[0] = 1.0f;
out[1] = 0.0f;
out[2] = 0.0f;
return;
}
// R B
if (wAB[0] <= 0.0f && wBC[1] <= 0.0f)
{
out[0] = 0.0f;
out[1] = 1.0f;
out[2] = 0.0f;
return;
}
// R C
if (wBC[0] <= 0.0f && wCA[1] <= 0.0f)
{
out[0] = 0.0f;
out[1] = 0.0f;
out[2] = 1.0f;
return;
}
// Test edge regions
float32 wABC[4];
b3BarycentricCoordinates(wABC, A, B, C, Q);
// R AB
if (wAB[0] > 0.0f && wAB[1] > 0.0f && wABC[3] * wABC[2] <= 0.0f)
{
float32 divisor = wAB[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wAB[0];
out[1] = s * wAB[1];
out[2] = 0.0f;
return;
}
// R BC
if (wBC[0] > 0.0f && wBC[1] > 0.0f && wABC[3] * wABC[0] <= 0.0f)
{
float32 divisor = wBC[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = 0.0f;
out[1] = s * wBC[0];
out[2] = s * wBC[1];
return;
}
// R CA
if (wCA[0] > 0.0f && wCA[1] > 0.0f && wABC[3] * wABC[1] <= 0.0f)
{
float32 divisor = wCA[2];
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wCA[1];
out[1] = 0.0f;
out[2] = s * wCA[0];
return;
}
// R ABC/ACB
float32 divisor = wABC[3];
if (divisor == 0.0f)
{
float32 s = 1.0f / 3.0f;
out[0] = s;
out[1] = s;
out[2] = s;
return;
}
B3_ASSERT(divisor > 0.0f);
float32 s = 1.0f / divisor;
out[0] = s * wABC[0];
out[1] = s * wABC[1];
out[2] = s * wABC[2];
}
void b3ClothContactManager::Update(b3ParticleTriangleContact* c)
{
b3Particle* p1 = c->m_p1;
b3Particle* p2 = c->m_p2;
b3Particle* p3 = c->m_p3;
b3Particle* p4 = c->m_p4;
float32 r1 = p1->m_radius;
float32 r2 = 0.0f;
float32 totalRadius = r1 + r2;
b3Vec3 A = p2->m_position;
b3Vec3 B = p3->m_position;
b3Vec3 C = p4->m_position;
b3Vec3 n = b3Cross(B - A, C - A);
float32 len = n.Normalize();
// Is ABC degenerate?
if (len == 0.0f)
{
c->m_active = false;
return;
}
b3Vec3 P1 = p1->m_position;
float32 distance = b3Dot(n, P1 - A);
// Is P1 below the plane?
if (distance < -totalRadius)
{
c->m_active = false;
return;
}
// Is P1 above the plane?
if (distance > totalRadius)
{
c->m_active = false;
return;
}
// Closest point on ABC to P1
float32 wABC[3];
b3Solve3(wABC, A, B, C, P1);
b3Vec3 P2 = wABC[0] * A + wABC[1] * B + wABC[2] * C;
if (b3DistanceSquared(P1, P2) > totalRadius * totalRadius)
{
c->m_active = false;
return;
}
// Activate the contact
c->m_active = true;
// Is the the other point in front of the plane?
if (distance >= 0.0f)
{
c->m_front = true;
}
else
{
c->m_front = false;
}
}
void b3ClothContactManager::UpdateContacts()
{
B3_PROFILE("Cloth Update Contacts");
// Update the state of all triangle contacts.
// Update the state of particle-triangle contacts.
b3ParticleTriangleContact* c = m_particleTriangleContactList.m_head;
while (c)
{
@ -327,7 +158,7 @@ void b3ClothContactManager::UpdateContacts()
}
// The contact persists.
Update(c);
c->Update();
c = c->m_next;
}