From f7becc7ee78872c221d37e3fdffbc5f074072636 Mon Sep 17 00:00:00 2001 From: Irlan Date: Thu, 13 Jun 2019 10:13:15 -0300 Subject: [PATCH] Organize cloth contacts --- include/bounce/cloth/cloth_contact.h | 64 +++++++ include/bounce/cloth/cloth_contact_manager.h | 39 +--- include/bounce/cloth/particle.h | 9 +- src/bounce/cloth/cloth_contact.cpp | 183 +++++++++++++++++++ src/bounce/cloth/cloth_contact_manager.cpp | 183 +------------------ 5 files changed, 264 insertions(+), 214 deletions(-) create mode 100644 include/bounce/cloth/cloth_contact.h create mode 100644 src/bounce/cloth/cloth_contact.cpp diff --git a/include/bounce/cloth/cloth_contact.h b/include/bounce/cloth/cloth_contact.h new file mode 100644 index 0000000..f913ebe --- /dev/null +++ b/include/bounce/cloth/cloth_contact.h @@ -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 + +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; + 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 \ No newline at end of file diff --git a/include/bounce/cloth/cloth_contact_manager.h b/include/bounce/cloth/cloth_contact_manager.h index 3e67e2f..8f4517e 100644 --- a/include/bounce/cloth/cloth_contact_manager.h +++ b/include/bounce/cloth/cloth_contact_manager.h @@ -19,36 +19,12 @@ #ifndef B3_CLOTH_CONTACT_MANAGER_H #define B3_CLOTH_CONTACT_MANAGER_H +#include +#include #include #include -#include 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 m_particleTriangleContactList; }; diff --git a/include/bounce/cloth/particle.h b/include/bounce/cloth/particle.h index d2d13cf..bdef984 100644 --- a/include/bounce/cloth/particle.h +++ b/include/bounce/cloth/particle.h @@ -19,10 +19,10 @@ #ifndef B3_PARTICLE_H #define B3_PARTICLE_H +#include #include #include #include -#include 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; }; diff --git a/src/bounce/cloth/cloth_contact.cpp b/src/bounce/cloth/cloth_contact.cpp new file mode 100644 index 0000000..edbcb05 --- /dev/null +++ b/src/bounce/cloth/cloth_contact.cpp @@ -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 +#include +#include +#include + +// +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; + } +} \ No newline at end of file diff --git a/src/bounce/cloth/cloth_contact_manager.cpp b/src/bounce/cloth/cloth_contact_manager.cpp index 601041d..872f2c2 100644 --- a/src/bounce/cloth/cloth_contact_manager.cpp +++ b/src/bounce/cloth/cloth_contact_manager.cpp @@ -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; }