bugfix, particle friction, test code
This commit is contained in:
parent
863bf7f052
commit
86cfec55f0
@ -30,9 +30,10 @@ public:
|
|||||||
// Create 3D mesh
|
// Create 3D mesh
|
||||||
m_rectangleClothMesh.Set(&m_rectangleGarmentMesh);
|
m_rectangleClothMesh.Set(&m_rectangleGarmentMesh);
|
||||||
|
|
||||||
//
|
b3Mat33 Rx = b3Mat33RotationX(0.5f * B3_PI);
|
||||||
for (u32 i = 0; i < m_rectangleClothMesh.vertexCount; ++i)
|
for (u32 i = 0; i < m_rectangleClothMesh.vertexCount; ++i)
|
||||||
{
|
{
|
||||||
|
m_rectangleClothMesh.vertices[i] = Rx * m_rectangleClothMesh.vertices[i];
|
||||||
m_rectangleClothMesh.vertices[i].y += 10.0f;
|
m_rectangleClothMesh.vertices[i].y += 10.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,8 @@ public:
|
|||||||
|
|
||||||
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
|
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
|
||||||
{
|
{
|
||||||
p->SetRadius(0.25f);
|
p->SetRadius(0.2f);
|
||||||
|
p->SetFriction(0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -54,14 +56,13 @@ public:
|
|||||||
|
|
||||||
b3Body* b = m_world.CreateBody(bd);
|
b3Body* b = m_world.CreateBody(bd);
|
||||||
|
|
||||||
m_boxHull.Set(50.0f, 1.0f, 50.0f);
|
b3CapsuleShape capsuleShape;
|
||||||
|
capsuleShape.m_centers[0].Set(0.0f, 5.0f, -5.0f);
|
||||||
b3HullShape boxShape;
|
capsuleShape.m_centers[1].Set(0.0f, 5.0f, 5.0f);
|
||||||
boxShape.m_hull = &m_boxHull;
|
capsuleShape.m_radius = 1.0f;;
|
||||||
boxShape.m_radius = 0.2f;
|
|
||||||
|
|
||||||
b3ShapeDef sd;
|
b3ShapeDef sd;
|
||||||
sd.shape = &boxShape;
|
sd.shape = &capsuleShape;
|
||||||
sd.friction = 1.0f;
|
sd.friction = 1.0f;
|
||||||
|
|
||||||
b->CreateShape(sd);
|
b->CreateShape(sd);
|
||||||
|
@ -30,6 +30,7 @@ class b3Particle;
|
|||||||
class b3Force;
|
class b3Force;
|
||||||
class b3BodyContact;
|
class b3BodyContact;
|
||||||
class b3ParticleContact;
|
class b3ParticleContact;
|
||||||
|
class b3TriangleContact;
|
||||||
|
|
||||||
struct b3ParticleDef;
|
struct b3ParticleDef;
|
||||||
struct b3ForceDef;
|
struct b3ForceDef;
|
||||||
@ -151,6 +152,9 @@ private:
|
|||||||
// Update particle contacts.
|
// Update particle contacts.
|
||||||
void UpdateParticleContacts();
|
void UpdateParticleContacts();
|
||||||
|
|
||||||
|
// Update triangle contacts.
|
||||||
|
void UpdateTriangleContacts();
|
||||||
|
|
||||||
// Solve
|
// Solve
|
||||||
void Solve(float32 dt, const b3Vec3& gravity);
|
void Solve(float32 dt, const b3Vec3& gravity);
|
||||||
|
|
||||||
@ -169,6 +173,9 @@ private:
|
|||||||
// Pool of particle contacts
|
// Pool of particle contacts
|
||||||
b3BlockPool m_particleContactBlocks;
|
b3BlockPool m_particleContactBlocks;
|
||||||
|
|
||||||
|
// Pool of triangle contacts
|
||||||
|
b3BlockPool m_triangleContactBlocks;
|
||||||
|
|
||||||
// List of particles
|
// List of particles
|
||||||
b3List2<b3Particle> m_particleList;
|
b3List2<b3Particle> m_particleList;
|
||||||
|
|
||||||
@ -178,6 +185,9 @@ private:
|
|||||||
// List of particle contacts
|
// List of particle contacts
|
||||||
b3List2<b3ParticleContact> m_particleContactList;
|
b3List2<b3ParticleContact> m_particleContactList;
|
||||||
|
|
||||||
|
// List of triangle contacts
|
||||||
|
b3List2<b3TriangleContact> m_triangleContactList;
|
||||||
|
|
||||||
// The parent world of this cloth.
|
// The parent world of this cloth.
|
||||||
b3World* m_world;
|
b3World* m_world;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ class b3Body;
|
|||||||
class b3Force;
|
class b3Force;
|
||||||
class b3BodyContact;
|
class b3BodyContact;
|
||||||
class b3ParticleContact;
|
class b3ParticleContact;
|
||||||
|
class b3TriangleContact;
|
||||||
|
|
||||||
struct b3DenseVec3;
|
struct b3DenseVec3;
|
||||||
struct b3DiagMat33;
|
struct b3DiagMat33;
|
||||||
@ -41,6 +42,7 @@ struct b3ClothSolverDef
|
|||||||
u32 forceCapacity;
|
u32 forceCapacity;
|
||||||
u32 bodyContactCapacity;
|
u32 bodyContactCapacity;
|
||||||
u32 particleContactCapacity;
|
u32 particleContactCapacity;
|
||||||
|
u32 triangleContactCapacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct b3ClothSolverData
|
struct b3ClothSolverData
|
||||||
@ -149,6 +151,44 @@ struct b3ClothSolverParticleContactPositionConstraint
|
|||||||
float32 radiusB;
|
float32 radiusB;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct b3ClothSolverTriangleContactVelocityConstraint
|
||||||
|
{
|
||||||
|
u32 indexA;
|
||||||
|
float32 invMassA;
|
||||||
|
|
||||||
|
u32 indexB;
|
||||||
|
float32 invMassB;
|
||||||
|
u32 indexC;
|
||||||
|
float32 invMassC;
|
||||||
|
u32 indexD;
|
||||||
|
float32 invMassD;
|
||||||
|
|
||||||
|
b3Vec3 JA;
|
||||||
|
b3Vec3 JB;
|
||||||
|
b3Vec3 JC;
|
||||||
|
b3Vec3 JD;
|
||||||
|
|
||||||
|
float32 normalMass;
|
||||||
|
float32 normalImpulse;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct b3ClothSolverTriangleContactPositionConstraint
|
||||||
|
{
|
||||||
|
u32 indexA;
|
||||||
|
float32 invMassA;
|
||||||
|
float32 radiusA;
|
||||||
|
|
||||||
|
u32 indexB;
|
||||||
|
float32 invMassB;
|
||||||
|
u32 indexC;
|
||||||
|
float32 invMassC;
|
||||||
|
u32 indexD;
|
||||||
|
float32 invMassD;
|
||||||
|
float32 triangleRadius;
|
||||||
|
|
||||||
|
bool front;
|
||||||
|
};
|
||||||
|
|
||||||
class b3ClothSolver
|
class b3ClothSolver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -159,6 +199,7 @@ public:
|
|||||||
void Add(b3Force* f);
|
void Add(b3Force* f);
|
||||||
void Add(b3BodyContact* c);
|
void Add(b3BodyContact* c);
|
||||||
void Add(b3ParticleContact* c);
|
void Add(b3ParticleContact* c);
|
||||||
|
void Add(b3TriangleContact* c);
|
||||||
|
|
||||||
void Solve(float32 dt, const b3Vec3& gravity);
|
void Solve(float32 dt, const b3Vec3& gravity);
|
||||||
private:
|
private:
|
||||||
@ -177,6 +218,9 @@ private:
|
|||||||
//
|
//
|
||||||
void InitializeParticleContactConstraints();
|
void InitializeParticleContactConstraints();
|
||||||
|
|
||||||
|
//
|
||||||
|
void InitializeTriangleContactConstraints();
|
||||||
|
|
||||||
//
|
//
|
||||||
void WarmStart();
|
void WarmStart();
|
||||||
|
|
||||||
@ -186,6 +230,9 @@ private:
|
|||||||
//
|
//
|
||||||
void SolveParticleContactVelocityConstraints();
|
void SolveParticleContactVelocityConstraints();
|
||||||
|
|
||||||
|
//
|
||||||
|
void SolveTriangleContactVelocityConstraints();
|
||||||
|
|
||||||
//
|
//
|
||||||
void StoreImpulses();
|
void StoreImpulses();
|
||||||
|
|
||||||
@ -195,6 +242,9 @@ private:
|
|||||||
//
|
//
|
||||||
bool SolveParticleContactPositionConstraints();
|
bool SolveParticleContactPositionConstraints();
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SolveTriangleContactPositionConstraints();
|
||||||
|
|
||||||
b3StackAllocator* m_allocator;
|
b3StackAllocator* m_allocator;
|
||||||
|
|
||||||
u32 m_particleCapacity;
|
u32 m_particleCapacity;
|
||||||
@ -221,6 +271,12 @@ private:
|
|||||||
b3ClothSolverParticleContactVelocityConstraint* m_particleVelocityConstraints;
|
b3ClothSolverParticleContactVelocityConstraint* m_particleVelocityConstraints;
|
||||||
b3ClothSolverParticleContactPositionConstraint* m_particlePositionConstraints;
|
b3ClothSolverParticleContactPositionConstraint* m_particlePositionConstraints;
|
||||||
|
|
||||||
|
u32 m_triangleContactCapacity;
|
||||||
|
u32 m_triangleContactCount;
|
||||||
|
b3TriangleContact** m_triangleContacts;
|
||||||
|
b3ClothSolverTriangleContactVelocityConstraint* m_triangleVelocityConstraints;
|
||||||
|
b3ClothSolverTriangleContactPositionConstraint* m_trianglePositionConstraints;
|
||||||
|
|
||||||
b3ClothSolverData m_solverData;
|
b3ClothSolverData m_solverData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ struct b3ParticleDef
|
|||||||
velocity.SetZero();
|
velocity.SetZero();
|
||||||
force.SetZero();
|
force.SetZero();
|
||||||
radius = 0.0f;
|
radius = 0.0f;
|
||||||
|
friction = 0.0f;
|
||||||
userData = nullptr;
|
userData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,21 +57,10 @@ struct b3ParticleDef
|
|||||||
b3Vec3 velocity;
|
b3Vec3 velocity;
|
||||||
b3Vec3 force;
|
b3Vec3 force;
|
||||||
float32 radius;
|
float32 radius;
|
||||||
|
float32 friction;
|
||||||
void* userData;
|
void* userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
class b3FrictionForce : public b3Force
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
b3FrictionForce() { }
|
|
||||||
~b3FrictionForce() { }
|
|
||||||
|
|
||||||
void Apply(const b3ClothSolverData* data);
|
|
||||||
|
|
||||||
b3Particle* m_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A contact between a particle and a solid
|
// A contact between a particle and a solid
|
||||||
class b3BodyContact
|
class b3BodyContact
|
||||||
{
|
{
|
||||||
@ -134,6 +124,27 @@ struct b3ParticleContactWorldPoint
|
|||||||
float32 separation;
|
float32 separation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A contact between a particle and a triangle
|
||||||
|
class b3TriangleContact
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
b3TriangleContact() { }
|
||||||
|
~b3TriangleContact() { }
|
||||||
|
|
||||||
|
b3Particle* p1;
|
||||||
|
b3Particle* p2;
|
||||||
|
b3Particle* p3;
|
||||||
|
b3Particle* p4;
|
||||||
|
|
||||||
|
bool front;
|
||||||
|
|
||||||
|
// Contact constraint
|
||||||
|
float32 normalImpulse;
|
||||||
|
|
||||||
|
b3TriangleContact* m_prev;
|
||||||
|
b3TriangleContact* m_next;
|
||||||
|
};
|
||||||
|
|
||||||
// A cloth particle.
|
// A cloth particle.
|
||||||
class b3Particle
|
class b3Particle
|
||||||
{
|
{
|
||||||
@ -170,6 +181,12 @@ public:
|
|||||||
// Get the particle radius.
|
// Get the particle radius.
|
||||||
float32 GetRadius() const;
|
float32 GetRadius() const;
|
||||||
|
|
||||||
|
// Set the particle coefficient of friction.
|
||||||
|
void SetFriction(float32 friction);
|
||||||
|
|
||||||
|
// Get the particle coefficient of friction.
|
||||||
|
float32 GetFriction() const;
|
||||||
|
|
||||||
// Apply a force.
|
// Apply a force.
|
||||||
void ApplyForce(const b3Vec3& force);
|
void ApplyForce(const b3Vec3& force);
|
||||||
|
|
||||||
@ -214,6 +231,9 @@ private:
|
|||||||
// Radius
|
// Radius
|
||||||
float32 m_radius;
|
float32 m_radius;
|
||||||
|
|
||||||
|
// Coefficient of friction
|
||||||
|
float32 m_friction;
|
||||||
|
|
||||||
// User data.
|
// User data.
|
||||||
void* m_userData;
|
void* m_userData;
|
||||||
|
|
||||||
@ -291,6 +311,16 @@ inline float32 b3Particle::GetRadius() const
|
|||||||
return m_radius;
|
return m_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void b3Particle::SetFriction(float32 friction)
|
||||||
|
{
|
||||||
|
m_friction = friction;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 b3Particle::GetFriction() const
|
||||||
|
{
|
||||||
|
return m_friction;
|
||||||
|
}
|
||||||
|
|
||||||
inline void b3Particle::ApplyForce(const b3Vec3& force)
|
inline void b3Particle::ApplyForce(const b3Vec3& force)
|
||||||
{
|
{
|
||||||
if (m_type != e_dynamicParticle)
|
if (m_type != e_dynamicParticle)
|
||||||
|
@ -149,9 +149,10 @@ static u32 b3FindSharedEdges(b3SharedEdge* sharedEdges, const b3ClothMesh* m)
|
|||||||
return sharedCount;
|
return sharedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
b3Cloth::b3Cloth(const b3ClothDef& def, b3World* world) :
|
b3Cloth::b3Cloth(const b3ClothDef& def, b3World* world) :
|
||||||
m_particleBlocks(sizeof(b3Particle)),
|
m_particleBlocks(sizeof(b3Particle)),
|
||||||
m_particleContactBlocks(sizeof(b3ParticleContact))
|
m_particleContactBlocks(sizeof(b3ParticleContact)),
|
||||||
|
m_triangleContactBlocks(sizeof(b3TriangleContact))
|
||||||
{
|
{
|
||||||
B3_ASSERT(def.mesh);
|
B3_ASSERT(def.mesh);
|
||||||
B3_ASSERT(def.density > 0.0f);
|
B3_ASSERT(def.density > 0.0f);
|
||||||
@ -481,8 +482,7 @@ bool b3Cloth::RayCast(b3RayCastOutput* output, const b3RayCastInput* input, u32
|
|||||||
float32 v = b3Dot(QC_x_QA, AB_x_AC);
|
float32 v = b3Dot(QC_x_QA, AB_x_AC);
|
||||||
float32 w = b3Dot(QA_x_QB, AB_x_AC);
|
float32 w = b3Dot(QA_x_QB, AB_x_AC);
|
||||||
|
|
||||||
// This tolerance helps intersections lying on
|
// Characteristic length of triangle
|
||||||
// shared edges to not be missed.
|
|
||||||
const float32 kTol = -B3_EPSILON;
|
const float32 kTol = -B3_EPSILON;
|
||||||
|
|
||||||
// Is the intersection on the triangle?
|
// Is the intersection on the triangle?
|
||||||
@ -588,7 +588,7 @@ void b3Cloth::UpdateBodyContacts()
|
|||||||
void b3Cloth::UpdateParticleContacts()
|
void b3Cloth::UpdateParticleContacts()
|
||||||
{
|
{
|
||||||
B3_PROFILE("Update Particle Contacts");
|
B3_PROFILE("Update Particle Contacts");
|
||||||
|
|
||||||
// Clear buffer
|
// Clear buffer
|
||||||
b3ParticleContact* c = m_particleContactList.m_head;
|
b3ParticleContact* c = m_particleContactList.m_head;
|
||||||
while (c)
|
while (c)
|
||||||
@ -624,7 +624,7 @@ void b3Cloth::UpdateParticleContacts()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
b3Vec3 n(0.0f, 1.0f, 0.0f);
|
b3Vec3 n(0.0f, 1.0f, 0.0f);
|
||||||
if (dd > B3_EPSILON * B3_EPSILON)
|
if (dd > B3_EPSILON * B3_EPSILON)
|
||||||
{
|
{
|
||||||
@ -637,7 +637,7 @@ void b3Cloth::UpdateParticleContacts()
|
|||||||
c->p2 = p2;
|
c->p2 = p2;
|
||||||
c->normalImpulse = 0.0f;
|
c->normalImpulse = 0.0f;
|
||||||
c->t1 = b3Perp(n);
|
c->t1 = b3Perp(n);
|
||||||
c->t2 = b3Cross(c->t1, n);
|
c->t2 = b3Cross(c->t1, n);
|
||||||
c->tangentImpulse.SetZero();
|
c->tangentImpulse.SetZero();
|
||||||
|
|
||||||
m_particleContactList.PushFront(c);
|
m_particleContactList.PushFront(c);
|
||||||
@ -645,6 +645,241 @@ void b3Cloth::UpdateParticleContacts()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static B3_FORCE_INLINE void b3Barycentric(float32 out[3],
|
||||||
|
const b3Vec3& A, const b3Vec3& B,
|
||||||
|
const b3Vec3& Q)
|
||||||
|
{
|
||||||
|
b3Vec3 AB = B - A;
|
||||||
|
b3Vec3 QA = A - Q;
|
||||||
|
b3Vec3 QB = B - Q;
|
||||||
|
|
||||||
|
//float32 divisor = b3Dot(AB, AB);
|
||||||
|
|
||||||
|
out[0] = b3Dot(QB, AB);
|
||||||
|
out[1] = -b3Dot(QA, AB);
|
||||||
|
out[2] = out[0] + out[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a point Q from Cartesian coordinates to Barycentric coordinates (u, v, w)
|
||||||
|
// with respect to a triangle ABC.
|
||||||
|
// The last output value is the divisor.
|
||||||
|
static B3_FORCE_INLINE void b3Barycentric(float32 out[4],
|
||||||
|
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C,
|
||||||
|
const b3Vec3& Q)
|
||||||
|
{
|
||||||
|
b3Vec3 AB = B - A;
|
||||||
|
b3Vec3 AC = C - A;
|
||||||
|
|
||||||
|
b3Vec3 QA = A - Q;
|
||||||
|
b3Vec3 QB = B - Q;
|
||||||
|
b3Vec3 QC = C - Q;
|
||||||
|
|
||||||
|
b3Vec3 QB_x_QC = b3Cross(QB, QC);
|
||||||
|
b3Vec3 QC_x_QA = b3Cross(QC, QA);
|
||||||
|
b3Vec3 QA_x_QB = b3Cross(QA, QB);
|
||||||
|
|
||||||
|
b3Vec3 AB_x_AC = b3Cross(AB, AC);
|
||||||
|
|
||||||
|
//float32 divisor = b3Dot(AB_x_AC, AB_x_AC);
|
||||||
|
|
||||||
|
out[0] = b3Dot(QB_x_QC, AB_x_AC);
|
||||||
|
out[1] = b3Dot(QC_x_QA, AB_x_AC);
|
||||||
|
out[2] = b3Dot(QA_x_QB, AB_x_AC);
|
||||||
|
out[3] = out[0] + out[1] + out[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static B3_FORCE_INLINE 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];
|
||||||
|
b3Barycentric(wAB, A, B, Q);
|
||||||
|
b3Barycentric(wBC, B, C, Q);
|
||||||
|
b3Barycentric(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];
|
||||||
|
b3Barycentric(wABC, A, B, C, Q);
|
||||||
|
|
||||||
|
// This is used to help testing if the face degenerates
|
||||||
|
// into an edge.
|
||||||
|
float32 area = wABC[3];
|
||||||
|
|
||||||
|
// R AB
|
||||||
|
if (wAB[0] > 0.0f && wAB[1] > 0.0f && area * 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 && area * 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 && area * wABC[1] <= 0.0f)
|
||||||
|
{
|
||||||
|
float32 divisor = wCA[2];
|
||||||
|
B3_ASSERT(divisor > 0.0f);
|
||||||
|
float32 s = 1.0f / divisor;
|
||||||
|
out[0] = 0.0f;
|
||||||
|
out[2] = s * wCA[0];
|
||||||
|
out[1] = s * wCA[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// R ABC/ACB
|
||||||
|
float32 divisor = wABC[3];
|
||||||
|
if (divisor <= 0.0f)
|
||||||
|
{
|
||||||
|
float32 s = 1.0f / 3.0f;
|
||||||
|
out[0] = s;
|
||||||
|
out[2] = s;
|
||||||
|
out[1] = 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 b3Cloth::UpdateTriangleContacts()
|
||||||
|
{
|
||||||
|
B3_PROFILE("Update Triangle Contacts");
|
||||||
|
|
||||||
|
// Clear buffer
|
||||||
|
b3TriangleContact* c = m_triangleContactList.m_head;
|
||||||
|
while (c)
|
||||||
|
{
|
||||||
|
b3TriangleContact* c0 = c;
|
||||||
|
c = c->m_next;
|
||||||
|
m_triangleContactList.Remove(c0);
|
||||||
|
c0->~b3TriangleContact();
|
||||||
|
m_triangleContactBlocks.Free(c0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create triangle contacts
|
||||||
|
for (b3Particle* p1 = m_particleList.m_head; p1; p1 = p1->m_next)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < m_mesh->triangleCount; ++i)
|
||||||
|
{
|
||||||
|
b3ClothMeshTriangle* triangle = m_mesh->triangles + i;
|
||||||
|
|
||||||
|
b3Particle* p2 = m_vertexParticles[triangle->v1];
|
||||||
|
b3Particle* p3 = m_vertexParticles[triangle->v2];
|
||||||
|
b3Particle* p4 = m_vertexParticles[triangle->v3];
|
||||||
|
|
||||||
|
if (p1 == p2 || p1 == p3 || p1 == p4)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 P = p1->m_position;
|
||||||
|
|
||||||
|
b3Vec3 n = b3Cross(B - A, C - A);
|
||||||
|
float32 n_len = n.Normalize();
|
||||||
|
|
||||||
|
float32 distance = b3Dot(n, P - A);
|
||||||
|
|
||||||
|
if (distance < -totalRadius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distance > totalRadius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project particle on triangle plane
|
||||||
|
b3Vec3 Q = P - distance * n;
|
||||||
|
|
||||||
|
// Barycentric coordinates for Q
|
||||||
|
float32 wABC[3];
|
||||||
|
b3Solve3(wABC, A, B, C, Q);
|
||||||
|
|
||||||
|
b3Vec3 c1 = p1->m_position;
|
||||||
|
b3Vec3 c2 = wABC[0] * A + wABC[1] * B + wABC[2] * C;
|
||||||
|
|
||||||
|
if (b3DistanceSquared(c1, c2) > totalRadius * totalRadius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool front = false;
|
||||||
|
|
||||||
|
// Is the the other point in front of the triangle plane?
|
||||||
|
if (distance >= 0.0f)
|
||||||
|
{
|
||||||
|
front = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3TriangleContact* c = (b3TriangleContact*)m_triangleContactBlocks.Allocate();
|
||||||
|
c->p1 = p1;
|
||||||
|
c->p2 = p2;
|
||||||
|
c->p3 = p3;
|
||||||
|
c->p4 = p4;
|
||||||
|
c->front = front;
|
||||||
|
c->normalImpulse = 0.0f;
|
||||||
|
|
||||||
|
m_triangleContactList.PushFront(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void b3Cloth::Solve(float32 dt, const b3Vec3& gravity)
|
void b3Cloth::Solve(float32 dt, const b3Vec3& gravity)
|
||||||
{
|
{
|
||||||
B3_PROFILE("Solve");
|
B3_PROFILE("Solve");
|
||||||
@ -684,6 +919,11 @@ void b3Cloth::Solve(float32 dt, const b3Vec3& gravity)
|
|||||||
solver.Add(pc);
|
solver.Add(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (b3TriangleContact* tc = m_triangleContactList.m_head; tc; tc = tc->m_next)
|
||||||
|
{
|
||||||
|
solver.Add(tc);
|
||||||
|
}
|
||||||
|
|
||||||
// Solve
|
// Solve
|
||||||
solver.Solve(dt, gravity);
|
solver.Solve(dt, gravity);
|
||||||
|
|
||||||
@ -704,6 +944,9 @@ void b3Cloth::Step(float32 dt, const b3Vec3& gravity)
|
|||||||
|
|
||||||
// Update particle contacts
|
// Update particle contacts
|
||||||
UpdateParticleContacts();
|
UpdateParticleContacts();
|
||||||
|
|
||||||
|
// Update triangle contacts
|
||||||
|
UpdateTriangleContacts();
|
||||||
|
|
||||||
// Solve constraints, integrate state, clear forces and translations.
|
// Solve constraints, integrate state, clear forces and translations.
|
||||||
if (dt > 0.0f)
|
if (dt > 0.0f)
|
||||||
|
@ -63,10 +63,20 @@ b3ClothSolver::b3ClothSolver(const b3ClothSolverDef& def)
|
|||||||
m_particleContacts = (b3ParticleContact**)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ParticleContact*));
|
m_particleContacts = (b3ParticleContact**)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ParticleContact*));
|
||||||
m_particleVelocityConstraints = (b3ClothSolverParticleContactVelocityConstraint*)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ClothSolverParticleContactVelocityConstraint));
|
m_particleVelocityConstraints = (b3ClothSolverParticleContactVelocityConstraint*)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ClothSolverParticleContactVelocityConstraint));
|
||||||
m_particlePositionConstraints = (b3ClothSolverParticleContactPositionConstraint*)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ClothSolverParticleContactPositionConstraint));
|
m_particlePositionConstraints = (b3ClothSolverParticleContactPositionConstraint*)m_allocator->Allocate(m_particleContactCapacity * sizeof(b3ClothSolverParticleContactPositionConstraint));
|
||||||
|
|
||||||
|
m_triangleContactCapacity = def.triangleContactCapacity;
|
||||||
|
m_triangleContactCount = 0;
|
||||||
|
m_triangleContacts = (b3TriangleContact**)m_allocator->Allocate(m_triangleContactCapacity * sizeof(b3TriangleContact*));
|
||||||
|
m_triangleVelocityConstraints = (b3ClothSolverTriangleContactVelocityConstraint*)m_allocator->Allocate(m_triangleContactCapacity * sizeof(b3ClothSolverTriangleContactVelocityConstraint));
|
||||||
|
m_trianglePositionConstraints = (b3ClothSolverTriangleContactPositionConstraint*)m_allocator->Allocate(m_triangleContactCapacity * sizeof(b3ClothSolverTriangleContactPositionConstraint));
|
||||||
}
|
}
|
||||||
|
|
||||||
b3ClothSolver::~b3ClothSolver()
|
b3ClothSolver::~b3ClothSolver()
|
||||||
{
|
{
|
||||||
|
m_allocator->Free(m_trianglePositionConstraints);
|
||||||
|
m_allocator->Free(m_triangleVelocityConstraints);
|
||||||
|
m_allocator->Free(m_triangleContacts);
|
||||||
|
|
||||||
m_allocator->Free(m_particlePositionConstraints);
|
m_allocator->Free(m_particlePositionConstraints);
|
||||||
m_allocator->Free(m_particleVelocityConstraints);
|
m_allocator->Free(m_particleVelocityConstraints);
|
||||||
m_allocator->Free(m_particleContacts);
|
m_allocator->Free(m_particleContacts);
|
||||||
@ -101,6 +111,11 @@ void b3ClothSolver::Add(b3ParticleContact* c)
|
|||||||
m_particleContacts[m_particleContactCount++] = c;
|
m_particleContacts[m_particleContactCount++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void b3ClothSolver::Add(b3TriangleContact* c)
|
||||||
|
{
|
||||||
|
m_triangleContacts[m_triangleContactCount++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
void b3ClothSolver::ApplyForces()
|
void b3ClothSolver::ApplyForces()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_forceCount; ++i)
|
for (u32 i = 0; i < m_forceCount; ++i)
|
||||||
@ -263,6 +278,9 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity)
|
|||||||
// Initialize particle contact constraints
|
// Initialize particle contact constraints
|
||||||
InitializeParticleContactConstraints();
|
InitializeParticleContactConstraints();
|
||||||
|
|
||||||
|
// Initialize triangle contact constraints
|
||||||
|
// InitializeTriangleContactConstraints();
|
||||||
|
|
||||||
// Warm start velocity constraints
|
// Warm start velocity constraints
|
||||||
WarmStart();
|
WarmStart();
|
||||||
|
|
||||||
@ -273,6 +291,7 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity)
|
|||||||
{
|
{
|
||||||
SolveBodyContactVelocityConstraints();
|
SolveBodyContactVelocityConstraints();
|
||||||
SolveParticleContactVelocityConstraints();
|
SolveParticleContactVelocityConstraints();
|
||||||
|
// SolveTriangleContactVelocityConstraints();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store impulses to improve convergence
|
// Store impulses to improve convergence
|
||||||
@ -283,11 +302,13 @@ void b3ClothSolver::Solve(float32 dt, const b3Vec3& gravity)
|
|||||||
|
|
||||||
// Solve position constraints
|
// Solve position constraints
|
||||||
const u32 kPositionIterations = 2;
|
const u32 kPositionIterations = 2;
|
||||||
|
|
||||||
bool positionSolved = false;
|
bool positionSolved = false;
|
||||||
for (u32 i = 0; i < kPositionIterations; ++i)
|
for (u32 i = 0; i < kPositionIterations; ++i)
|
||||||
{
|
{
|
||||||
bool particleContactsSolved = SolveParticleContactPositionConstraints();
|
bool particleContactsSolved = SolveParticleContactPositionConstraints();
|
||||||
|
// bool triangleContactsSolved = SolveTriangleContactPositionConstraints();
|
||||||
|
//if (particleContactsSolved && triangleContactsSolved)
|
||||||
if (particleContactsSolved)
|
if (particleContactsSolved)
|
||||||
{
|
{
|
||||||
positionSolved = true;
|
positionSolved = true;
|
||||||
@ -559,6 +580,12 @@ void b3ClothSolver::InitializeBodyContactConstraints()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
static B3_FORCE_INLINE float32 b3MixFriction(float32 u1, float32 u2)
|
||||||
|
{
|
||||||
|
return b3Sqrt(u1 * u2);
|
||||||
|
}
|
||||||
|
|
||||||
void b3ClothSolver::InitializeParticleContactConstraints()
|
void b3ClothSolver::InitializeParticleContactConstraints()
|
||||||
{
|
{
|
||||||
b3DenseVec3& x = *m_solverData.x;
|
b3DenseVec3& x = *m_solverData.x;
|
||||||
@ -578,7 +605,7 @@ void b3ClothSolver::InitializeParticleContactConstraints()
|
|||||||
vc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
|
vc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
|
||||||
vc->invMassB = c->p2->m_type == e_staticParticle ? 0.0f : c->p2->m_invMass;
|
vc->invMassB = c->p2->m_type == e_staticParticle ? 0.0f : c->p2->m_invMass;
|
||||||
|
|
||||||
vc->friction = 1.0f;
|
vc->friction = b3MixFriction(c->p1->m_friction, c->p2->m_friction);
|
||||||
|
|
||||||
pc->indexA = c->p1->m_solverId;
|
pc->indexA = c->p1->m_solverId;
|
||||||
pc->indexB = c->p2->m_solverId;
|
pc->indexB = c->p2->m_solverId;
|
||||||
@ -624,7 +651,7 @@ void b3ClothSolver::InitializeParticleContactConstraints()
|
|||||||
float32 K = mA + mB;
|
float32 K = mA + mB;
|
||||||
|
|
||||||
vc->normalMass = K > 0.0f ? 1.0f / K : 0.0f;
|
vc->normalMass = K > 0.0f ? 1.0f / K : 0.0f;
|
||||||
|
|
||||||
vc->velocityBias = 0.0f;
|
vc->velocityBias = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,6 +672,93 @@ void b3ClothSolver::InitializeParticleContactConstraints()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void b3ClothSolver::InitializeTriangleContactConstraints()
|
||||||
|
{
|
||||||
|
b3DenseVec3& x = *m_solverData.x;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_triangleContactCount; ++i)
|
||||||
|
{
|
||||||
|
b3TriangleContact* c = m_triangleContacts[i];
|
||||||
|
b3ClothSolverTriangleContactVelocityConstraint* vc = m_triangleVelocityConstraints + i;
|
||||||
|
b3ClothSolverTriangleContactPositionConstraint* pc = m_trianglePositionConstraints + i;
|
||||||
|
|
||||||
|
vc->indexA = c->p1->m_solverId;
|
||||||
|
vc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
|
||||||
|
|
||||||
|
vc->indexB = c->p2->m_solverId;
|
||||||
|
vc->invMassB = c->p2->m_type == e_staticParticle ? 0.0f : c->p2->m_invMass;
|
||||||
|
|
||||||
|
vc->indexC = c->p3->m_solverId;
|
||||||
|
vc->invMassC = c->p3->m_type == e_staticParticle ? 0.0f : c->p3->m_invMass;
|
||||||
|
|
||||||
|
vc->indexD = c->p4->m_solverId;
|
||||||
|
vc->invMassD = c->p4->m_type == e_staticParticle ? 0.0f : c->p4->m_invMass;
|
||||||
|
|
||||||
|
pc->indexA = c->p1->m_solverId;
|
||||||
|
pc->invMassA = c->p1->m_type == e_staticParticle ? 0.0f : c->p1->m_invMass;
|
||||||
|
pc->radiusA = c->p1->m_radius;
|
||||||
|
|
||||||
|
pc->indexB = c->p2->m_solverId;
|
||||||
|
pc->invMassB = c->p2->m_type == e_staticParticle ? 0.0f : c->p2->m_invMass;
|
||||||
|
|
||||||
|
pc->indexC = c->p3->m_solverId;
|
||||||
|
pc->invMassC = c->p3->m_type == e_staticParticle ? 0.0f : c->p3->m_invMass;
|
||||||
|
|
||||||
|
pc->indexD = c->p4->m_solverId;
|
||||||
|
pc->invMassD = c->p4->m_type == e_staticParticle ? 0.0f : c->p4->m_invMass;
|
||||||
|
|
||||||
|
pc->triangleRadius = 0.0f;
|
||||||
|
pc->front = c->front;
|
||||||
|
|
||||||
|
u32 indexA = pc->indexA;
|
||||||
|
float32 mA = pc->invMassA;
|
||||||
|
|
||||||
|
u32 indexB = pc->indexB;
|
||||||
|
float32 mB = pc->invMassB;
|
||||||
|
|
||||||
|
u32 indexC = pc->indexC;
|
||||||
|
float32 mC = pc->invMassC;
|
||||||
|
|
||||||
|
u32 indexD = pc->indexD;
|
||||||
|
float32 mD = pc->invMassD;
|
||||||
|
|
||||||
|
b3Vec3 xA = x[indexA];
|
||||||
|
b3Vec3 xB = x[indexB];
|
||||||
|
b3Vec3 xC = x[indexC];
|
||||||
|
b3Vec3 xD = x[indexD];
|
||||||
|
|
||||||
|
b3Vec3 n = b3Cross(xC - xB, xD - xB);
|
||||||
|
|
||||||
|
if (pc->front == false)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
float32 n_len = n.Normalize();
|
||||||
|
|
||||||
|
b3Mat33 I; I.SetIdentity();
|
||||||
|
|
||||||
|
b3Mat33 N = I - b3Outer(n, n);
|
||||||
|
if (n_len > B3_EPSILON)
|
||||||
|
{
|
||||||
|
N = (1.0f / n_len) * N;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 N_n = N * n;
|
||||||
|
|
||||||
|
vc->JA = n;
|
||||||
|
vc->JC = b3Cross(xD - xB, N_n);
|
||||||
|
vc->JD = b3Cross(xC - xB, N_n);
|
||||||
|
vc->JB = b3Cross(xC - xD, N_n) - n;
|
||||||
|
|
||||||
|
// Compute effective mass.
|
||||||
|
float32 K = mA + mB + mC + mD;
|
||||||
|
|
||||||
|
vc->normalMass = K > 0.0f ? 1.0f / K : 0.0f;
|
||||||
|
vc->normalImpulse = c->normalImpulse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void b3ClothSolver::WarmStart()
|
void b3ClothSolver::WarmStart()
|
||||||
{
|
{
|
||||||
b3DenseVec3& v = *m_solverData.v;
|
b3DenseVec3& v = *m_solverData.v;
|
||||||
@ -718,6 +832,41 @@ void b3ClothSolver::WarmStart()
|
|||||||
v[indexA] = vA;
|
v[indexA] = vA;
|
||||||
v[indexB] = vB;
|
v[indexB] = vB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_triangleContactCount; ++i)
|
||||||
|
{
|
||||||
|
b3ClothSolverTriangleContactVelocityConstraint* vc = m_triangleVelocityConstraints + i;
|
||||||
|
|
||||||
|
u32 indexA = vc->indexA;
|
||||||
|
u32 indexB = vc->indexB;
|
||||||
|
u32 indexC = vc->indexC;
|
||||||
|
u32 indexD = vc->indexD;
|
||||||
|
|
||||||
|
b3Vec3 vA = v[indexA];
|
||||||
|
b3Vec3 vB = v[indexB];
|
||||||
|
b3Vec3 vC = v[indexC];
|
||||||
|
b3Vec3 vD = v[indexD];
|
||||||
|
|
||||||
|
float32 mA = vc->invMassA;
|
||||||
|
float32 mB = vc->invMassB;
|
||||||
|
float32 mC = vc->invMassC;
|
||||||
|
float32 mD = vc->invMassD;
|
||||||
|
|
||||||
|
b3Vec3 PA = vc->normalImpulse * vc->JA;
|
||||||
|
b3Vec3 PB = vc->normalImpulse * vc->JB;
|
||||||
|
b3Vec3 PC = vc->normalImpulse * vc->JC;
|
||||||
|
b3Vec3 PD = vc->normalImpulse * vc->JD;
|
||||||
|
|
||||||
|
vA += mA * PA;
|
||||||
|
vB += mB * PB;
|
||||||
|
vC += mC * PC;
|
||||||
|
vD += mD * PD;
|
||||||
|
|
||||||
|
v[indexA] = vA;
|
||||||
|
v[indexB] = vB;
|
||||||
|
v[indexC] = vC;
|
||||||
|
v[indexD] = vD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void b3ClothSolver::SolveBodyContactVelocityConstraints()
|
void b3ClothSolver::SolveBodyContactVelocityConstraints()
|
||||||
@ -879,6 +1028,59 @@ void b3ClothSolver::SolveParticleContactVelocityConstraints()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void b3ClothSolver::SolveTriangleContactVelocityConstraints()
|
||||||
|
{
|
||||||
|
b3DenseVec3& v = *m_solverData.v;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_triangleContactCount; ++i)
|
||||||
|
{
|
||||||
|
b3ClothSolverTriangleContactVelocityConstraint* vc = m_triangleVelocityConstraints + i;
|
||||||
|
|
||||||
|
u32 indexA = vc->indexA;
|
||||||
|
float32 mA = vc->invMassA;
|
||||||
|
|
||||||
|
u32 indexB = vc->indexB;
|
||||||
|
float32 mB = vc->invMassB;
|
||||||
|
|
||||||
|
u32 indexC = vc->indexC;
|
||||||
|
float32 mC = vc->invMassC;
|
||||||
|
|
||||||
|
u32 indexD = vc->indexD;
|
||||||
|
float32 mD = vc->invMassD;
|
||||||
|
|
||||||
|
b3Vec3 vA = v[indexA];
|
||||||
|
b3Vec3 vB = v[indexB];
|
||||||
|
b3Vec3 vC = v[indexC];
|
||||||
|
b3Vec3 vD = v[indexD];
|
||||||
|
|
||||||
|
b3Vec3 n = vc->JA;
|
||||||
|
|
||||||
|
// Allow some slop and prevent large corrections.
|
||||||
|
float32 Cdot = b3Dot(n, vA - vB);
|
||||||
|
|
||||||
|
float32 impulse = -vc->normalMass * Cdot;
|
||||||
|
|
||||||
|
float32 oldImpulse = vc->normalImpulse;
|
||||||
|
vc->normalImpulse = b3Max(vc->normalImpulse + impulse, 0.0f);
|
||||||
|
impulse = vc->normalImpulse - oldImpulse;
|
||||||
|
|
||||||
|
b3Vec3 PA = impulse * vc->JA;
|
||||||
|
b3Vec3 PB = impulse * vc->JB;
|
||||||
|
b3Vec3 PC = impulse * vc->JC;
|
||||||
|
b3Vec3 PD = impulse * vc->JD;
|
||||||
|
|
||||||
|
vA += mA * PA;
|
||||||
|
vB += mB * PB;
|
||||||
|
vC += mC * PC;
|
||||||
|
vD += mD * PD;
|
||||||
|
|
||||||
|
v[indexA] = vA;
|
||||||
|
v[indexB] = vB;
|
||||||
|
v[indexC] = vC;
|
||||||
|
v[indexD] = vD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void b3ClothSolver::StoreImpulses()
|
void b3ClothSolver::StoreImpulses()
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < m_bodyContactCount; ++i)
|
for (u32 i = 0; i < m_bodyContactCount; ++i)
|
||||||
@ -898,6 +1100,14 @@ void b3ClothSolver::StoreImpulses()
|
|||||||
c->normalImpulse = vc->normalImpulse;
|
c->normalImpulse = vc->normalImpulse;
|
||||||
c->tangentImpulse = vc->tangentImpulse;
|
c->tangentImpulse = vc->tangentImpulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_triangleContactCount; ++i)
|
||||||
|
{
|
||||||
|
b3TriangleContact* c = m_triangleContacts[i];
|
||||||
|
b3ClothSolverTriangleContactVelocityConstraint* vc = m_triangleVelocityConstraints + i;
|
||||||
|
|
||||||
|
c->normalImpulse = vc->normalImpulse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct b3ClothSolverContactSolverPoint
|
struct b3ClothSolverContactSolverPoint
|
||||||
@ -995,14 +1205,8 @@ bool b3ClothSolver::SolveBodyContactPositionConstraints()
|
|||||||
|
|
||||||
struct b3ClothSolverParticleContactSolverPoint
|
struct b3ClothSolverParticleContactSolverPoint
|
||||||
{
|
{
|
||||||
void Initialize(const b3Particle* p1, const b3Particle* p2)
|
void Initialize(const b3Vec3& cA, float32 rA, const b3Vec3& cB, float32 rB)
|
||||||
{
|
{
|
||||||
b3Vec3 cA = p1->GetPosition();
|
|
||||||
float32 rA = p1->GetRadius();
|
|
||||||
|
|
||||||
b3Vec3 cB = p2->GetPosition();
|
|
||||||
float32 rB = p2->GetRadius();
|
|
||||||
|
|
||||||
b3Vec3 d = cB - cA;
|
b3Vec3 d = cB - cA;
|
||||||
float32 distance = b3Length(d);
|
float32 distance = b3Length(d);
|
||||||
|
|
||||||
@ -1037,15 +1241,17 @@ bool b3ClothSolver::SolveParticleContactPositionConstraints()
|
|||||||
|
|
||||||
u32 indexA = pc->indexA;
|
u32 indexA = pc->indexA;
|
||||||
float32 mA = pc->invMassA;
|
float32 mA = pc->invMassA;
|
||||||
|
float32 rA = pc->radiusA;
|
||||||
|
|
||||||
u32 indexB = pc->indexB;
|
u32 indexB = pc->indexB;
|
||||||
float32 mB = pc->invMassB;
|
float32 mB = pc->invMassB;
|
||||||
|
float32 rB = pc->radiusB;
|
||||||
|
|
||||||
b3Vec3 xA = x[indexA];
|
b3Vec3 xA = x[indexA];
|
||||||
b3Vec3 xB = x[indexB];
|
b3Vec3 xB = x[indexB];
|
||||||
|
|
||||||
b3ClothSolverParticleContactSolverPoint cpcp;
|
b3ClothSolverParticleContactSolverPoint cpcp;
|
||||||
cpcp.Initialize(m_particles[indexA], m_particles[indexB]);
|
cpcp.Initialize(xA, rA, xB, rB);
|
||||||
|
|
||||||
b3Vec3 normal = cpcp.normal;
|
b3Vec3 normal = cpcp.normal;
|
||||||
b3Vec3 point = cpcp.point;
|
b3Vec3 point = cpcp.point;
|
||||||
@ -1071,5 +1277,92 @@ bool b3ClothSolver::SolveParticleContactPositionConstraints()
|
|||||||
x[indexB] = xB;
|
x[indexB] = xB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return minSeparation >= -3.0f * B3_LINEAR_SLOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool b3ClothSolver::SolveTriangleContactPositionConstraints()
|
||||||
|
{
|
||||||
|
b3DenseVec3& x = *m_solverData.v;
|
||||||
|
|
||||||
|
float32 minSeparation = 0.0f;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_triangleContactCount; ++i)
|
||||||
|
{
|
||||||
|
b3ClothSolverTriangleContactPositionConstraint* pc = m_trianglePositionConstraints + i;
|
||||||
|
|
||||||
|
u32 indexA = pc->indexA;
|
||||||
|
float32 mA = pc->invMassA;
|
||||||
|
float32 radiusA = pc->radiusA;
|
||||||
|
|
||||||
|
u32 indexB = pc->indexB;
|
||||||
|
float32 mB = pc->invMassB;
|
||||||
|
|
||||||
|
u32 indexC = pc->indexC;
|
||||||
|
float32 mC = pc->invMassC;
|
||||||
|
|
||||||
|
u32 indexD = pc->indexD;
|
||||||
|
float32 mD = pc->invMassD;
|
||||||
|
|
||||||
|
float32 triangleRadius = pc->triangleRadius;
|
||||||
|
|
||||||
|
b3Vec3 xA = x[indexA];
|
||||||
|
b3Vec3 xB = x[indexB];
|
||||||
|
b3Vec3 xC = x[indexC];
|
||||||
|
b3Vec3 xD = x[indexD];
|
||||||
|
|
||||||
|
b3Vec3 n = b3Cross(xC - xB, xD - xB);
|
||||||
|
if (pc->front == false)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
float32 n_len = n.Normalize();
|
||||||
|
|
||||||
|
float32 distance = b3Dot(n, xA - xB);
|
||||||
|
float32 separation = distance - radiusA - triangleRadius;
|
||||||
|
|
||||||
|
// Update max constraint error.
|
||||||
|
minSeparation = b3Min(minSeparation, separation);
|
||||||
|
|
||||||
|
// Allow some slop and prevent large corrections.
|
||||||
|
float32 C = b3Clamp(B3_BAUMGARTE * (separation + B3_LINEAR_SLOP), -B3_MAX_LINEAR_CORRECTION, 0.0f);
|
||||||
|
|
||||||
|
// Compute effective mass.
|
||||||
|
float32 K = mA + mB + mC + mD;
|
||||||
|
|
||||||
|
b3Mat33 I; I.SetIdentity();
|
||||||
|
|
||||||
|
b3Mat33 N = I - b3Outer(n, n);
|
||||||
|
if (n_len > B3_EPSILON)
|
||||||
|
{
|
||||||
|
N = (1.0f / n_len) * N;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 N_n = N * n;
|
||||||
|
|
||||||
|
b3Vec3 JA = n;
|
||||||
|
b3Vec3 JC = b3Cross(xD - xB, N_n);
|
||||||
|
b3Vec3 JD = b3Cross(xC - xB, N_n);
|
||||||
|
b3Vec3 JB = b3Cross(xC - xD, N_n) - n;
|
||||||
|
|
||||||
|
// Compute normal impulse.
|
||||||
|
float32 impulse = K > 0.0f ? -C / K : 0.0f;
|
||||||
|
|
||||||
|
b3Vec3 PA = impulse * JA;
|
||||||
|
b3Vec3 PB = impulse * JB;
|
||||||
|
b3Vec3 PC = impulse * JC;
|
||||||
|
b3Vec3 PD = impulse * JD;
|
||||||
|
|
||||||
|
xA += mA * PA;
|
||||||
|
xB += mB * PB;
|
||||||
|
xC += mC * PC;
|
||||||
|
xD += mD * PD;
|
||||||
|
|
||||||
|
x[indexA] = xA;
|
||||||
|
x[indexB] = xB;
|
||||||
|
x[indexC] = xC;
|
||||||
|
x[indexD] = xD;
|
||||||
|
}
|
||||||
|
|
||||||
return minSeparation >= -3.0f * B3_LINEAR_SLOP;
|
return minSeparation >= -3.0f * B3_LINEAR_SLOP;
|
||||||
}
|
}
|
@ -73,6 +73,7 @@ b3Particle::b3Particle(const b3ParticleDef& def, b3Cloth* cloth)
|
|||||||
m_mass = 0.0f;
|
m_mass = 0.0f;
|
||||||
m_invMass = 0.0f;
|
m_invMass = 0.0f;
|
||||||
m_radius = def.radius;
|
m_radius = def.radius;
|
||||||
|
m_friction = def.friction;
|
||||||
m_userData = nullptr;
|
m_userData = nullptr;
|
||||||
m_x.SetZero();
|
m_x.SetZero();
|
||||||
m_vertex = ~0;
|
m_vertex = ~0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user