Upgrade bounce

This commit is contained in:
Luke Benstead
2020-01-30 18:42:47 +00:00
parent 1509b9bd0e
commit e5897d433d
459 changed files with 98378 additions and 48427 deletions

View File

@ -0,0 +1,178 @@
/*
* 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 AABB_TIME_OF_IMPACT_H
#define AABB_TIME_OF_IMPACT_H
class AABBTimeOfImpact : public Test
{
public:
AABBTimeOfImpact()
{
b3Vec3 cA = b3Vec3_zero;
b3Vec3 eA(1.0f, 1.0f, 1.0f);
m_aabbA.Set(cA, eA);
b3Vec3 cB(-2.0f, -2.0f, 0.0f);
b3Vec3 eB(1.0f, 1.0f, 1.0f);
m_aabbB.Set(cB, eB);
m_dB.Set(1.0f, 1.0f, 0.0f);
m_time = 0.0f;
}
void Step()
{
g_draw->DrawString(b3Color_white, "Arrows - Translate AABB");
g_draw->DrawAABB(m_aabbA, b3Color_white);
g_draw->DrawAABB(m_aabbB, b3Color_white);
b3Vec3 cA = m_aabbA.GetCenter();
b3Vec3 cB = m_aabbB.GetCenter();
b3Vec3 eA = m_aabbA.GetExtents();
b3Vec3 eB = m_aabbB.GetExtents();
b3Vec3 dA = b3Vec3_zero;
b3Vec3 dB = m_dB;
g_draw->DrawSegment(cA, cA + dA, b3Color_white);
g_draw->DrawSegment(cB, cB + dB, b3Color_white);
{
b3Vec3 cBt = cB + m_time * dB;
b3AABB B;
B.Set(cBt, eB);
g_draw->DrawAABB(B, b3Color_red);
}
b3TOIOutput out = b3TimeOfImpact(m_aabbA, dA, m_aabbB, dB);
b3TOIOutput::State state = out.state;
scalar t = out.t;
if (state == b3TOIOutput::e_touching)
{
b3Vec3 cAt = cA + t * dA;
b3Vec3 cBt = cB + t * dB;
b3AABB A;
A.Set(cAt, eA);
b3AABB B;
B.Set(cBt, eB);
g_draw->DrawAABB(A, b3Color_black);
g_draw->DrawAABB(B, b3Color_black);
}
if (state == b3TOIOutput::e_failed)
{
g_draw->DrawString(b3Color_white, "State = Failed");
}
else if (state == b3TOIOutput::e_overlapped)
{
g_draw->DrawString(b3Color_white, "State = Overlapped");
}
else if (state == b3TOIOutput::e_separated)
{
g_draw->DrawString(b3Color_white, "State = Separated!");
}
else if (state == b3TOIOutput::e_touching)
{
g_draw->DrawString(b3Color_white, "State = Touching!");
}
}
void KeyDown(int key)
{
const scalar dt = 0.01f;
const scalar d = 0.1f;
if (key == GLFW_KEY_F)
{
m_time += dt;
if (m_time > 1.0f)
{
m_time = 0.0f;
}
}
if (key == GLFW_KEY_B)
{
m_time -= dt;
if (m_time < 0.0f)
{
m_time = 1.0f;
}
}
if (key == GLFW_KEY_LEFT)
{
m_aabbB.lowerBound.x -= d;
m_aabbB.upperBound.x -= d;
}
if (key == GLFW_KEY_RIGHT)
{
m_aabbB.lowerBound.x += d;
m_aabbB.upperBound.x += d;
}
if (key == GLFW_KEY_UP)
{
m_aabbB.lowerBound.y += d;
m_aabbB.upperBound.y += d;
}
if (key == GLFW_KEY_DOWN)
{
m_aabbB.lowerBound.y -= d;
m_aabbB.upperBound.y -= d;
}
if (key == GLFW_KEY_W)
{
m_aabbB.lowerBound.z += d;
m_aabbB.upperBound.z += d;
}
if (key == GLFW_KEY_S)
{
m_aabbB.lowerBound.z -= d;
m_aabbB.upperBound.z -= d;
}
}
static Test* Create()
{
return new AABBTimeOfImpact();
}
scalar m_time;
b3AABB m_aabbA;
b3AABB m_aabbB;
b3Vec3 m_dB;
};
#endif

View File

@ -32,8 +32,8 @@ public:
b3Body* body = m_world.CreateBody(bd);
b3CapsuleShape shape;
shape.m_centers[0].Set(0.0f, 0.0f, -1.0f);
shape.m_centers[1].Set(0.0f, 0.0f, 1.0f);
shape.m_vertex1.Set(0.0f, 0.0f, -1.0f);
shape.m_vertex2.Set(0.0f, 0.0f, 1.0f);
shape.m_radius = 1.0f;
b3ShapeDef sdef;

View File

@ -19,33 +19,34 @@
#ifndef BEAM_H
#define BEAM_H
#include <testbed/framework/softbody_dragger.h>
class Beam : public Test
{
public:
enum
{
e_w = 5,
e_h = 2,
e_d = 2
};
Beam()
{
m_E0 = 1000.0f;
m_E = m_E0;
// Create soft body
b3SoftBodyDef def;
def.mesh = &m_mesh;
def.density = 0.2f;
def.E = 1000.0f;
def.E = m_E0;
def.nu = 0.33f;
def.radius = 0.2f;
def.friction = 0.6f;
m_body = new b3SoftBody(def);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
m_body->SetWorld(&m_world);
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
b3SoftBodyNode* n = m_body->GetVertexNode(i);
n->SetRadius(0.05f);
n->SetFriction(0.2f);
}
// Create body
{
@ -55,7 +56,7 @@ public:
b3Body* b = m_world.CreateBody(bd);
m_wallHull.Set(1.0f, 5.0f, 5.0f);
m_wallHull.SetExtents(1.0f, 5.0f, 5.0f);
b3HullShape wallShape;
wallShape.m_hull = &m_wallHull;
@ -64,18 +65,20 @@ public:
sd.shape = &wallShape;
b3Shape* wall = b->CreateShape(sd);
b3SoftBodyWorldShapeDef ssd;
ssd.shape = wall;
m_body->CreateWorldShape(ssd);
}
b3AABB3 aabb;
aabb.m_lower.Set(-3.0f, -5.0f, -5.0f);
aabb.m_upper.Set(-2.0f, 5.0f, 5.0f);
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
for (u32 i = 0; i < e_h + 1; ++i)
{
b3SoftBodyNode* n = m_body->GetVertexNode(i);
b3Vec3 p = n->GetPosition();
if (aabb.Contains(p))
for (u32 k = 0; k < e_d + 1; ++k)
{
u32 v = m_mesh.GetVertex(i, 0, k);
b3SoftBodyNode* n = m_body->GetNode(v);
n->SetType(e_staticSoftBodyNode);
}
}
@ -107,9 +110,9 @@ public:
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -117,8 +120,10 @@ public:
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
float32 E = m_body->GetEnergy();
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
g_draw->DrawString(b3Color_white, "Up/Down - Young Modulus (%f)", m_E);
}
void MouseMove(const b3Ray3& pw)
@ -146,13 +151,37 @@ public:
}
}
void KeyDown(int button)
{
if (button == GLFW_KEY_UP)
{
m_E = b3Clamp(m_E + scalar(10), scalar(0), m_E0);
for (u32 i = 0; i < m_mesh.tetrahedronCount; ++i)
{
m_body->GetElement(i)->SetE(m_E);
}
}
if (button == GLFW_KEY_DOWN)
{
m_E = b3Clamp(m_E - scalar(10), scalar(10), m_E0);
for (u32 i = 0; i < m_mesh.tetrahedronCount; ++i)
{
m_body->GetElement(i)->SetE(m_E);
}
}
}
static Test* Create()
{
return new Beam();
}
b3BlockSoftBodyMesh<5, 2, 2> m_mesh;
b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh;
scalar m_E0;
scalar m_E;
b3SoftBody* m_body;
b3SoftBodyDragger* m_bodyDragger;

View File

@ -47,8 +47,8 @@ public:
m_body = m_world.CreateBody(bd);
b3CapsuleShape cap;
cap.m_centers[0].Set(0.0f, 2.0f, 0.0f);
cap.m_centers[1].Set(0.0f, -2.0f, 0.0f);
cap.m_vertex1.Set(0.0f, 2.0f, 0.0f);
cap.m_vertex2.Set(0.0f, -2.0f, 0.0f);
cap.m_radius = 0.5f;
b3ShapeDef sd;
@ -94,7 +94,7 @@ public:
bd.type = b3BodyType::e_dynamicBody;
bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f));
b3Vec3 n = m_body->GetTransform().position - bd.position;
b3Vec3 n = m_body->GetTransform().translation - bd.position;
n.Normalize();
bd.linearVelocity = 100.0f * n;
@ -122,7 +122,7 @@ public:
p.x -= 1.0f;
m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w);
m_body->SetTransform(p, q);
}
if (button == GLFW_KEY_RIGHT)
@ -132,7 +132,7 @@ public:
p.x += 1.0f;
m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w);
m_body->SetTransform(p, q);
}
if (button == GLFW_KEY_UP)
@ -142,7 +142,7 @@ public:
p.z += 1.0f;
m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w);
m_body->SetTransform(p, q);
}
if (button == GLFW_KEY_DOWN)
@ -152,7 +152,7 @@ public:
p.z -= 1.0f;
m_body->SetTransform(p, b3Vec3(q.x, q.y, q.z), q.w);
m_body->SetTransform(p, q);
}
}

View File

@ -24,27 +24,19 @@ class BoxEdgeContact : public Collide
public:
BoxEdgeContact()
{
b3Transform xf;
xf.position.SetZero();
xf.rotation = b3Diagonal(1.0f, 2.0f, 1.0f);
m_box.SetTransform(xf);
m_box.SetExtents(1.0f, 2.0f, 1.0f);
m_sA.m_hull = &m_box;
m_sB.m_hull = &m_box;
m_xfA.position.Set(1.500000, 1.000000, 0.000000);
m_xfA.rotation.x.Set(0.707107, 0.000000, -0.707107);
m_xfA.rotation.y.Set(0.000000, 1.000000, 0.000000);
m_xfA.rotation.z.Set(0.707107, 0.000000, 0.707107);
m_xfA.translation.Set(1.500000, 1.000000, 0.000000);
m_xfA.rotation.SetIdentity();
m_shapeA = &m_sA;
m_xfB.position.Set(-1.300000, 0.000000, 0.000000);
m_xfB.rotation.x.Set(0.809017, 0.266849, -0.523721);
m_xfB.rotation.y.Set(0.000000, 0.891007, 0.453991);
m_xfB.rotation.z.Set(0.587785, -0.367286, 0.720840);
m_sB.m_hull = &m_box;
m_xfB.translation.Set(-1.29999995, 1.34999979, 0.000000000);
m_xfB.rotation.Set(0.810514629, 0.342624813, 0.334119707, 0.337692767);
m_shapeB = &m_sB;
m_cache.count = 0;
m_shapeA = &m_sA;
m_shapeB = &m_sB;
}
static Test* Create()

View File

@ -24,28 +24,24 @@ class BoxFaceContact : public Collide
public:
BoxFaceContact()
{
b3Transform m;
m.rotation = b3Diagonal(1.0f, 2.0f, 1.0f);
m.position.Set(0.0f, 2.0f, 0.0f);
m_box1.SetTransform(m);
m_boxA.SetExtents(1.0f, 2.0f, 1.0f);
b3Vec3 translation(0.0f, 2.0f, 0.0f);
m_boxA.Translate(translation);
m.rotation = b3Diagonal(1.0f, 1.0f, 1.0f);
m.position.Set(0.0f, 0.0f, 0.0f);
m_box2.SetTransform(m);
m_xfA.SetIdentity();
m_xfA.position.SetZero();
m_xfA.rotation.SetIdentity();
m_sA.m_hull = &m_box1;
m_sA.m_hull = &m_boxA;
m_xfB.SetIdentity();
m_xfB.position.Set(0.0f, 0.0f, 0.0f);
m_xfB.rotation.SetIdentity();
m_sB.m_hull = &m_box2;
m_xfA.SetIdentity();
m_cache.count = 0;
m_shapeA = &m_sA;
m_boxB.SetExtents(1.0f, 1.0f, 1.0f);
m_xfB.SetIdentity();
m_sB.m_hull = &m_boxB;
m_shapeB = &m_sB;
m_cache.count = 0;
}
static Test* Create()
@ -53,8 +49,8 @@ public:
return new BoxFaceContact();
}
b3BoxHull m_box1;
b3BoxHull m_box2;
b3BoxHull m_boxA;
b3BoxHull m_boxB;
b3HullShape m_sA;
b3HullShape m_sB;
};

View File

@ -24,17 +24,15 @@ class BoxStack : public Test
public:
enum
{
e_rowCount = 1,
e_columnCount = 5,
e_depthCount = 1
e_h = 5,
e_w = 1,
e_d = 1
};
BoxStack()
{
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_staticBody;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
@ -47,30 +45,53 @@ public:
body->CreateShape(sdef);
}
b3Vec3 boxScale(1.0f, 1.0f, 1.0f);
b3Vec3 e(1.0f, 1.0f, 1.0f);
b3Vec3 stackOrigin(0.0f, 4.05f, 0.0f);
m_boxHull.SetExtents(e.x, e.y, e.z);
for (u32 i = 0; i < e_rowCount; ++i)
b3Vec3 separation;
separation.x = 1.0f;
separation.y = 1.0f;
separation.z = 1.0f;
b3Vec3 scale;
scale.x = 2.0f * e.x + separation.x;
scale.y = 2.0f * e.y + separation.y;
scale.z = 2.0f * e.z + separation.z;
b3Vec3 size;
size.x = 2.0f * e.x + scale.x * scalar(e_w - 1);
size.y = 2.0f * e.y + scale.y * scalar(e_h - 1);
size.z = 2.0f * e.z + scale.z * scalar(e_d - 1);
b3Vec3 translation;
translation.x = e.x - 0.5f * size.x;
translation.y = e.y - 0.5f * size.y;
translation.z = e.z - 0.5f * size.z;
translation.y += 9.0f;
for (u32 i = 0; i < e_h; ++i)
{
for (u32 j = 0; j < e_columnCount; ++j)
for (u32 j = 0; j < e_w; ++j)
{
for (u32 k = 0; k < e_depthCount; ++k)
for (u32 k = 0; k < e_d; ++k)
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_dynamicBody;
bdef.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.5f * B3_PI);
bdef.type = e_dynamicBody;
bdef.position.x = float32(i) * boxScale.x;
bdef.position.y = 2.5f * float32(j) * boxScale.y;
bdef.position.z = float32(k) * boxScale.z;
bdef.position.Set(scalar(j), scalar(i), scalar(k));
bdef.position += stackOrigin;
bdef.position.x *= scale.x;
bdef.position.y *= scale.y;
bdef.position.z *= scale.z;
bdef.position += translation;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
hs.m_hull = &m_boxHull;
b3ShapeDef sdef;
sdef.density = 0.1f;
@ -78,15 +99,30 @@ public:
sdef.shape = &hs;
body->CreateShape(sdef);
u32 bodyIndex = GetBodyIndex(i, j, k);
m_bodies[bodyIndex] = body;
}
}
}
}
u32 GetBodyIndex(u32 i, u32 j, u32 k)
{
B3_ASSERT(i < e_h);
B3_ASSERT(j < e_w);
B3_ASSERT(k < e_d);
return k + e_d * (j + e_w * i);
}
static Test* Create()
{
return new BoxStack();
}
b3BoxHull m_boxHull;
b3Body* m_bodies[e_h * e_w * e_d];
};
#endif

View File

@ -0,0 +1,215 @@
/*
* 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 CAPE_H
#define CAPE_H
class Cape : public Test
{
public:
enum
{
e_w = 5,
e_h = 10
};
Cape()
{
// Translate the cloth mesh
for (u32 i = 0; i < m_clothMesh.vertexCount; ++i)
{
m_clothMesh.vertices[i].y += 5.0f;
m_clothMesh.vertices[i].z -= 6.0f;
}
// Create cloth
b3ClothDef def;
def.mesh = &m_clothMesh;
def.density = 0.2f;
def.streching = 100000.0f;
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
// Freeze some particles
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 vj = m_clothMesh.GetVertex(e_h, j);
b3ClothParticle* p = m_cloth->GetParticle(vj);
p->SetType(e_kinematicClothParticle);
}
m_clothDragger = new b3ClothDragger(&m_ray, m_cloth);
{
// Create body
b3BodyDef bdef;
bdef.type = b3BodyType::e_kinematicBody;
m_body = m_world.CreateBody(bdef);
static b3BoxHull box(1.0f, 5.0f, 1.0f);
b3HullShape hs;
hs.m_hull = &box;
hs.m_radius = 0.25f;
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &hs;
m_body->CreateShape(sdef);
}
// Store cloth vertices in body space
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 vj = m_clothMesh.GetVertex(e_h, j);
b3ClothParticle* p = m_cloth->GetParticle(vj);
b3Vec3 position = p->GetPosition();
m_localPoints[j] = m_body->GetLocalPoint(position);
}
}
~Cape()
{
delete m_clothDragger;
delete m_cloth;
}
void KeyDown(int button)
{
b3Vec3 v = m_body->GetLinearVelocity();
if (button == GLFW_KEY_LEFT)
{
v.x -= 5.0f;
}
if (button == GLFW_KEY_RIGHT)
{
v.x += 5.0f;
}
if (button == GLFW_KEY_UP)
{
v.z -= 5.0f;
}
if (button == GLFW_KEY_DOWN)
{
v.z += 5.0f;
}
m_body->SetLinearVelocity(v);
}
void Step()
{
Test::Step();
scalar inv_h = g_testSettings->hertz;
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 vj = m_clothMesh.GetVertex(e_h, j);
b3ClothParticle* p = m_cloth->GetParticle(vj);
b3Vec3 x0 = p->GetPosition();
b3Vec3 x = m_body->GetWorldPoint(m_localPoints[j]);
// Apply finite difference method
b3Vec3 v = inv_h * (x - x0);
p->SetVelocity(v);
}
m_cloth->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_cloth->Draw();
if (m_clothDragger->IsDragging())
{
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
g_draw->DrawString(b3Color_white, "Arrows - Apply Velocity");
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->Drag();
}
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_clothDragger->IsDragging() == false)
{
m_clothDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->StopDragging();
}
}
static Test* Create()
{
return new Cape();
}
b3GridClothMesh<e_w, e_h> m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
b3Body* m_body;
b3Vec3 m_localPoints[e_w + 1];
};
#endif

View File

@ -24,25 +24,21 @@ class CapsuleCollision : public Collide
public:
CapsuleCollision()
{
m_xfA.SetIdentity();
m_xfA.position.Set(0.0f, 0.0f, 0.0f);
//m_xfA.rotation = b3ConvertQuatToRot(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.25f * B3_PI));
m_xfA.rotation.SetIdentity();
m_sA.m_centers[0].Set(0.0f, -5.0f, 0.0f);
m_sA.m_centers[1].Set(0.0f, 5.0f, 0.0f);
m_sA.m_vertex1.Set(0.0f, -5.0f, 0.0f);
m_sA.m_vertex2.Set(0.0f, 5.0f, 0.0f);
m_sA.m_radius = 1.0f;
m_xfB.SetIdentity();
m_xfB.position.Set(0.f, 0.0f, 0.0f);
//m_xfB.rotation = b3ConvertQuatToRot(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.251f * B3_PI));
m_xfB.rotation.SetIdentity();
m_sB.m_centers[0].Set(0.0f, -1.0f, 0.0f);
m_sB.m_centers[1].Set(0.0f, 1.0f, 0.0f);
m_xfA.SetIdentity();
m_sB.m_vertex1.Set(0.0f, -1.0f, 0.0f);
m_sB.m_vertex2.Set(0.0f, 1.0f, 0.0f);
m_sB.m_radius = 1.0f;
m_cache.count = 0;
m_xfB.SetIdentity();
m_shapeA = &m_sA;
m_shapeB = &m_sB;
m_cache.count = 0;
}
static Test* Create()

View File

@ -40,16 +40,15 @@ public:
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(0.0f, 10.0f, 0.0f);
bdef.orientation.Set(b3Vec3(0.0f, 0.0f, -1.0f), 1.5f * B3_PI);
bdef.linearVelocity.Set(0.005f, -10.0f, 0.005f);
bdef.angularVelocity.Set(2000.0f * B3_PI, 2000.0f * B3_PI, 10000.0f * B3_PI);
bdef.angularVelocity.Set(0.5f * B3_PI, 10.0f * B3_PI, 0.0f);
b3Body* body = m_world.CreateBody(bdef);
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, 4.0f, 0.0f);
capsule.m_centers[1].Set(0.0f, -4.0f, 0.0f);
capsule.m_vertex1.Set(0.0f, 4.0f, 0.0f);
capsule.m_vertex2.Set(0.0f, -4.0f, 0.0f);
capsule.m_radius = 0.5f;
b3ShapeDef sd;

View File

@ -24,104 +24,110 @@ class CapsuleStack : public Test
public:
enum
{
e_rowCount = 1,
e_columnCount = 5,
e_depthCount = 1
e_h = 5,
e_w = 1,
e_d = 1
};
CapsuleStack()
{
{
b3BodyDef bd;
bd.type = b3BodyType::e_staticBody;
b3Body* body = m_world.CreateBody(bd);
b3BodyDef bdef;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &hs;
body->CreateShape(sd);
b3ShapeDef sdef;
sdef.shape = &hs;
sdef.friction = 1.0f;
body->CreateShape(sdef);
}
float32 height = 3.0f;
float32 radius = 1.0f;
float32 separation = 0.0f;
scalar rx = 1.0f;
scalar r = 1.0f;
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, -0.5f * height, 0.0f);
capsule.m_centers[1].Set(0.0f, 0.5f * height, 0.0f);
capsule.m_radius = radius;
capsule.m_vertex1.Set(-rx, 0.0f, 0.0f);
capsule.m_vertex2.Set(rx, 0.0f, 0.0f);
capsule.m_radius = r;
b3ShapeDef sdef;
sdef.shape = &capsule;
sdef.density = 0.1f;
sdef.friction = 0.4f;
b3Vec3 e;
e.x = rx + r;
e.y = r;
e.z = r;
const u32 c = e_rowCount * e_columnCount * e_depthCount;
b3Body* bs[c];
u32 n = 0;
b3Vec3 separation;
separation.x = 1.0f;
separation.y = 1.0f;
separation.z = 1.0f;
b3AABB3 aabb;
aabb.m_lower.Set(0.0f, 0.0f, 0.0f);
aabb.m_upper.Set(0.0f, 0.0f, 0.0f);
b3Vec3 scale;
scale.x = 2.0f * e.x + separation.x;
scale.y = 2.0f * e.y + separation.y;
scale.z = 2.0f * e.z + separation.z;
for (u32 i = 0; i < e_rowCount; ++i)
b3Vec3 size;
size.x = 2.0f * e.x + scale.x * scalar(e_w - 1);
size.y = 2.0f * e.y + scale.y * scalar(e_h - 1);
size.z = 2.0f * e.z + scale.z * scalar(e_d - 1);
b3Vec3 translation;
translation.x = e.x - 0.5f * size.x;
translation.y = e.y - 0.5f * size.y;
translation.z = e.z - 0.5f * size.z;
translation.y += 9.0f;
for (u32 i = 0; i < e_h; ++i)
{
for (u32 j = 0; j < e_columnCount; ++j)
for (u32 j = 0; j < e_w; ++j)
{
for (u32 k = 0; k < e_depthCount; ++k)
for (u32 k = 0; k < e_d; ++k)
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_dynamicBody;
bdef.position.x = (2.0f + separation) * float32(i) * (0.5f * height + radius);
bdef.position.y = 2.0f + (2.0f + separation) * float32(j) * radius;
bdef.position.z = (2.0f + separation) * float32(k) * radius;
bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bdef.type = e_dynamicBody;
bdef.position.Set(scalar(j), scalar(i), scalar(k));
bdef.position.x *= scale.x;
bdef.position.y *= scale.y;
bdef.position.z *= scale.z;
bdef.position += translation;
b3Body* body = m_world.CreateBody(bdef);
bs[n++] = body;
b3Shape* shape = body->CreateShape(sdef);
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &capsule;
b3AABB3 aabb2;
shape->ComputeAABB(&aabb2, body->GetTransform());
body->CreateShape(sdef);
aabb = b3Combine(aabb, aabb2);
u32 bodyIndex = GetBodyIndex(i, j, k);
m_bodies[bodyIndex] = body;
}
}
}
}
b3Vec3 center = aabb.Centroid();
for (u32 i = 0; i < n; ++i)
{
b3Body* b = bs[i];
const b3Vec3& p = b->GetSweep().worldCenter;
const b3Quat& q = b->GetSweep().orientation;
// centralize
b3Vec3 position = p - center;
// move up
position.y += 5.0f + 0.5f * aabb.Height() + radius;
// maintain orientation
b3Vec3 axis;
float32 angle;
q.GetAxisAngle(&axis, &angle);
b->SetTransform(position, axis, angle);
}
u32 GetBodyIndex(u32 i, u32 j, u32 k)
{
B3_ASSERT(i < e_h);
B3_ASSERT(j < e_w);
B3_ASSERT(k < e_d);
return k + e_d * (j + e_w * i);
}
static Test* Create()
{
return new CapsuleStack();
}
b3Body* m_bodies[e_h * e_w * e_d];
};
#endif
#endif

View File

@ -0,0 +1,181 @@
/*
* 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 CLOTH_ELEMENT_TEST_H
#define CLOTH_ELEMENT_TEST_H
class ClothElementTest : public Test
{
public:
enum
{
e_w = 10,
e_h = 10
};
ClothElementTest()
{
g_camera->m_zoom = 20.0f;
b3GridClothMesh<e_w, e_h> m;
b3ClothParticle** particles = (b3ClothParticle * *)b3Alloc(m.vertexCount * sizeof(b3ClothParticle*));
for (u32 i = 0; i < m.vertexCount; ++i)
{
b3ClothParticleDef pd;
pd.type = e_dynamicClothParticle;
pd.position = m.vertices[i];
b3ClothParticle* p = m_cloth.CreateParticle(pd);
particles[i] = p;
b3ClothSphereShapeDef sd;
sd.p = p;
sd.radius = 0.2f;
sd.friction = 0.4f;
m_cloth.CreateSphereShape(sd);
}
for (u32 i = 0; i < m.triangleCount; ++i)
{
u32 v1 = m.triangles[i].v1;
u32 v2 = m.triangles[i].v2;
u32 v3 = m.triangles[i].v3;
b3Vec3 x1 = m.vertices[v1];
b3Vec3 x2 = m.vertices[v2];
b3Vec3 x3 = m.vertices[v3];
b3ClothParticle* p1 = particles[v1];
b3ClothParticle* p2 = particles[v2];
b3ClothParticle* p3 = particles[v3];
b3ClothTriangleShapeDef tsd;
tsd.p1 = p1;
tsd.p2 = p2;
tsd.p3 = p3;
tsd.v1 = x1;
tsd.v2 = x2;
tsd.v3 = x3;
tsd.density = 0.1f;
m_cloth.CreateTriangleShape(tsd);
b3ElementForceDef fd;
fd.p1 = p1;
fd.p2 = p2;
fd.p3 = p3;
fd.E_x = 500.0f;
fd.E_y = 500.0f;
fd.E_s = 500.0f;
fd.nu_xy = 0.3f;
fd.nu_yx = 0.3f;
fd.v1 = x1;
fd.v2 = x2;
fd.v3 = x3;
m_cloth.CreateForce(fd);
}
for (u32 i = 0; i < e_w + 1; ++i)
{
u32 vertex = m.GetVertex(0, i);
particles[vertex]->SetType(e_staticClothParticle);
}
b3Free(particles);
m_cloth.SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_clothDragger = new b3ClothDragger(&m_ray, &m_cloth);
m_clothDragger->SetStaticDrag(false);
}
~ClothElementTest()
{
delete m_clothDragger;
}
void Step()
{
Test::Step();
m_cloth.Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_cloth.Draw();
if (m_clothDragger->IsDragging())
{
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
scalar E = m_cloth.GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->Drag();
}
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_clothDragger->IsDragging() == false)
{
m_clothDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->StopDragging();
}
}
static Test* Create()
{
return new ClothElementTest();
}
b3Cloth m_cloth;
b3ClothDragger* m_clothDragger;
};
#endif

View File

@ -0,0 +1,268 @@
/*
* 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 CLOTH_SDF_H
#define CLOTH_SDF_H
#define TINYOBJLOADER_IMPLEMENTATION
#include <tinyobjloader/tiny_obj_loader.h>
struct SDFMesh
{
u32 vertexCount;
b3Vec3* vertices;
u32 indexCount;
u32* indices;
SDFMesh()
{
vertexCount = 0;
vertices = nullptr;
indexCount = 0;
indices = nullptr;
}
~SDFMesh()
{
free(vertices);
free(indices);
}
bool Load(const char* filename)
{
tinyobj::attrib_t attributes;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warning;
std::string error;
bool ok = tinyobj::LoadObj(&attributes, &shapes, &materials, &warning, &error, filename);
if (!ok)
{
return false;
}
assert(vertexCount == 0);
vertexCount = attributes.vertices.size() / 3;
vertices = (b3Vec3*)malloc(vertexCount * sizeof(b3Vec3));
for (size_t i = 0; i < attributes.vertices.size() / 3; ++i)
{
tinyobj::real_t x = attributes.vertices[3 * i + 0];
tinyobj::real_t y = attributes.vertices[3 * i + 1];
tinyobj::real_t z = attributes.vertices[3 * i + 2];
b3Vec3 v(x, y, z);
vertices[i] = v;
}
assert(indexCount == 0);
for (size_t s = 0; s < shapes.size(); s++)
{
tinyobj::shape_t& shape = shapes[s];
for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++)
{
indexCount += 3;
}
}
indices = (u32*)malloc(indexCount * sizeof(u32));
indexCount = 0;
for (size_t s = 0; s < shapes.size(); s++)
{
tinyobj::shape_t& shape = shapes[s];
size_t index_offset = 0;
for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++)
{
unsigned char fv = shapes[s].mesh.num_face_vertices[f];
for (size_t v = 0; v < 3; v++)
{
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
size_t vi = idx.vertex_index;
indices[indexCount++] = vi;
}
index_offset += fv;
}
}
return true;
}
void Draw(const b3Transform& xf, const b3Vec3& scale, const b3Color& color) const
{
for (u32 i = 0; i < indexCount / 3; ++i)
{
u32 i1 = indices[3 * i + 0];
u32 i2 = indices[3 * i + 1];
u32 i3 = indices[3 * i + 2];
b3Vec3 v1 = xf * b3MulCW(scale, vertices[i1]);
b3Vec3 v2 = xf * b3MulCW(scale, vertices[i2]);
b3Vec3 v3 = xf * b3MulCW(scale, vertices[i3]);
b3Vec3 n = b3Cross(v2 - v1, v3 - v1);
n.Normalize();
g_draw->DrawSolidTriangle(n, v1, v2, v3, color);
}
}
};
class ClothSDF : public Test
{
public:
ClothSDF()
{
// Translate the cloth mesh
for (u32 i = 0; i < m_clothMesh.vertexCount; ++i)
{
m_clothMesh.vertices[i].y += 5.0f;
}
// Create cloth
b3ClothDef def;
def.mesh = &m_clothMesh;
def.density = 0.2f;
def.streching = 10000.0f;
def.strechDamping = 100.0f;
def.thickness = 0.2f;
def.friction = 0.2f;
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
{
bool ok = m_sdfMesh.Load("data/teapot.obj");
assert(ok);
}
{
b3BodyDef bd;
bd.type = e_staticBody;
b3Body* b = m_world.CreateBody(bd);
bool ok = m_sdf.Load("data/teapot.cdf");
assert(ok);
b3SDFShape sdfShape;
sdfShape.m_sdf = &m_sdf;
sdfShape.m_radius = 0.2f;
b3ShapeDef sd;
sd.shape = &sdfShape;
sd.friction = 1.0f;
m_sdfShape = (b3SDFShape*)b->CreateShape(sd);
b3ClothWorldShapeDef csd;
csd.shape = m_sdfShape;
m_cloth->CreateWorldShape(csd);
}
m_clothDragger = new b3ClothDragger(&m_ray, m_cloth);
}
~ClothSDF()
{
delete m_clothDragger;
delete m_cloth;
}
void Step()
{
Test::Step();
m_cloth->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_cloth->Draw();
if (m_clothDragger->IsDragging())
{
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
b3Body* sdfBody = m_sdfShape->GetBody();
m_sdfMesh.Draw(sdfBody->GetTransform(), m_sdfShape->m_scale, b3Color_white);
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->Drag();
}
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_clothDragger->IsDragging() == false)
{
m_clothDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->StopDragging();
}
}
static Test* Create()
{
return new ClothSDF();
}
b3GridClothMesh<10, 10> m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
SDFMesh m_sdfMesh;
b3SDF m_sdf;
b3SDFShape* m_sdfShape;
};
#endif

View File

@ -22,15 +22,82 @@
class ClothSelfCollision : public Test
{
public:
enum
{
e_w1 = 5,
e_h1 = 5,
e_w2 = 5,
e_h2 = 5
};
ClothSelfCollision()
{
// Translate the mesh
for (u32 i = 0; i < m_clothMesh.vertexCount; ++i)
b3GridClothMesh<e_w1, e_h1> mesh1;
b3Quat qX = b3QuatRotationX(0.5f * B3_PI);
for (u32 i = 0; i < mesh1.vertexCount; ++i)
{
m_clothMesh.vertices[i].y += 5.0f;
mesh1.vertices[i] = b3Mul(qX, mesh1.vertices[i]);
mesh1.vertices[i].y += 5.0f;
}
// Create cloth
b3GridClothMesh<e_w2, e_h2> mesh2;
b3Quat qY = b3QuatRotationY(0.5f * B3_PI);
for (u32 i = 0; i < mesh2.vertexCount; ++i)
{
mesh2.vertices[i] = b3Mul(qY * qX, mesh2.vertices[i]);
mesh2.vertices[i].y += 12.0f;
}
// Merge the meshes
m_clothMesh.vertexCount = mesh1.vertexCount + mesh2.vertexCount;
m_clothMesh.vertices = (b3Vec3*)b3Alloc(m_clothMesh.vertexCount * sizeof(b3Vec3));
u32* newVertices1 = (u32*)b3Alloc(mesh1.vertexCount * sizeof(u32));
u32 vertexIndex = 0;
for (u32 i = 0; i < mesh1.vertexCount; ++i)
{
newVertices1[i] = vertexIndex;
m_clothMesh.vertices[vertexIndex++] = mesh1.vertices[i];
}
u32* newVertices2 = (u32*)b3Alloc(mesh2.vertexCount * sizeof(u32));
for (u32 i = 0; i < mesh2.vertexCount; ++i)
{
newVertices2[i] = vertexIndex;
m_clothMesh.vertices[vertexIndex++] = mesh2.vertices[i];
}
m_clothMesh.triangleCount = mesh1.triangleCount + mesh2.triangleCount;
m_clothMesh.triangles = (b3ClothMeshTriangle*)b3Alloc(m_clothMesh.triangleCount * sizeof(b3ClothMeshTriangle));
u32 triangleIndex = 0;
for (u32 i = 0; i < mesh1.triangleCount; ++i)
{
m_clothMesh.triangles[triangleIndex].v1 = newVertices1[mesh1.triangles[i].v1];
m_clothMesh.triangles[triangleIndex].v2 = newVertices1[mesh1.triangles[i].v2];
m_clothMesh.triangles[triangleIndex].v3 = newVertices1[mesh1.triangles[i].v3];
++triangleIndex;
}
for (u32 i = 0; i < mesh2.triangleCount; ++i)
{
m_clothMesh.triangles[triangleIndex].v1 = newVertices2[mesh2.triangles[i].v1];
m_clothMesh.triangles[triangleIndex].v2 = newVertices2[mesh2.triangles[i].v2];
m_clothMesh.triangles[triangleIndex].v3 = newVertices2[mesh2.triangles[i].v3];
++triangleIndex;
}
m_clothMesh.meshCount = 1;
m_clothMesh.meshes = (b3ClothMeshMesh*)b3Alloc(sizeof(b3ClothMeshMesh));
m_clothMesh.meshes->startTriangle = 0;
m_clothMesh.meshes->triangleCount = m_clothMesh.triangleCount;
m_clothMesh.meshes->startVertex = 0;
m_clothMesh.meshes->vertexCount = m_clothMesh.vertexCount;
m_clothMesh.shearingLineCount = 0;
m_clothMesh.bendingLineCount = 0;
m_clothMesh.sewingLineCount = 0;
// Create the cloth
b3ClothDef def;
def.mesh = &m_clothMesh;
def.density = 1.0f;
@ -41,24 +108,37 @@ public:
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_cloth->SetWorld(&m_world);
m_cloth->EnableSelfCollision(true);
for (u32 i = 0; i < mesh1.vertexCount; ++i)
{
u32 newVertex = newVertices1[i];
m_cloth->GetParticle(newVertex)->SetType(e_staticClothParticle);
}
b3Free(newVertices1);
b3Free(newVertices2);
{
b3BodyDef bd;
bd.type = e_staticBody;
b3Body* b = m_world.CreateBody(bd);
b3CapsuleShape capsuleShape;
capsuleShape.m_centers[0].Set(0.0f, 0.0f, -5.0f);
capsuleShape.m_centers[1].Set(0.0f, 0.0f, 5.0f);
capsuleShape.m_radius = 1.0f;;
b3HullShape hullShape;
hullShape.m_hull = &m_groundHull;
hullShape.m_radius = 0.0f;;
b3ShapeDef sd;
sd.shape = &capsuleShape;
sd.shape = &hullShape;
sd.friction = 1.0f;
b->CreateShape(sd);
b3Shape* s = b->CreateShape(sd);
b3ClothWorldShapeDef csd;
csd.shape = s;
m_cloth->CreateWorldShape(csd);
}
m_clothDragger = new b3ClothDragger(&m_ray, m_cloth);
@ -66,6 +146,10 @@ public:
~ClothSelfCollision()
{
b3Free(m_clothMesh.vertices);
b3Free(m_clothMesh.triangles);
b3Free(m_clothMesh.meshes);
delete m_cloth;
delete m_clothDragger;
}
@ -83,17 +167,27 @@ public:
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
g_draw->DrawString(b3Color_white, "S - Turn on/off self collision");
if (m_cloth->IsSelfCollisionEnabled())
{
g_draw->DrawString(b3Color_white, "Self collision enabled");
}
else
{
g_draw->DrawString(b3Color_white, "Self collision disabled");
}
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
float32 E = m_cloth->GetEnergy();
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
@ -127,12 +221,20 @@ public:
}
}
void KeyDown(int key)
{
if (key == GLFW_KEY_S)
{
m_cloth->EnableSelfCollision(!m_cloth->IsSelfCollisionEnabled());
}
}
static Test* Create()
{
return new ClothSelfCollision();
}
b3GridClothMesh<10, 10> m_clothMesh;
b3ClothMesh m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
};

View File

@ -0,0 +1,571 @@
/*
* 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 CLOTH_TEARING_H
#define CLOTH_TEARING_H
class ClothTearing : public Test
{
public:
enum
{
e_w = 10,
e_h = 10
};
ClothTearing()
{
g_camera->m_zoom = 20.0f;
b3GridClothMesh<e_w, e_h> m;
b3ClothParticle** particles = (b3ClothParticle * *)b3Alloc(m.vertexCount * sizeof(b3ClothParticle*));
for (u32 i = 0; i < m.vertexCount; ++i)
{
b3ClothParticleDef pd;
pd.type = e_dynamicClothParticle;
pd.position = m.vertices[i];
b3ClothParticle* p = m_cloth.CreateParticle(pd);
particles[i] = p;
b3ClothSphereShapeDef sd;
sd.p = p;
sd.radius = 0.2f;
sd.friction = 0.4f;
m_cloth.CreateSphereShape(sd);
}
for (u32 i = 0; i < m.triangleCount; ++i)
{
u32 v1 = m.triangles[i].v1;
u32 v2 = m.triangles[i].v2;
u32 v3 = m.triangles[i].v3;
b3ClothParticle* p1 = particles[v1];
b3ClothParticle* p2 = particles[v2];
b3ClothParticle* p3 = particles[v3];
b3ClothTriangleShapeDef tsd;
tsd.p1 = p1;
tsd.p2 = p2;
tsd.p3 = p3;
tsd.v1 = m.vertices[v1];
tsd.v2 = m.vertices[v2];
tsd.v3 = m.vertices[v3];
tsd.density = 0.1f;
m_cloth.CreateTriangleShape(tsd);
{
b3SpringForceDef sfd;
sfd.Initialize(p1, p2, 1000.0f, 10.0f);
CreateSpringForce(sfd);
}
{
b3SpringForceDef sfd;
sfd.Initialize(p2, p3, 1000.0f, 10.0f);
CreateSpringForce(sfd);
}
{
b3SpringForceDef sfd;
sfd.Initialize(p3, p1, 1000.0f, 10.0f);
CreateSpringForce(sfd);
}
}
for (u32 i = 0; i < e_w + 1; ++i)
{
u32 vertex = m.GetVertex(0, i);
particles[vertex]->SetType(e_staticClothParticle);
}
b3Free(particles);
m_cloth.SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_clothDragger = new b3ClothDragger(&m_ray, &m_cloth);
m_clothDragger->SetStaticDrag(false);
}
~ClothTearing()
{
delete m_clothDragger;
}
b3SpringForce* FindSpringForce(b3ClothParticle* p1, b3ClothParticle* p2)
{
for (b3Force* f = m_cloth.GetForceList().m_head; f; f = f->GetNext())
{
if (f->GetType() != e_springForce)
{
continue;
}
b3SpringForce* sf = (b3SpringForce*)f;
b3ClothParticle* sp1 = sf->GetParticle1();
b3ClothParticle* sp2 = sf->GetParticle2();
if (sp1 == p1 && sp2 == p2)
{
return sf;
}
if (sp1 == p2 && sp2 == p1)
{
return sf;
}
}
return nullptr;
}
b3SpringForce* CreateSpringForce(const b3SpringForceDef& def)
{
b3SpringForce* sf = FindSpringForce(def.p1, def.p2);
if (sf != nullptr)
{
return sf;
}
return (b3SpringForce*)m_cloth.CreateForce(def);
}
void DrawSpringForces()
{
for (b3Force* f = m_cloth.GetForceList().m_head; f; f = f->GetNext())
{
if (f->GetType() != e_springForce)
{
continue;
}
b3SpringForce* s = (b3SpringForce*)f;
b3ClothParticle* p1 = s->GetParticle1();
b3ClothParticle* p2 = s->GetParticle2();
g_draw->DrawSegment(p1->GetPosition(), p2->GetPosition(), b3Color_black);
}
}
void Partition(b3ClothParticle* p, const b3Plane& plane,
b3Array<b3ClothTriangleShape*>& above,
b3Array<b3ClothTriangleShape*>& below)
{
for (b3ClothTriangleShape* t = m_cloth.GetTriangleShapeList().m_head; t; t = t->GetNext())
{
b3ClothParticle* p1 = t->GetParticle1();
b3ClothParticle* p2 = t->GetParticle2();
b3ClothParticle* p3 = t->GetParticle3();
if (p1 != p && p2 != p && p3 != p)
{
continue;
}
b3Vec3 x1 = p1->GetPosition();
b3Vec3 x2 = p2->GetPosition();
b3Vec3 x3 = p3->GetPosition();
b3Vec3 center = (x1 + x2 + x3) / 3.0f;
scalar distance = b3Distance(center, plane);
if (distance > 0.0f)
{
above.PushBack(t);
}
else
{
below.PushBack(t);
}
}
}
bool HasSpring(const b3Array<b3ClothTriangleShape*>& triangles,
b3ClothParticle* pOld, b3ClothParticle* pOther)
{
for (u32 i = 0; i < triangles.Count(); ++i)
{
b3ClothTriangleShape* triangle = triangles[i];
b3ClothParticle* tp1 = triangle->GetParticle1();
b3ClothParticle* tp2 = triangle->GetParticle2();
b3ClothParticle* tp3 = triangle->GetParticle3();
// 1, 2
if (tp1 == pOld && tp2 == pOther)
{
return true;
}
// 2, 1
if (tp2 == pOld && tp1 == pOther)
{
return true;
}
// 2, 3
if (tp2 == pOld && tp3 == pOther)
{
return true;
}
// 3, 2
if (tp3 == pOld && tp2 == pOther)
{
return true;
}
// 3, 1
if (tp3 == pOld && tp1 == pOther)
{
return true;
}
// 1, 3
if (tp1 == pOld && tp3 == pOther)
{
return true;
}
}
return false;
}
bool SplitParticle(b3ClothParticle* pOld, const b3Plane& plane)
{
// Collect triangles.
b3StackArray<b3ClothTriangleShape*, 32> trianglesAbove, trianglesBelow;
Partition(pOld, plane, trianglesAbove, trianglesBelow);
// There must be at least one triangle on each side of the plane.
if (trianglesAbove.Count() == 0 || trianglesBelow.Count() == 0)
{
return false;
}
b3ClothParticleDef pdNew;
pdNew.type = pOld->GetType();
pdNew.position = pOld->GetPosition() - 0.2f * plane.normal;
b3ClothParticle* pNew = m_cloth.CreateParticle(pdNew);
b3ClothSphereShapeDef ssdNew;
ssdNew.p = pNew;
ssdNew.radius = 0.2f;
ssdNew.friction = 0.4f;
m_cloth.CreateSphereShape(ssdNew);
for (u32 i = 0; i < trianglesBelow.Count(); ++i)
{
b3ClothTriangleShape* triangle = trianglesBelow[i];
b3ClothParticle* p1 = triangle->GetParticle1();
b3ClothParticle* p2 = triangle->GetParticle2();
b3ClothParticle* p3 = triangle->GetParticle3();
m_cloth.DestroyTriangleShape(triangle);
if (p1 == pOld)
{
b3ClothTriangleShapeDef tdNew;
tdNew.p1 = pNew;
tdNew.p2 = p2;
tdNew.p3 = p3;
tdNew.v1 = pNew->GetPosition();
tdNew.v2 = p2->GetPosition();
tdNew.v3 = p3->GetPosition();
m_cloth.CreateTriangleShape(tdNew);
b3SpringForce* sf1 = FindSpringForce(p1, p2);
if (sf1)
{
b3SpringForceDef sNew;
sNew.p1 = pNew;
sNew.p2 = p2;
sNew.restLength = sf1->GetRestLenght();
sNew.structural = sf1->GetStructuralStiffness();
sNew.damping = sf1->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p1, p2) == false)
{
m_cloth.DestroyForce(sf1);
}
}
b3SpringForce* sf2 = FindSpringForce(p3, p1);
if (sf2)
{
b3SpringForceDef sNew;
sNew.p1 = p3;
sNew.p2 = pNew;
sNew.restLength = sf2->GetRestLenght();
sNew.structural = sf2->GetStructuralStiffness();
sNew.damping = sf2->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p3, p1) == false)
{
m_cloth.DestroyForce(sf2);
}
}
}
if (p2 == pOld)
{
b3ClothTriangleShapeDef tdNew;
tdNew.p1 = p1;
tdNew.p2 = pNew;
tdNew.p3 = p3;
tdNew.v1 = p1->GetPosition();
tdNew.v2 = pNew->GetPosition();
tdNew.v3 = p3->GetPosition();
m_cloth.CreateTriangleShape(tdNew);
b3SpringForce* sf1 = FindSpringForce(p1, p2);
if (sf1)
{
b3SpringForceDef sNew;
sNew.p1 = p1;
sNew.p2 = pNew;
sNew.restLength = sf1->GetRestLenght();
sNew.structural = sf1->GetStructuralStiffness();
sNew.damping = sf1->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p1, p2) == false)
{
m_cloth.DestroyForce(sf1);
}
}
b3SpringForce* sf2 = FindSpringForce(p2, p3);
if (sf2)
{
b3SpringForceDef sNew;
sNew.p1 = pNew;
sNew.p2 = p3;
sNew.restLength = sf2->GetRestLenght();
sNew.structural = sf2->GetStructuralStiffness();
sNew.damping = sf2->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p2, p3) == false)
{
m_cloth.DestroyForce(sf2);
}
}
}
if (p3 == pOld)
{
b3ClothTriangleShapeDef tdNew;
tdNew.p1 = p1;
tdNew.p2 = p2;
tdNew.p3 = pNew;
tdNew.v1 = p1->GetPosition();
tdNew.v2 = p2->GetPosition();
tdNew.v3 = pNew->GetPosition();
m_cloth.CreateTriangleShape(tdNew);
b3SpringForce* sf1 = FindSpringForce(p2, p3);
if (sf1)
{
b3SpringForceDef sNew;
sNew.p1 = p2;
sNew.p2 = pNew;
sNew.restLength = sf1->GetRestLenght();
sNew.structural = sf1->GetStructuralStiffness();
sNew.damping = sf1->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p2, p3) == false)
{
m_cloth.DestroyForce(sf1);
}
}
b3SpringForce* sf2 = FindSpringForce(p3, p1);
if (sf2)
{
b3SpringForceDef sNew;
sNew.p1 = pNew;
sNew.p2 = p1;
sNew.restLength = sf2->GetRestLenght();
sNew.structural = sf2->GetStructuralStiffness();
sNew.damping = sf2->GetDampingStiffness();
m_cloth.CreateForce(sNew);
if (HasSpring(trianglesAbove, p3, p1) == false)
{
m_cloth.DestroyForce(sf2);
}
}
}
}
return true;
}
bool Tear()
{
b3Force* f = m_cloth.GetForceList().m_head;
while (f)
{
if (f->GetType() != e_springForce)
{
f = f->GetNext();
continue;
}
b3SpringForce* s = (b3SpringForce*)f;
f = f->GetNext();
b3Vec3 tension = s->GetActionForce();
const scalar kMaxTension = 1000.0f;
if (b3LengthSquared(tension) <= kMaxTension * kMaxTension)
{
continue;
}
b3ClothParticle* p1 = s->GetParticle1();
b3ClothParticle* p2 = s->GetParticle2();
b3Vec3 x1 = p1->GetPosition();
b3Vec3 x2 = p2->GetPosition();
if (p1->GetType() == e_dynamicClothParticle)
{
b3Vec3 n = b3Normalize(x2 - x1);
b3Plane plane(n, x1);
bool wasSplit = SplitParticle(p1, plane);
if (wasSplit)
{
return true;
}
}
if (p2->GetType() == e_dynamicClothParticle)
{
b3Vec3 n = b3Normalize(x1 - x2);
b3Plane plane(n, x2);
bool wasSplit = SplitParticle(p2, plane);
if (wasSplit)
{
return true;
}
}
}
return false;
}
void Step()
{
Test::Step();
m_cloth.Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
while (Tear());
m_cloth.Draw();
DrawSpringForces();
if (m_clothDragger->IsDragging())
{
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
scalar E = m_cloth.GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->Drag();
}
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_clothDragger->IsDragging() == false)
{
m_clothDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_clothDragger->IsDragging() == true)
{
m_clothDragger->StopDragging();
}
}
static Test* Create()
{
return new ClothTearing();
}
b3Cloth m_cloth;
b3ClothDragger* m_clothDragger;
};
#endif

View File

@ -38,9 +38,9 @@ public:
{
for (u32 i = 0; i < e_count; ++i)
{
float32 x = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 y = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 z = 3.0f * RandomFloat(-1.0f, 1.0f);
scalar x = 3.0f * RandomFloat(-1.0f, 1.0f);
scalar y = 3.0f * RandomFloat(-1.0f, 1.0f);
scalar z = 3.0f * RandomFloat(-1.0f, 1.0f);
b3Vec3 p(x, y, z);
m_points[i] = p;
@ -48,9 +48,9 @@ public:
for (u32 i = 0; i < B3_MAX_MANIFOLDS; ++i)
{
float32 r = RandomFloat(0.0f, 1.0f);
float32 g = RandomFloat(0.0f, 1.0f);
float32 b = RandomFloat(0.0f, 1.0f);
scalar r = RandomFloat(0.0f, 1.0f);
scalar g = RandomFloat(0.0f, 1.0f);
scalar b = RandomFloat(0.0f, 1.0f);
b3Color c(r, g, b);
m_colors[i] = c;

View File

@ -68,46 +68,43 @@ public:
{
if (key == GLFW_KEY_LEFT)
{
m_xfB.position.x -= 0.05f;
m_xfB.translation.x -= 0.05f;
}
if (key == GLFW_KEY_RIGHT)
{
m_xfB.position.x += 0.05f;
m_xfB.translation.x += 0.05f;
}
if (key == GLFW_KEY_UP)
{
m_xfB.position.y += 0.05f;
m_xfB.translation.y += 0.05f;
}
if (key == GLFW_KEY_DOWN)
{
m_xfB.position.y -= 0.05f;
m_xfB.translation.y -= 0.05f;
}
if (key == GLFW_KEY_X)
{
b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfx = b3QuatMat33(qx);
b3Quat qx = b3QuatRotationX(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfx;
m_xfB.rotation = m_xfB.rotation * qx;
}
if (key == GLFW_KEY_Y)
{
b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfy = b3QuatMat33(qy);
b3Quat qy = b3QuatRotationY(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfy;
m_xfB.rotation = m_xfB.rotation * qy;
}
if (key == GLFW_KEY_Z)
{
b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI);
b3Mat33 xfz = b3QuatMat33(qy);
b3Quat qz = b3QuatRotationZ(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfz;
m_xfB.rotation = m_xfB.rotation * qz;
}
}

View File

@ -38,38 +38,33 @@ public:
}
{
b3Transform xf;
xf.SetIdentity();
xf.position.Set(-5.0f, 10.0f, 0.0f);
m_box1.SetTransform(xf);
m_box1.SetExtents(1.0f, 1.0f, 1.0f);
b3Vec3 translation(-5.0f, 10.0f, 0.0f);
m_box1.Translate(translation);
}
{
b3Transform xf;
xf.SetIdentity();
xf.position.Set(5.0f, 10.0f, 0.0f);
m_box2.SetTransform(xf);
b3Vec3 translation(5.0f, 10.0f, 0.0f);
m_box2.SetExtents(1.0f, 1.0f, 1.0f);
m_box2.Translate(translation);
}
{
b3Transform xf;
xf.SetIdentity();
xf.position.Set(0.0f, 2.0f, 0.0f);
m_box3.SetTransform(xf);
b3Vec3 translation(0.0f, 2.0f, 0.0f);
m_box3.SetExtents(1.0f, 1.0f, 1.0f);
m_box3.Translate(translation);
}
{
b3Transform xf;
xf.SetIdentity();
xf.position.Set(0.0f, 6.0f, 0.0f);
m_box4.SetTransform(xf);
b3Vec3 translation(0.0f, 6.0f, 0.0f);
m_box4.SetExtents(1.0f, 1.0f, 1.0f);
m_box4.Translate(translation);
}
{
b3Transform xf;
xf.SetIdentity();
xf.position.Set(0.0f, 10.0f, 0.0f);
m_box5.SetTransform(xf);
b3Vec3 translation(0.0f, 10.0f, 0.0f);
m_box5.SetExtents(1.0f, 1.0f, 1.0f);
m_box5.Translate(translation);
}
{

View File

@ -42,8 +42,8 @@ public:
head = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 0.15f, 0.0f);
cs.m_centers[1].Set(0.0f, -0.15f, 0.0f);
cs.m_vertex1.Set(0.0f, 0.15f, 0.0f);
cs.m_vertex2.Set(0.0f, -0.15f, 0.0f);
cs.m_radius = 0.5f;
b3ShapeDef sd;
@ -55,19 +55,22 @@ public:
{
b3Vec3 anchor(0.0f, 0.0f, 0.0f);
b3Vec3 axis(0.0f, 1.0f, 0.0f);
float32 coneAngle = 0.5f * B3_PI;
scalar coneAngle = 0.5f * B3_PI;
b3ConeJointDef cd;
cd.Initialize(ref, head, axis, anchor, coneAngle);
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.enableTwistLimit = true;
cd.lowerAngle = 0.0f;
cd.upperAngle = B3_PI;
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}
// Invalidate the orientation
b3Vec3 axis(1.0f, 0.0f, 0.0f);
float32 angle = B3_PI;
head->SetTransform(head->GetPosition(), axis, angle);
b3Quat q = b3QuatRotationX(B3_PI);
head->SetTransform(head->GetPosition(), q);
}
static Test* Create()

View File

@ -0,0 +1,282 @@
/*
* 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 CONVEX_CAST_H
#define CONVEX_CAST_H
class ConvexCast : public Test
{
public:
ConvexCast()
{
{
b3BodyDef bdef;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(0.0f, 2.0f, 0.0f);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
m_shape = body->CreateShape(sdef);
}
{
m_grid.BuildTree();
m_grid.BuildAdjacency();
b3BodyDef bdef;
bdef.position.Set(-10.0f, 5.0f, -2.0f);
bdef.orientation = b3QuatRotationZ(0.25f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3MeshShape hs;
hs.m_mesh = &m_grid;
hs.m_scale.Set(-1.0f, -1.0f, -2.0f);
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(0.0f, 2.0f, 10.0f);
bdef.orientation = b3QuatRotationY(0.25f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(-10.0f, 6.0f, -10.0f);
bdef.orientation = b3QuatRotationY(0.25f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
static b3BoxHull boxHull(2.0f, 4.0f, 0.5f);
b3HullShape hs;
hs.m_hull = &boxHull;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(10.0f, 2.0f, 0.0f);
bdef.orientation = b3QuatRotationY(0.20f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(-10.0f, 2.0f, 14.0f);
bdef.orientation = b3QuatRotationY(0.05f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(-14.0f, 2.0f, 5.0f);
bdef.orientation = b3QuatRotationY(-0.05f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(20.0f, 2.0f, 5.0f);
bdef.orientation = b3QuatRotationY(-0.05f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(12.0f, 2.0f, 5.0f);
bdef.orientation = b3QuatRotationY(-0.35f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
b3SphereShape hs;
hs.m_center.SetZero();
hs.m_radius = 2.5f;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
{
b3BodyDef bdef;
bdef.position.Set(0.0f, 1.0f, -12.0f);
b3Body* body = m_world.CreateBody(bdef);
b3CapsuleShape hs;
hs.m_vertex1.Set(0.0f, 1.0f, 0.0f);
hs.m_vertex2.Set(0.0f, -1.0f, 0.0f);
hs.m_radius = 3.0f;
b3ShapeDef sdef;
sdef.shape = &hs;
b3Shape* shape = body->CreateShape(sdef);
}
m_d.Set(-50.0f, 2.0f, 0.0f);
}
void CastConvex() const
{
class ConvexCastFilter : public b3ConvexCastFilter
{
public:
bool ShouldConvexCast(b3Shape* shape)
{
return true;
}
};
ConvexCastFilter filter;
b3Body* body = m_shape->GetBody();
b3Transform xf = body->GetTransform();
m_world.DrawSolidShape(xf, m_shape, b3Color_red);
b3Vec3 p1 = xf.translation;
b3Vec3 p2 = p1 + m_d;
b3ConvexCastSingleOutput out;
if (m_world.ConvexCastSingle(&out, &filter, m_shape, m_d))
{
g_draw->DrawPoint(out.point, 4.0f, b3Color_red);
g_draw->DrawSegment(out.point, out.point + out.normal, b3Color_white);
b3Transform xft;
xft.rotation = xf.rotation;
xft.translation = xf.translation + out.fraction * m_d;
m_world.DrawShape(xft, m_shape, b3Color_red);
g_draw->DrawSegment(p1, xft.translation, b3Color_green);
}
else
{
g_draw->DrawSegment(p1, p2, b3Color_green);
b3Transform xf1;
xf1.rotation = xf.rotation;
xf1.translation = xf.translation + m_d;
m_world.DrawShape(xf1, m_shape, b3Color_red);
}
}
void Step()
{
scalar dt = g_testSettings->inv_hertz;
b3Quat q = b3QuatRotationY(0.05f * B3_PI * dt);
m_d = b3Mul(q, m_d);
CastConvex();
Test::Step();
}
static Test* Create()
{
return new ConvexCast();
}
b3GridMesh<5, 5> m_grid;
b3Shape* m_shape;
b3Vec3 m_d;
};
#endif

View File

@ -66,9 +66,9 @@ public:
m_count = 0;
for (u32 i = 0; i < e_count; ++i)
{
float32 x = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 y = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 z = 3.0f * RandomFloat(-1.0f, 1.0f);
float x = 3.0f * RandomFloat(-1.0f, 1.0f);
float y = 3.0f * RandomFloat(-1.0f, 1.0f);
float z = 3.0f * RandomFloat(-1.0f, 1.0f);
// Clamp to force coplanarities.
// This will stress the convex hull creation code.
@ -135,7 +135,7 @@ public:
edge = m_hull.GetEdge(edge->next);
} while (edge != begin);
c /= float32(vn);
c /= scalar(vn);
g_draw->DrawSegment(c, c + n, b3Color_white);
}

View File

@ -0,0 +1,119 @@
/*
* 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 CONVEYOR_BELT_H
#define CONVEYOR_BELT_H
class ConveyorBelt : public Test
{
public:
ConveyorBelt()
{
{
// Ground
b3BodyDef bd;
b3Body* body = m_world.CreateBody(bd);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &hs;
body->CreateShape(sd);
}
{
// Platform
b3BodyDef bd;
bd.position.Set(0.0f, 5.0f, 0.0f);
b3Body* body = m_world.CreateBody(bd);
m_platformHull.SetExtents(10.0f, 0.5f, 2.0f);
b3HullShape hs;
hs.m_hull = &m_platformHull;
b3ShapeDef sd;
sd.shape = &hs;
sd.friction = 0.8f;
m_platform = body->CreateShape(sd);
}
// Boxes
m_boxHull.SetExtents(0.5f, 0.5f, 0.5f);
for (u32 i = 0; i < 5; ++i)
{
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(2.0f * i, 7.0f, 0.0f);
b3Body* body = m_world.CreateBody(bd);
b3HullShape hs;
hs.m_hull = &m_boxHull;
b3ShapeDef sd;
sd.shape = &hs;
sd.density = 0.2f;
body->CreateShape(sd);
}
}
void PreSolve(b3Contact* contact)
{
Test::PreSolve(contact);
b3Shape* shapeA = contact->GetShapeA();
b3Shape* shapeB = contact->GetShapeB();
if (shapeA == m_platform)
{
for (u32 i = 0; i < contact->GetManifoldCount(); ++i)
{
b3Manifold* manifold = contact->GetManifold(i);
manifold->motorSpeed = 0.25f * B3_PI;
manifold->tangentSpeed2 = -2.0f;
}
}
if (shapeB == m_platform)
{
for (u32 i = 0; i < contact->GetManifoldCount(); ++i)
{
b3Manifold* manifold = contact->GetManifold(i);
manifold->motorSpeed = -0.25f * B3_PI;
manifold->tangentSpeed2 = 2.0f;
}
}
}
static Test* Create()
{
return new ConveyorBelt();
}
b3BoxHull m_platformHull;
b3Shape* m_platform;
b3BoxHull m_boxHull;
};
#endif

View File

@ -24,23 +24,17 @@ class DeepCapsule : public Collide
public:
DeepCapsule()
{
m_xfA.position.Set(0.0f, 0.0f, 0.0f);
m_xfA.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.55f * B3_PI));
m_sA.m_centers[0].Set(1.0f, -1.0f, 0.0f);
m_sA.m_centers[1].Set(0.0f, 1.0f, 0.0f);
m_sA.m_radius = 2.0f;
m_box.SetExtents(4.0f, 1.0f, 4.0f);
m_sA.m_hull = &m_box;
m_xfB.position.Set(0.f, 0.0f, 0.0f);
m_xfB.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.0f * B3_PI));
m_xfA.SetIdentity();
b3Transform xf;
xf.SetIdentity();
xf.rotation = b3Diagonal(4.0f, 1.0f, 4.0f);
m_sB.m_vertex1.Set(1.0f, -1.0f, 0.0f);
m_sB.m_vertex2.Set(0.0f, 1.0f, 0.0f);
m_sB.m_radius = 2.0f;
m_box.SetTransform(xf);
m_sB.m_hull = &m_box;
m_xfB.translation.Set(0.0f, 0.0f, 0.0f);
m_xfB.rotation = b3QuatRotationZ(0.55f * B3_PI);
m_shapeA = &m_sA;
m_shapeB = &m_sB;
@ -52,8 +46,8 @@ public:
return new DeepCapsule();
}
b3CapsuleShape m_sA;
b3HullShape m_sB;
b3HullShape m_sA;
b3CapsuleShape m_sB;
b3BoxHull m_box;
};

View File

@ -24,15 +24,11 @@ class Distance : public Test
public:
Distance()
{
m_xfA.SetIdentity();
m_xfA.position.Set(-5.0f, 0.0f, 0.0f);
m_xfA.translation.Set(-5.0f, 0.0f, 0.0f);
m_xfA.rotation.SetIdentity();
m_shapeA.m_centers[0].Set(0.0f, -2.0f, 0.0f);
m_shapeA.m_centers[1].Set(0.0f, 2.0f, 0.0f);
m_shapeA.m_radius = 1.0f;
m_shapeA.m_hull = &b3BoxHull_identity;
m_xfB.SetIdentity();
m_xfB.position.Set(5.0f, 0.0f, 0.0f);
m_xfB.translation.Set(5.0f, 0.0f, 0.0f);
m_xfB.rotation.SetIdentity();
m_shapeB.m_hull = &b3BoxHull_identity;
@ -79,46 +75,43 @@ public:
{
if (key == GLFW_KEY_LEFT)
{
m_xfB.position.x -= 0.05f;
m_xfB.translation.x -= 0.05f;
}
if (key == GLFW_KEY_RIGHT)
{
m_xfB.position.x += 0.05f;
m_xfB.translation.x += 0.05f;
}
if (key == GLFW_KEY_UP)
{
m_xfB.position.y += 0.05f;
m_xfB.translation.y += 0.05f;
}
if (key == GLFW_KEY_DOWN)
{
m_xfB.position.y -= 0.05f;
m_xfB.translation.y -= 0.05f;
}
if (key == GLFW_KEY_X)
{
b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfx = b3QuatMat33(qx);
b3Quat qx = b3QuatRotationX(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfx;
m_xfB.rotation = m_xfB.rotation * qx;
}
if (key == GLFW_KEY_Y)
{
b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfy = b3QuatMat33(qy);
b3Quat qy = b3QuatRotationY(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfy;
m_xfB.rotation = m_xfB.rotation * qy;
}
if (key == GLFW_KEY_Z)
{
b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI);
b3Mat33 xfz = b3QuatMat33(qy);
b3Quat qz = b3QuatRotationZ(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * xfz;
m_xfB.rotation = m_xfB.rotation * qz;
}
}
@ -127,7 +120,7 @@ public:
return new Distance();
}
b3CapsuleShape m_shapeA;
b3HullShape m_shapeA;
b3Transform m_xfA;
b3ShapeGJKProxy m_proxyA;

View File

@ -40,14 +40,14 @@ public:
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.orientation.Set(b3Vec3(1.0f, 0.0f, 0.0f), 0.5f * B3_PI);
bdef.orientation.SetAxisAngle(b3Vec3(1.0f, 0.0f, 0.0f), 0.5f * B3_PI);
bdef.position.Set(0.0f, 10.0f, 0.0f);
bdef.angularVelocity.Set(0.0f, 0.0f, 4.0f * B3_PI);
b3Body* body = m_world.CreateBody(bdef);
{
m_rotorBox.Set(1.0f, 0.5f, 7.0f);
m_rotorBox.SetExtents(1.0f, 0.5f, 7.0f);
b3HullShape hull;
hull.m_hull = &m_rotorBox;
@ -60,7 +60,7 @@ public:
}
{
m_cylinderHull.SetAsCylinder(0.95f, 4.0f);
m_cylinderHull.SetExtents(0.95f, 4.0f);
b3HullShape hull;
hull.m_hull = &m_cylinderHull;
@ -86,7 +86,7 @@ public:
}
b3BoxHull m_rotorBox;
b3QHull m_cylinderHull;
b3CylinderHull m_cylinderHull;
};
#endif

View File

@ -24,16 +24,10 @@ class HingeChain : public Test
public:
HingeChain()
{
static b3BoxHull doorHull;
{
b3Transform xf;
xf.position.SetZero();
xf.rotation = b3Diagonal(2.0f, 4.0f, 0.5f);
doorHull.SetTransform(xf);
}
static b3BoxHull box(2.0f, 4.0f, 0.5f);
float32 x = -50.0f;
float32 y = 0.0f;
scalar x = -50.0f;
scalar y = 0.0f;
b3Body* lastHinge;
{
@ -42,7 +36,7 @@ public:
lastHinge = m_world.CreateBody(bd);
b3HullShape hull;
hull.m_hull = &doorHull;
hull.m_hull = &box;
b3ShapeDef sdef;
sdef.shape = &hull;
@ -60,7 +54,7 @@ public:
b3Body* hinge = m_world.CreateBody(bd);
b3HullShape hull;
hull.m_hull = &doorHull;
hull.m_hull = &box;
b3ShapeDef sdef;
sdef.shape = &hull;

View File

@ -29,7 +29,7 @@ public:
HullCollision()
{
m_xfA.position.Set(0.0f, 1.5f, 0.0f);
m_xfA.translation.Set(0.0f, 1.5f, 0.0f);
m_xfA.rotation.SetIdentity();
m_xfB.SetIdentity();
@ -53,9 +53,9 @@ public:
{
for (u32 i = 0; i < e_count; ++i)
{
float32 x = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 y = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 z = 3.0f * RandomFloat(-1.0f, 1.0f);
float x = 3.0f * RandomFloat(-1.0f, 1.0f);
float y = 3.0f * RandomFloat(-1.0f, 1.0f);
float z = 3.0f * RandomFloat(-1.0f, 1.0f);
x = b3Clamp(x, -2.5f, 2.5f);
y = b3Clamp(y, -2.5f, 2.5f);
@ -68,9 +68,9 @@ public:
for (u32 i = 0; i < e_count; ++i)
{
float32 x = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 y = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 z = 3.0f * RandomFloat(-1.0f, 1.0f);
float x = 3.0f * RandomFloat(-1.0f, 1.0f);
float y = 3.0f * RandomFloat(-1.0f, 1.0f);
float z = 3.0f * RandomFloat(-1.0f, 1.0f);
x = b3Clamp(x, -2.5f, 2.5f);
y = b3Clamp(y, -2.5f, 2.5f);
@ -98,7 +98,7 @@ public:
sB.m_hull = &hull2;
m_shapeB = &sB;
g_draw->DrawString(b3Color_white, "G - Generate a random convex hull pair");
g_draw->DrawString(b3Color_white, "G - Generate random convex hulls");
Collide::Step();
}

View File

@ -53,9 +53,9 @@ public:
{
// Clamp to force coplanarities.
// This will stress the generation code.
float32 x = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 y = 3.0f * RandomFloat(-1.0f, 1.0f);
float32 z = 3.0f * RandomFloat(-1.0f, 1.0f);
float x = 3.0f * RandomFloat(-1.0f, 1.0f);
float y = 3.0f * RandomFloat(-1.0f, 1.0f);
float z = 3.0f * RandomFloat(-1.0f, 1.0f);
x = b3Clamp(x, -1.5f, 1.5f);
y = b3Clamp(y, -1.5f, 1.5f);

View File

@ -38,14 +38,7 @@ public:
}
b3Vec3 boxScale(1.0f, 0.5f, 2.0f);
static b3BoxHull boxHull;
b3Transform m;
m.rotation = b3Diagonal(boxScale.x, boxScale.y, boxScale.z);
m.position.SetZero();
boxHull.SetTransform(m);
static b3BoxHull boxHull(boxScale.x, boxScale.y, boxScale.z);
{
b3BodyDef bd;
@ -70,8 +63,8 @@ public:
bd.type = e_dynamicBody;
bd.position.Set(0.0f, 1.5f, 0.0f);
b3Quat q_y(b3Vec3(0.0f, 1.0f, 0.0f), 0.4f * B3_PI);
b3Quat q_z(b3Vec3(0.0f, 0.0f, 1.0f), 0.04f * B3_PI);
b3Quat q_y = b3QuatRotationY(0.4f * B3_PI);
b3Quat q_z = b3QuatRotationZ(0.04f * B3_PI);
b3Quat q = q_z * q_y;
bd.orientation = q;

View File

@ -45,15 +45,9 @@ public:
b3Vec3 boxScale(1.0f, 0.5f, 3.0f);
static b3BoxHull boxHull;
static b3BoxHull boxHull(boxScale.x, boxScale.y, boxScale.z);
b3Transform m;
m.rotation = b3Diagonal(boxScale.x, boxScale.y, boxScale.z);
m.position.SetZero();
boxHull.SetTransform(m);
float32 y = 2.0f;
scalar y = 2.0f;
for (u32 i = 0; i < e_layerCount / 2; ++i)
{
@ -62,7 +56,7 @@ public:
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
bd.position.x = 2.0f * float32(j) * boxScale.x;
bd.position.x = 2.0f * scalar(j) * boxScale.x;
bd.position.y = y;
bd.position.z = 0.0f;
@ -86,11 +80,11 @@ public:
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
bd.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.5f * B3_PI);
bd.orientation = b3QuatRotationY(0.5f * B3_PI);
bd.position.x = 2.0f * boxScale.x;
bd.position.y = y;
bd.position.z = -2.0f * boxScale.x + 2.0f * float32(j) * boxScale.x;
bd.position.z = -2.0f * boxScale.x + 2.0f * scalar(j) * boxScale.x;
b3Body* body = m_world.CreateBody(bd);

View File

@ -34,8 +34,8 @@ public:
m_body = m_world.CreateBody(bdef);
b3CapsuleShape shape;
shape.m_centers[0].Set(0.0f, 1.0f, 0.0f);
shape.m_centers[1].Set(0.0f, -1.0f, 0.0f);
shape.m_vertex1.Set(0.0f, 1.0f, 0.0f);
shape.m_vertex2.Set(0.0f, -1.0f, 0.0f);
shape.m_radius = 1.0f;
b3ShapeDef sdef;
@ -55,16 +55,11 @@ public:
{
Test::Step();
b3Vec3 q(0.0f, 0.0f, 0.0f);
b3Vec3 p = m_body->GetTransform().position;
if (b3Distance(p, q) > 50.0f)
b3Vec3 p(0.0f, 0.0f, 0.0f);
if (b3Distance(m_body->GetPosition(), p) > 50.0f)
{
b3Quat quat = m_body->GetSweep().orientation;
b3Vec3 axis;
float32 angle;
quat.GetAxisAngle(&axis, &angle);
m_body->SetTransform(q, axis, angle);
b3Quat q = m_body->GetOrientation();
m_body->SetTransform(p, q);
}
}

View File

@ -0,0 +1,171 @@
/*
* 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 LINEAR_TIME_OF_IMPACT_H
#define LINEAR_TIME_OF_IMPACT_H
class LinearTimeOfImpact : public Test
{
public:
LinearTimeOfImpact()
{
m_shapeA.m_hull = &b3BoxHull_identity;
m_shapeA.m_radius = 0.0f;
m_shapeB.m_hull = &b3BoxHull_identity;
m_shapeB.m_radius = 0.0f;
m_xfA.translation.Set(0.0f, 0.0f, 0.0f);
m_xfA.rotation.SetIdentity();
m_xfB.translation.Set(5.0f, 1.0f, 0.0f);
m_xfB.rotation.SetIdentity();
m_proxyA.Set(&m_shapeA, 0);
m_proxyB.Set(&m_shapeB, 0);
}
void Step()
{
b3Vec3 dA = b3Vec3_zero;
b3Vec3 dB(-10.0f, 0.0f, 0.0f);
b3TOIOutput out = b3TimeOfImpact(m_xfA, m_proxyA, dA, m_xfB, m_proxyB, dB);
b3TOIOutput::State state = out.state;
scalar t = out.t;
u32 iterations = out.iterations;
if (state == b3TOIOutput::e_touching)
{
b3Transform xfA;
xfA.rotation = m_xfA.rotation;
xfA.translation = m_xfA.translation + t * dA;
b3Transform xfB;
xfB.rotation = m_xfB.rotation;
xfB.translation = m_xfB.translation + t * dB;
b3GJKOutput query = b3GJK(xfA, m_proxyA, xfB, m_proxyB, false);
b3Vec3 p1 = query.point1;
b3Vec3 p2 = query.point2;
b3Vec3 n1 = b3Normalize(p2 - p1);
b3Vec3 p = 0.5f * (p1 + p2);
g_draw->DrawPoint(p, 4.0f, b3Color_green);
g_draw->DrawSegment(p1, p1 + n1, b3Color_green);
m_world.DrawShape(xfA, &m_shapeA, b3Color_black);
m_world.DrawShape(xfB, &m_shapeB, b3Color_black);
}
if (state == b3TOIOutput::e_failed)
{
g_draw->DrawString(b3Color_white, "State = Failed");
}
else if (state == b3TOIOutput::e_overlapped)
{
g_draw->DrawString(b3Color_white, "State = Overlapped");
}
else if (state == b3TOIOutput::e_separated)
{
g_draw->DrawString(b3Color_white, "State = Separated!");
}
else if (state == b3TOIOutput::e_touching)
{
g_draw->DrawString(b3Color_white, "State = Touching!");
}
g_draw->DrawString(b3Color_white, "Iterations = %d", out.iterations);
g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow - Translate shape");
g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape");
g_draw->DrawTransform(m_xfA);
g_draw->DrawTransform(m_xfB);
m_world.DrawShape(m_xfA, &m_shapeA, b3Color_black);
m_world.DrawShape(m_xfB, &m_shapeB, b3Color_black);
m_world.DrawSolidShape(m_xfA, &m_shapeA, b3Color_white);
m_world.DrawSolidShape(m_xfB, &m_shapeB, b3Color_white);
g_draw->DrawSegment(m_xfA.translation, m_xfA.translation + dA, b3Color_white);
g_draw->DrawSegment(m_xfB.translation, m_xfB.translation + dB, b3Color_white);
}
void KeyDown(int key)
{
if (key == GLFW_KEY_LEFT)
{
m_xfB.translation.x -= 0.105f;
}
if (key == GLFW_KEY_RIGHT)
{
m_xfB.translation.x += 0.105f;
}
if (key == GLFW_KEY_UP)
{
m_xfB.translation.y += 0.105f;
}
if (key == GLFW_KEY_DOWN)
{
m_xfB.translation.y -= 0.105f;
}
if (key == GLFW_KEY_X)
{
b3Quat qx = b3QuatRotationX(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * qx;
}
if (key == GLFW_KEY_Y)
{
b3Quat qy = b3QuatRotationY(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * qy;
}
if (key == GLFW_KEY_Z)
{
b3Quat qz = b3QuatRotationZ(0.05f * B3_PI);
m_xfB.rotation = m_xfB.rotation * qz;
}
}
static Test* Create()
{
return new LinearTimeOfImpact();
}
b3HullShape m_shapeA;
b3Transform m_xfA;
b3ShapeGJKProxy m_proxyA;
b3HullShape m_shapeB;
b3Transform m_xfB;
b3ShapeGJKProxy m_proxyB;
};
#endif

View File

@ -25,6 +25,7 @@ public:
MeshContactTest()
{
m_gridMesh.BuildTree();
m_gridMesh.BuildAdjacency();
// Transform grid into a terrain
for (u32 i = 0; i < m_terrainMesh.vertexCount; ++i)
@ -33,18 +34,22 @@ public:
}
m_terrainMesh.BuildTree();
m_terrainMesh.BuildAdjacency();
{
b3BodyDef bd;
m_ground = m_world.CreateBody(bd);
b3Body* groundBody = m_world.CreateBody(bd);
b3MeshShape ms;
ms.m_mesh = &m_gridMesh;
ms.m_scale.Set(2.0f, 1.0f, 2.0f);
b3ShapeDef sd;
sd.shape = &ms;
m_ground->CreateShape(sd);
m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd);
m_selection = m_groundShape->m_mesh->triangleCount / 2;
}
{
@ -52,8 +57,8 @@ public:
bd.type = b3BodyType::e_dynamicBody;
bd.position.Set(0.0f, 5.0f, 0.0f);
m_body = m_world.CreateBody(bd);
b3Body* body = m_world.CreateBody(bd);
{
b3SphereShape sphere;
sphere.m_center.SetZero();
@ -64,25 +69,43 @@ public:
sd.density = 1.0f;
sd.friction = 0.5f;
m_body->CreateShape(sd);
m_bodyShape = body->CreateShape(sd);
}
}
m_drawEdgeTypes = true;
}
void KeyDown(int key)
{
u32 minSelection = 0;
if (key == GLFW_KEY_LEFT)
{
m_selection = m_selection == minSelection ? minSelection : m_selection - 1;
}
u32 maxSelection = m_groundShape->m_mesh->triangleCount - 1;
if (key == GLFW_KEY_RIGHT)
{
m_selection = m_selection == maxSelection ? maxSelection : m_selection + 1;
}
if (key == GLFW_KEY_E)
{
m_drawEdgeTypes = !m_drawEdgeTypes;
}
if (key == GLFW_KEY_S || key == GLFW_KEY_C || key == GLFW_KEY_H)
{
if (m_body)
{
m_world.DestroyBody(m_body);
}
b3Body* body = m_bodyShape->GetBody();
m_world.DestroyBody(body);
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
bd.position.Set(0.0f, 5.0f, 0.0f);
m_body = m_world.CreateBody(bd);
body = m_world.CreateBody(bd);
if (key == GLFW_KEY_S)
{
@ -95,14 +118,14 @@ public:
sd.density = 1.0f;
sd.friction = 0.5f;
m_body->CreateShape(sd);
m_bodyShape = body->CreateShape(sd);
}
if (key == GLFW_KEY_C)
{
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, -1.0f, 0.0f);
capsule.m_centers[1].Set(0.0f, 1.0f, 0.0f);
capsule.m_vertex1.Set(0.0f, -1.0f, 0.0f);
capsule.m_vertex2.Set(0.0f, 1.0f, 0.0f);
capsule.m_radius = 1.0f;
b3ShapeDef sd;
@ -110,7 +133,7 @@ public:
sd.density = 1.0f;
sd.friction = 0.5f;
m_body->CreateShape(sd);
m_bodyShape = body->CreateShape(sd);
}
if (key == GLFW_KEY_H)
@ -123,41 +146,43 @@ public:
sd.density = 1.0f;
sd.friction = 0.5f;
m_body->CreateShape(sd);
m_bodyShape = body->CreateShape(sd);
}
}
if (key == GLFW_KEY_G || key == GLFW_KEY_T)
{
if (m_ground)
{
m_world.DestroyBody(m_ground);
}
b3Body* groundBody = m_groundShape->GetBody();
m_world.DestroyBody(groundBody);
b3BodyDef bd;
m_ground = m_world.CreateBody(bd);
groundBody = m_world.CreateBody(bd);
if (key == GLFW_KEY_G)
{
b3MeshShape ms;
ms.m_mesh = &m_gridMesh;
ms.m_scale.Set(2.0f, 1.0f, 2.0f);
b3ShapeDef sd;
sd.shape = &ms;
m_ground->CreateShape(sd);
m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd);
}
if (key == GLFW_KEY_T)
{
b3MeshShape ms;
ms.m_mesh = &m_terrainMesh;
ms.m_scale.Set(2.0f, 1.5f, 2.0f);
b3ShapeDef sd;
sd.shape = &ms;
m_ground->CreateShape(sd);
m_groundShape = (b3MeshShape*)groundBody->CreateShape(sd);
}
m_selection = m_groundShape->m_mesh->triangleCount / 2;
}
}
@ -165,6 +190,108 @@ public:
{
Test::Step();
const b3Mesh* mesh = m_groundShape->m_mesh;
b3Vec3 scale = m_groundShape->m_scale;
b3Body* body = m_groundShape->GetBody();
b3Transform xf = body->GetTransform();
{
const b3MeshTriangle* triangle = mesh->triangles + m_selection;
const b3MeshTriangleWings* triangleWings = mesh->triangleWings + m_selection;
for (u32 i = 0; i < 3; ++i)
{
u32 j = i + 1 < 3 ? i + 1 : 0;
u32 v1 = triangle->GetVertex(i);
u32 v2 = triangle->GetVertex(j);
b3Vec3 p1 = xf * b3MulCW(scale, mesh->vertices[v1]);
b3Vec3 p2 = xf * b3MulCW(scale, mesh->vertices[v2]);
b3Vec3 center = scalar(0.5) * (p1 + p2);
g_draw->DrawString(b3Color_white, center, "e%d", i);
u32 wingVertex = triangleWings->GetVertex(i);
if (wingVertex != B3_NULL_VERTEX)
{
b3Vec3 vertex = xf * b3MulCW(scale, mesh->vertices[wingVertex]);
g_draw->DrawString(b3Color_white, vertex, "u%d", i);
}
}
}
if (m_drawEdgeTypes)
{
b3Vec3 eyePoint(0.0f, 10.0f, 0.0f);
for (u32 i = 0; i < mesh->triangleCount; ++i)
{
b3MeshTriangle* triangle = mesh->triangles + i;
b3MeshTriangleWings* triangleWings = mesh->triangleWings + i;
b3Vec3 A = xf * b3MulCW(scale, mesh->vertices[triangle->v1]);
b3Vec3 B = xf * b3MulCW(scale, mesh->vertices[triangle->v2]);
b3Vec3 C = xf * b3MulCW(scale, mesh->vertices[triangle->v3]);
b3Vec3 N = b3Cross(B - A, C - A);
N.Normalize();
b3Plane plane(N, A);
if (b3Distance(eyePoint, plane) < 0.0f)
{
plane = b3Plane(-N, A);
}
for (u32 j = 0; j < 3; ++j)
{
u32 k = j + 1 < 3 ? j + 1 : 0;
u32 v1 = triangle->GetVertex(j);
u32 v2 = triangle->GetVertex(k);
u32 u = triangleWings->GetVertex(j);
b3Vec3 p1 = xf * b3MulCW(scale, mesh->vertices[v1]);
b3Vec3 p2 = xf * b3MulCW(scale, mesh->vertices[v2]);
b3Vec3 center = scalar(0.5) * (p1 + p2);
if (u == B3_NULL_VERTEX)
{
g_draw->DrawPoint(center, scalar(4), b3Color_white);
continue;
}
b3Vec3 wingVertex = xf * b3MulCW(scale, mesh->vertices[u]);
scalar d = b3Distance(wingVertex, plane);
const scalar kCoplanarTol = 0.005f;
if (d < -kCoplanarTol)
{
// Below <=> Convex
g_draw->DrawPoint(center, scalar(4), b3Color_green);
}
else if (d > kCoplanarTol)
{
// Above <=> Concave
g_draw->DrawPoint(center, scalar(4), b3Color_yellow);
}
else
{
// d > -e && d < e
// On <=> Coplanar
g_draw->DrawPoint(center, scalar(4), b3Color_red);
}
}
}
}
g_draw->DrawString(b3Color_white, "E - View Edge Types");
g_draw->DrawString(b3Color_white, "Arrows - Select Face Wings");
g_draw->DrawString(b3Color_white, "S - Sphere");
g_draw->DrawString(b3Color_white, "C - Capsule");
g_draw->DrawString(b3Color_white, "H - Hull");
@ -177,11 +304,14 @@ public:
return new MeshContactTest();
}
bool m_drawEdgeTypes;
u32 m_selection;
b3GridMesh<25, 25> m_terrainMesh;
b3GridMesh<25, 25> m_gridMesh;
b3Body* m_ground;
b3Body* m_body;
b3MeshShape* m_groundShape;
b3Shape* m_bodyShape;
};
#endif

View File

@ -0,0 +1,123 @@
/*
* 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 MOTOR_TEST_H
#define MOTOR_TEST_H
class MotorTest : public Test
{
public:
MotorTest()
{
b3Body* ground = nullptr;
{
// Ground
b3BodyDef bd;
ground = m_world.CreateBody(bd);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &hs;
ground->CreateShape(sd);
}
{
// Motorized body
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(0.0f, 8.0f, 0.0f);
b3Body* body = m_world.CreateBody(bd);
m_boxHull.SetExtents(2.0f, 0.5f, 0.5f);
b3HullShape shape;
shape.m_hull = &m_boxHull;
b3ShapeDef sd;
sd.shape = &shape;
sd.friction = 0.3f;
sd.density = 2.0f;
body->CreateShape(sd);
b3MotorJointDef mjd;
mjd.Initialize(ground, body);
mjd.maxForce = 1000.0f;
mjd.maxTorque = 1000.0f;
m_joint = (b3MotorJoint*)m_world.CreateJoint(mjd);
}
m_play = false;
m_x = 0.0f;
}
void KeyDown(int key)
{
if (key == GLFW_KEY_S)
{
m_play = !m_play;
}
}
void Step()
{
if (m_play)
{
m_x += g_testSettings->inv_hertz;
if (m_x >= 2.0f * B3_PI)
{
m_x = 0.0f;
}
}
b3Vec3 linearOffset;
linearOffset.x = 8.0f * sinf(2.0f * m_x);
linearOffset.y = 8.0f + sinf(m_x);
linearOffset.z = 0.0f;
m_joint->SetLinearOffset(linearOffset);
b3Quat angularOffset;
angularOffset.SetAxisAngle(b3Vec3_z, m_x);
angularOffset.Normalize();
m_joint->SetAngularOffset(angularOffset);
Test::Step();
g_draw->DrawPoint(linearOffset, 4.0f, b3Color(0.9f, 0.9f, 0.9f));
g_draw->DrawString(b3Color_white, "S - Play/Pause");
}
static Test* Create()
{
return new MotorTest();
}
b3BoxHull m_boxHull;
b3MotorJoint* m_joint;
bool m_play;
scalar m_x;
};
#endif

View File

@ -39,8 +39,8 @@ public:
bs[1] = m_world.CreateBody(bd);
b3CapsuleShape s;
s.m_centers[0].Set(0.5f, 0.0f, 0.0f);
s.m_centers[1].Set(-0.5f, 0.0f, 0.0f);
s.m_vertex1.Set(0.5f, 0.0f, 0.0f);
s.m_vertex2.Set(-0.5f, 0.0f, 0.0f);
s.m_radius = 0.05f;
b3ShapeDef sd;
@ -60,8 +60,8 @@ public:
bs[2] = m_world.CreateBody(bd);
b3CapsuleShape s;
s.m_centers[0].Set(0.5f, 0.0f, 0.0f);
s.m_centers[1].Set(-0.5f, 0.0f, 0.0f);
s.m_vertex1.Set(0.5f, 0.0f, 0.0f);
s.m_vertex2.Set(-0.5f, 0.0f, 0.0f);
s.m_radius = 0.05f;
b3ShapeDef sd;
@ -81,8 +81,8 @@ public:
bs[3] = m_world.CreateBody(bd);
b3CapsuleShape s;
s.m_centers[0].Set(0.5f, 0.0f, 0.0f);
s.m_centers[1].Set(-0.5f, 0.0f, 0.0f);
s.m_vertex1.Set(0.5f, 0.0f, 0.0f);
s.m_vertex2.Set(-0.5f, 0.0f, 0.0f);
s.m_radius = 0.05f;
b3ShapeDef sd;
@ -102,8 +102,8 @@ public:
bs[4] = m_world.CreateBody(bd);
b3CapsuleShape s;
s.m_centers[0].Set(0.5f, 0.0f, 0.0f);
s.m_centers[1].Set(-0.5f, 0.0f, 0.0f);
s.m_vertex1.Set(0.5f, 0.0f, 0.0f);
s.m_vertex2.Set(-0.5f, 0.0f, 0.0f);
s.m_radius = 0.05f;
b3ShapeDef sd;
@ -123,8 +123,8 @@ public:
bs[5] = m_world.CreateBody(bd);
b3CapsuleShape s;
s.m_centers[0].Set(0.5f, 0.0f, 0.0f);
s.m_centers[1].Set(-0.5f, 0.0f, 0.0f);
s.m_vertex1.Set(0.5f, 0.0f, 0.0f);
s.m_vertex2.Set(-0.5f, 0.0f, 0.0f);
s.m_radius = 0.05f;
b3ShapeDef sd;

View File

@ -38,15 +38,15 @@ public:
}
b3CapsuleShape edge;
edge.m_centers[0].Set(0.0f, -10.0f, 0.0f);
edge.m_centers[1].Set(0.0f, 10.0f, 0.0f);
edge.m_vertex1.Set(0.0f, -10.0f, 0.0f);
edge.m_vertex2.Set(0.0f, 10.0f, 0.0f);
edge.m_radius = 0.5f;
b3Body* frame1, *frame2;
{
b3BodyDef bd;
bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bd.orientation = b3QuatRotationZ(0.5f * B3_PI);
bd.position.Set(0.0f, 10.0f, -5.0f);
frame1 = m_world.CreateBody(bd);
@ -59,7 +59,7 @@ public:
{
b3BodyDef bd;
bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bd.orientation = b3QuatRotationZ(0.5f * B3_PI);
bd.position.Set(0.0f, 10.0f, 5.0f);
frame2 = m_world.CreateBody(bd);

View File

@ -0,0 +1,222 @@
/*
* 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 NODE_TYPES_H
#define NODE_TYPES_H
class NodeTypes : public Test
{
public:
enum
{
e_w = 5,
e_h = 2,
e_d = 2
};
NodeTypes()
{
// Create soft body
b3SoftBodyDef def;
def.mesh = &m_mesh;
def.density = 0.2f;
def.E = 1000.0f;
def.nu = 0.33f;
def.radius = 0.2f;
def.friction = 0.6f;
m_body = new b3SoftBody(def);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
for (u32 i = 0; i < e_h + 1; ++i)
{
for (u32 k = 0; k < e_d + 1; ++k)
{
u32 v = m_mesh.GetVertex(i, 0, k);
b3SoftBodyNode* n = m_body->GetNode(v);
n->SetType(e_staticSoftBodyNode);
}
}
m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body);
}
~NodeTypes()
{
delete m_bodyDragger;
delete m_body;
}
void Step()
{
Test::Step();
if (m_bodyDragger->IsDragging())
{
m_bodyDragger->Drag();
}
m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_body->Draw();
if (m_bodyDragger->IsDragging())
{
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
g_draw->DrawString(b3Color_white, "S - Static");
g_draw->DrawString(b3Color_white, "D - Dynamic");
g_draw->DrawString(b3Color_white, "K - Kinematic");
g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position");
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_bodyDragger->IsDragging() == false)
{
m_bodyDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_bodyDragger->IsDragging() == true)
{
m_bodyDragger->StopDragging();
}
}
void SetBodyType(b3SoftBodyNodeType type)
{
for (u32 i = 0; i < e_h + 1; ++i)
{
for (u32 k = 0; k < e_d + 1; ++k)
{
u32 v = m_mesh.GetVertex(i, 0, k);
b3SoftBodyNode* n = m_body->GetNode(v);
n->SetType(type);
}
}
}
void KeyDown(int button)
{
if (button == GLFW_KEY_S)
{
SetBodyType(e_staticSoftBodyNode);
}
if (button == GLFW_KEY_K)
{
SetBodyType(e_kinematicSoftBodyNode);
}
if (button == GLFW_KEY_D)
{
SetBodyType(e_dynamicSoftBodyNode);
}
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
b3SoftBodyNode* n = m_body->GetNode(i);
b3Vec3 d;
d.SetZero();
if (button == GLFW_KEY_LEFT)
{
d.x = -1.0f;
}
if (button == GLFW_KEY_RIGHT)
{
d.x = 1.0f;
}
if (button == GLFW_KEY_UP)
{
d.y = 1.0f;
}
if (button == GLFW_KEY_DOWN)
{
d.y = -1.0f;
}
if (button == GLFW_KEY_LEFT ||
button == GLFW_KEY_RIGHT ||
button == GLFW_KEY_UP ||
button == GLFW_KEY_DOWN)
{
if (n->GetType() == e_staticSoftBodyNode)
{
n->ApplyTranslation(d);
}
if (n->GetType() == e_kinematicSoftBodyNode)
{
b3Vec3 v = n->GetVelocity();
v += 5.0f * d;
n->SetVelocity(v);
}
if (n->GetType() == e_dynamicSoftBodyNode)
{
b3Vec3 f = 100.0f * d;
n->ApplyForce(f);
}
}
}
}
static Test* Create()
{
return new NodeTypes();
}
b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh;
b3SoftBody* m_body;
b3SoftBodyDragger* m_bodyDragger;
};
#endif

View File

@ -36,10 +36,21 @@ public:
g_draw->DrawString(b3Color_white, "Arrows - Apply Force/Velocity/Position");
}
void SetClothType(b3ParticleType type)
void SetClothType(b3ClothParticleType type)
{
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 v = m_clothMesh.GetVertex(0, j);
b3ClothParticle* p = m_cloth->GetParticle(v);
p->SetType(type);
}
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 v = m_clothMesh.GetVertex(e_h, j);
b3ClothParticle* p = m_cloth->GetParticle(v);
p->SetType(type);
}
}
@ -48,20 +59,20 @@ public:
{
if (button == GLFW_KEY_S)
{
SetClothType(e_staticParticle);
SetClothType(e_staticClothParticle);
}
if (button == GLFW_KEY_K)
{
SetClothType(e_kinematicParticle);
SetClothType(e_kinematicClothParticle);
}
if (button == GLFW_KEY_D)
{
SetClothType(e_dynamicParticle);
SetClothType(e_dynamicClothParticle);
}
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
for (b3ClothParticle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
{
b3Vec3 d;
d.SetZero();
@ -91,12 +102,12 @@ public:
button == GLFW_KEY_UP ||
button == GLFW_KEY_DOWN)
{
if (p->GetType() == e_staticParticle)
if (p->GetType() == e_staticClothParticle)
{
p->ApplyTranslation(d);
}
if (p->GetType() == e_kinematicParticle)
if (p->GetType() == e_kinematicClothParticle)
{
b3Vec3 v = p->GetVelocity();
@ -105,7 +116,7 @@ public:
p->SetVelocity(v);
}
if (p->GetType() == e_dynamicParticle)
if (p->GetType() == e_dynamicClothParticle)
{
b3Vec3 f = 100.0f * d;

View File

@ -22,6 +22,12 @@
class PinnedCloth : public Test
{
public:
enum
{
e_w = 10,
e_h = 10
};
PinnedCloth()
{
// Create cloth
@ -33,30 +39,24 @@ public:
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_cloth->SetWorld(&m_world);
// Freeze some particles
b3AABB3 aabb1;
aabb1.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb1.m_upper.Set(5.0f, 1.0f, -4.0f);
b3AABB3 aabb2;
aabb2.m_lower.Set(-5.0f, -1.0f, 4.0f);
aabb2.m_upper.Set(5.0f, 1.0f, 6.0f);
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
for (u32 j = 0; j < e_w + 1; ++j)
{
if (aabb1.Contains(p->GetPosition()))
{
p->SetType(e_staticParticle);
}
u32 v = m_clothMesh.GetVertex(0, j);
if (aabb2.Contains(p->GetPosition()))
{
p->SetType(e_staticParticle);
}
b3ClothParticle* p = m_cloth->GetParticle(v);
p->SetType(e_staticClothParticle);
}
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 v = m_clothMesh.GetVertex(e_h, j);
b3ClothParticle* p = m_cloth->GetParticle(v);
p->SetType(e_staticClothParticle);
}
m_clothDragger = new b3ClothDragger(&m_ray, m_cloth);
}
@ -79,9 +79,9 @@ public:
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -89,7 +89,7 @@ public:
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
float32 E = m_cloth->GetEnergy();
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
@ -128,7 +128,7 @@ public:
return new PinnedCloth();
}
b3GridClothMesh<10, 10> m_clothMesh;
b3GridClothMesh<e_w, e_h> m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
};

View File

@ -19,14 +19,12 @@
#ifndef PINNED_SOFTBODY_H
#define PINNED_SOFTBODY_H
#include <testbed/framework/softbody_dragger.h>
class PinnedSoftBody : public Test
{
public:
PinnedSoftBody()
{
m_mesh.SetAsSphere(5.0f, 0);
m_mesh.SetAsSphere(4.0f, 0);
// Create soft body
b3SoftBodyDef def;
@ -37,20 +35,15 @@ public:
def.c_yield = 0.1f;
def.c_creep = 0.5f;
def.c_max = 1.0f;
def.massDamping = 0.2f;
m_body = new b3SoftBody(def);
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
b3SoftBodyNode* n = m_body->GetVertexNode(i);
n->SetMassDamping(0.2f);
}
u32 pinIndex = ~0;
float32 pinDot = -B3_MAX_FLOAT;
scalar pinDot = -B3_MAX_SCALAR;
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
float32 dot = b3Dot(m_mesh.vertices[i], b3Vec3_y);
scalar dot = b3Dot(m_mesh.vertices[i], b3Vec3_y);
if (dot > pinDot)
{
pinDot = dot;
@ -58,7 +51,7 @@ public:
}
}
b3SoftBodyNode* pinNode = m_body->GetVertexNode(pinIndex);
b3SoftBodyNode* pinNode = m_body->GetNode(pinIndex);
pinNode->SetType(e_staticSoftBodyNode);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
@ -91,9 +84,9 @@ public:
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -101,7 +94,7 @@ public:
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
float32 E = m_body->GetEnergy();
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}

View File

@ -0,0 +1,135 @@
/*
* 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 PRISMATIC_TEST_H
#define PRISMATIC_TEST_H
class PrismaticTest : public Test
{
public:
PrismaticTest()
{
{
b3BodyDef bd;
b3Body* ground = m_world.CreateBody(bd);
b3HullShape shape;
shape.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &shape;
ground->CreateShape(sd);
}
b3Body* bA, * bB;
{
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(-5.0f, 5.0f, 0.0f);
bA = m_world.CreateBody(bd);
m_hullA.SetExtents(2.0f, 2.0f, 0.5f);
b3HullShape hull;
hull.m_hull = &m_hullA;
b3ShapeDef sdef;
sdef.shape = &hull;
sdef.density = 1.0f;
bA->CreateShape(sdef);
}
{
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(5.0f, 5.0f, 0.0f);
bB = m_world.CreateBody(bd);
m_hullB.SetExtents(2.0f, 2.0f, 0.5f);
b3HullShape hull;
hull.m_hull = &m_hullB;
b3ShapeDef sdef;
sdef.shape = &hull;
sdef.density = 1.0f;
bB->CreateShape(sdef);
}
// Create prismatic joint
{
b3Vec3 anchor(0.0f, 5.0f, 0.0f);
b3Vec3 axis(1.0f, 0.0f, 0.0f);
b3PrismaticJointDef jd;
jd.Initialize(bA, bB, anchor, axis);
jd.motorSpeed = 10.0f;
jd.maxMotorForce = 10000.0f;
jd.enableMotor = true;
jd.lowerTranslation = 0.0f;
jd.upperTranslation = 10.0f;
jd.enableLimit = true;
m_joint = (b3PrismaticJoint*)m_world.CreateJoint(jd);
}
}
void Step()
{
Test::Step();
g_draw->DrawString(b3Color_white, "L - Enable Limit");
g_draw->DrawString(b3Color_white, "M - Enable Motor");
g_draw->DrawString(b3Color_white, "S - Flip Motor Speed");
}
void KeyDown(int button)
{
if (button == GLFW_KEY_L)
{
m_joint->EnableLimit(!m_joint->IsLimitEnabled());
}
if (button == GLFW_KEY_M)
{
m_joint->EnableMotor(!m_joint->IsMotorEnabled());
}
if (button == GLFW_KEY_S)
{
m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed());
}
}
static Test* Create()
{
return new PrismaticTest();
}
b3BoxHull m_hullA;
b3BoxHull m_hullB;
b3PrismaticJoint* m_joint;
};
#endif

View File

@ -47,9 +47,9 @@ public:
// shift to ground center
b3Vec3 translation;
translation.x = -0.5f * float32(e_count) * boxSize.x;
translation.x = -0.5f * scalar(e_count) * boxSize.x;
translation.y = 1.5f * boxSize.y;
translation.z = -0.5f * float32(e_count) * boxSize.z;
translation.z = -0.5f * scalar(e_count) * boxSize.z;
u32 count = e_count;
for (u32 i = 0; i < e_count; ++i)
@ -61,9 +61,9 @@ public:
{
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
bd.position.x = 1.05f * float32(j) * boxSize.x;
bd.position.x = 1.05f * scalar(j) * boxSize.x;
bd.position.y = 0.0f;
bd.position.z = 1.05f * float32(k) * boxSize.z;
bd.position.z = 1.05f * scalar(k) * boxSize.z;
bd.position += translation;
b3Body* body = m_world.CreateBody(bd);

View File

@ -48,15 +48,15 @@ public:
// shift to ground center
b3Vec3 translation;
translation.x = -0.5f * float32(e_count - 1) * 4.0f * boxSize.x;
translation.x = -0.5f * scalar(e_count - 1) * 4.0f * boxSize.x;
translation.y = 1.5f * boxSize.y;
translation.z = -0.5f * float32(e_depthCount) * boxSize.z;
translation.z = -0.5f * scalar(e_depthCount) * boxSize.z;
for (u32 i = 0; i < e_count; ++i)
{
// reset
translation.y = 1.5f * boxSize.y;
translation.z = -0.5f * float32(e_depthCount) * boxSize.z;
translation.z = -0.5f * scalar(e_depthCount) * boxSize.z;
for (u32 j = 0; j < e_depthCount; ++j)
{
@ -66,7 +66,7 @@ public:
bd.type = e_dynamicBody;
bd.position.x = 0.0f;
bd.position.y = 0.0f;
bd.position.z = 1.05f * float32(k) * boxSize.z;
bd.position.z = 1.05f * scalar(k) * boxSize.z;
bd.position += translation;
b3Body* body = m_world.CreateBody(bd);

View File

@ -64,8 +64,8 @@ public:
b3Body* body = m_world.CreateBody(bdef);
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, 0.0f, -1.0f);
capsule.m_centers[1].Set(0.0f, 0.0f, 1.0f);
capsule.m_vertex1.Set(0.0f, 0.0f, -1.0f);
capsule.m_vertex2.Set(0.0f, 0.0f, 1.0f);
capsule.m_radius = 1.0f;
b3ShapeDef sdef;
@ -83,7 +83,7 @@ public:
b3Body* body = m_world.CreateBody(bdef);
m_coneHull.SetAsCone();
m_coneHull.SetExtents(1.0f, 1.0f);
b3HullShape hull;
hull.m_hull = &m_coneHull;
@ -103,7 +103,7 @@ public:
b3Body* body = m_world.CreateBody(bdef);
m_cylinderHull.SetAsCylinder();
m_cylinderHull.SetExtents(1.0f, 1.0f);
b3HullShape hull;
hull.m_hull = &m_cylinderHull;
@ -126,8 +126,8 @@ public:
return new QuadricShapes();
}
b3QHull m_coneHull;
b3QHull m_cylinderHull;
b3ConeHull m_coneHull;
b3CylinderHull m_cylinderHull;
};
#endif

View File

@ -52,8 +52,8 @@ public:
hip->ApplyForceToCenter(b3Vec3(0.0f, 0.0f, -5000.0f), true);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 0.5f, 0.0f);
cs.m_centers[1].Set(0.0f, -0.5f, 0.0f);
cs.m_vertex1.Set(0.0f, 0.5f, 0.0f);
cs.m_vertex2.Set(0.0f, -0.5f, 0.0f);
cs.m_radius = 1.0f;
b3ShapeDef sd;
@ -70,8 +70,8 @@ public:
head = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 0.15f, 0.0f);
cs.m_centers[1].Set(0.0f, -0.15f, 0.0f);
cs.m_vertex1.Set(0.0f, 0.15f, 0.0f);
cs.m_vertex2.Set(0.0f, -0.15f, 0.0f);
cs.m_radius = 0.5f;
b3ShapeDef sd;
@ -86,7 +86,7 @@ public:
cd.bodyA = hip;
cd.bodyB = head;
cd.collideLinked = false;
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.Initialize(hip, head, b3Vec3(0.0f, 1.0f, 0.0f), b3Vec3(0.0f, 11.55f, 0.0f), 0.25f * B3_PI);
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}
@ -95,12 +95,12 @@ public:
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(-2.5f, 11.0f, 0.0f);
bd.orientation.Set(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bd.orientation = b3QuatRotationZ(0.5f * B3_PI);
lArm = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 1.0f, 0.0f);
cs.m_centers[1].Set(0.0f, -1.0f, 0.0f);
cs.m_vertex1.Set(0.0f, 1.0f, 0.0f);
cs.m_vertex2.Set(0.0f, -1.0f, 0.0f);
cs.m_radius = 0.5f;
b3ShapeDef sd;
@ -116,7 +116,7 @@ public:
cd.bodyA = hip;
cd.bodyB = lArm;
cd.collideLinked = false;
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.Initialize(hip, lArm, b3Vec3(-1.0f, 0.0f, 0.0f), b3Vec3(-1.0f, 11.0f, 0.0f), B3_PI);
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}
@ -125,12 +125,12 @@ public:
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.Set(2.5f, 11.0f, 0.0f);
bd.orientation.Set(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bd.orientation.SetAxisAngle(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
rArm = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 1.0f, 0.0f);
cs.m_centers[1].Set(0.0f, -1.0f, 0.0f);
cs.m_vertex1.Set(0.0f, 1.0f, 0.0f);
cs.m_vertex2.Set(0.0f, -1.0f, 0.0f);
cs.m_radius = 0.5f;
b3ShapeDef sd;
@ -146,7 +146,7 @@ public:
cd.bodyA = hip;
cd.bodyB = rArm;
cd.collideLinked = false;
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.Initialize(hip, rArm, b3Vec3(1.0f, 0.0f, 0.0f), b3Vec3(1.0f, 11.0f, 0.0f), B3_PI);
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}
@ -158,8 +158,8 @@ public:
lLeg = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 2.0f, 0.0f);
cs.m_centers[1].Set(0.0f, -2.0f, 0.0f);
cs.m_vertex1.Set(0.0f, 2.0f, 0.0f);
cs.m_vertex2.Set(0.0f, -2.0f, 0.0f);
cs.m_radius = 0.45f;
b3ShapeDef sd;
@ -175,7 +175,7 @@ public:
cd.bodyA = hip;
cd.bodyB = lLeg;
cd.collideLinked = false;
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.Initialize(hip, lLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(-0.5f, 8.5f, 0.0f), 0.25f * B3_PI);
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}
@ -187,8 +187,8 @@ public:
rLeg = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_centers[0].Set(0.0f, 2.0f, 0.0f);
cs.m_centers[1].Set(0.0f, -2.0f, 0.0f);
cs.m_vertex1.Set(0.0f, 2.0f, 0.0f);
cs.m_vertex2.Set(0.0f, -2.0f, 0.0f);
cs.m_radius = 0.45f;
b3ShapeDef sd;
@ -204,7 +204,7 @@ public:
cd.bodyA = hip;
cd.bodyB = rLeg;
cd.collideLinked = false;
cd.enableLimit = true;
cd.enableConeLimit = true;
cd.Initialize(hip, rLeg, b3Vec3(0.0f, -1.0f, 0.0f), b3Vec3(0.5f, 8.5f, 0.0f), 0.25f * B3_PI);
b3ConeJoint* cj = (b3ConeJoint*)m_world.CreateJoint(cd);
}

View File

@ -159,8 +159,8 @@ public:
b3Body* body = m_world.CreateBody(bdef);
b3CapsuleShape hs;
hs.m_centers[0].Set(0.0f, 1.0f, 0.0f);
hs.m_centers[1].Set(0.0f, -1.0f, 0.0f);
hs.m_vertex1.Set(0.0f, 1.0f, 0.0f);
hs.m_vertex2.Set(0.0f, -1.0f, 0.0f);
hs.m_radius = 3.0f;
b3ShapeDef sdef;
@ -175,11 +175,22 @@ public:
m_p12.Set(0.0f, 2.0f, 0.0f);
m_p22.Set(-50.0f, 2.0f, 0.0f);
}
void CastRay(const b3Vec3 p1, const b3Vec3 p2) const
{
class RayCastFilter : public b3RayCastFilter
{
public:
bool ShouldRayCast(b3Shape* shape)
{
return true;
}
};
RayCastFilter filter;
b3RayCastSingleOutput out;
if (m_world.RayCastSingle(&out, p1, p2))
if (m_world.RayCastSingle(&out, &filter, p1, p2))
{
g_draw->DrawSegment(p1, out.point, b3Color_green);
@ -194,7 +205,7 @@ public:
void Step()
{
float32 dt = g_testSettings->inv_hertz;
scalar dt = g_testSettings->inv_hertz;
b3Quat dq = b3QuatRotationY(0.05f * B3_PI * dt);
m_p1 = b3Mul(dq, m_p1);

View File

@ -16,13 +16,13 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef HINGE_MOTOR_H
#define HINGE_MOTOR_H
#ifndef REVOLUTE_TEST_H
#define REVOLUTE_TEST_H
class HingeMotor : public Test
class RevoluteTest : public Test
{
public:
HingeMotor()
RevoluteTest()
{
{
b3BodyDef bd;
@ -46,8 +46,8 @@ public:
hinge = m_world.CreateBody(bd);
b3CapsuleShape shape;
shape.m_centers[0].Set(0.0f, 0.0f, -4.0f);
shape.m_centers[1].Set(0.0f, 0.0f, 4.0f);
shape.m_vertex1.Set(0.0f, 0.0f, -4.0f);
shape.m_vertex2.Set(0.0f, 0.0f, 4.0f);
shape.m_radius = 0.5f;
b3ShapeDef sd;
@ -66,7 +66,7 @@ public:
door = m_world.CreateBody(bd);
m_doorBox.Set(1.0f, 0.5f, 4.0f);
m_doorBox.SetExtents(1.0f, 0.5f, 4.0f);
b3HullShape hull;
hull.m_hull = &m_doorBox;
@ -78,23 +78,34 @@ public:
door->CreateShape(sdef);
}
{
b3Vec3 axis(0.0f, 0.0f, 1.0f);
b3Vec3 anchor(0.0f, 7.0f, 0.0f);
b3RevoluteJointDef jd;
jd.Initialize(hinge, door, axis, anchor, 0.0f, B3_PI);
jd.Initialize(hinge, door, axis, anchor, -0.25f * B3_PI, 0.5f * B3_PI);
jd.maxMotorTorque = 1000.0f;
jd.enableMotor = false;
jd.enableLimit = true;
jd.motorSpeed = B3_PI;
jd.maxMotorTorque = door->GetMass() * 10000.0f;
jd.enableMotor = true;
m_rj = (b3RevoluteJoint*)m_world.CreateJoint(jd);
}
// Invalidate the orientation
b3Vec3 axis(1.0f, 0.0f, 0.0f);
float32 angle = B3_PI;
door->SetTransform(door->GetPosition(), axis, angle);
b3Quat q = b3QuatRotationX(B3_PI);
door->SetTransform(door->GetPosition(), q);
}
void Step()
{
Test::Step();
g_draw->DrawString(b3Color_white, "M - Motor");
g_draw->DrawString(b3Color_white, "L - Limits");
g_draw->DrawString(b3Color_white, "S/K/D - Static/kinematic/dynamic body");
}
void KeyDown(int button)
@ -127,7 +138,7 @@ public:
static Test* Create()
{
return new HingeMotor();
return new RevoluteTest();
}
b3BoxHull m_doorBox;

View File

@ -30,7 +30,7 @@ public:
Rope()
{
b3Vec3 vs[e_count];
float32 ms[e_count];
scalar ms[e_count];
vs[0].Set(0.0f, 0.0f, 0.0f);
ms[0] = 0.0f;
@ -38,7 +38,7 @@ public:
for (u32 i = 1; i < e_count; ++i)
{
ms[i] = 1.0f;
vs[i].Set(float32(i), 0.0f, 0.0f);
vs[i].Set(scalar(i), 0.0f, 0.0f);
}
b3RopeDef rd;

View File

@ -63,8 +63,8 @@ public:
m_character = m_world.CreateBody(bd);
b3CapsuleShape cap;
cap.m_centers[0].Set(0.0f, 2.0f, 0.0f);
cap.m_centers[1].Set(0.0f, -2.0f, 0.0f);
cap.m_vertex1.Set(0.0f, 2.0f, 0.0f);
cap.m_vertex2.Set(0.0f, -2.0f, 0.0f);
cap.m_radius = 0.5f;
b3ShapeDef sd;
@ -129,7 +129,7 @@ public:
bd.type = b3BodyType::e_dynamicBody;
bd.position.Set(RandomFloat(-20.0f, 20.0f), RandomFloat(10.0f, 20.0f), RandomFloat(-20.0f, 20.0f));
b3Vec3 n = m_character->GetTransform().position - bd.position;
b3Vec3 n = m_character->GetTransform().translation - bd.position;
n.Normalize();
bd.linearVelocity = 60.0f * n;

View File

@ -1,121 +0,0 @@
#ifndef SHAPE_CAST_H
#define SHAPE_CAST_H
class ShapeCast : public Test
{
public:
ShapeCast()
{
m_shapeA.m_hull = &b3BoxHull_identity;
m_shapeA.m_radius = 0.0f;
m_shapeB.m_hull = &b3BoxHull_identity;
m_shapeB.m_radius = 0.0f;
m_xfA.position.Set(-5.0f, 0.0f, 0.0f);
m_xfA.rotation.SetIdentity();
m_xfB.position.Set(10.0f, 0.0f, 0.0f);
m_xfB.rotation.SetIdentity();
m_proxyA.Set(&m_shapeA, 0);
m_proxyB.Set(&m_shapeB, 0);
}
void Step()
{
g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow - Translate shape");
g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape");
g_draw->DrawTransform(m_xfA);
g_draw->DrawTransform(m_xfB);
m_world.DrawShape(m_xfA, &m_shapeA, b3Color_black);
m_world.DrawShape(m_xfB, &m_shapeB, b3Color_black);
m_world.DrawSolidShape(m_xfA, &m_shapeA, b3Color_white);
m_world.DrawSolidShape(m_xfB, &m_shapeB, b3Color_white);
b3Vec3 translationB = -100.0f * b3Vec3_x;
g_draw->DrawSegment(m_xfB.position, m_xfB.position + translationB, b3Color_white);
b3GJKShapeCastOutput out;
bool hit = b3GJKShapeCast(&out, m_xfA, m_proxyA, m_xfB, m_proxyB, translationB);
g_draw->DrawString(b3Color_white, "Iterations = %d", out.iterations);
if (hit)
{
g_draw->DrawPoint(out.point, 4.0f, b3Color_green);
g_draw->DrawSegment(out.point, out.point + out.normal, b3Color_green);
b3Transform xfB;
xfB.rotation = m_xfB.rotation;
xfB.position = m_xfB.position + out.t * translationB;
m_world.DrawShape(xfB, &m_shapeB, b3Color_black);
}
}
void KeyDown(int key)
{
if (key == GLFW_KEY_LEFT)
{
m_xfB.position.x -= 0.105f;
}
if (key == GLFW_KEY_RIGHT)
{
m_xfB.position.x += 0.105f;
}
if (key == GLFW_KEY_UP)
{
m_xfB.position.y += 0.105f;
}
if (key == GLFW_KEY_DOWN)
{
m_xfB.position.y -= 0.105f;
}
if (key == GLFW_KEY_X)
{
b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfx = b3QuatMat33(qx);
m_xfB.rotation = m_xfB.rotation * xfx;
}
if (key == GLFW_KEY_Y)
{
b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI);
b3Mat33 xfy = b3QuatMat33(qy);
m_xfB.rotation = m_xfB.rotation * xfy;
}
if (key == GLFW_KEY_Z)
{
b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI);
b3Mat33 xfz = b3QuatMat33(qy);
m_xfB.rotation = m_xfB.rotation * xfz;
}
}
static Test* Create()
{
return new ShapeCast();
}
b3HullShape m_shapeA;
b3Transform m_xfA;
b3ShapeGJKProxy m_proxyA;
b3HullShape m_shapeB;
b3Transform m_xfB;
b3ShapeGJKProxy m_proxyB;
};
#endif

View File

@ -26,7 +26,6 @@ public:
{
{
b3BodyDef bd;
bd.orientation.Set(b3Vec3(0.0f, 1.0f, 0.0f), 0.18f * B3_PI);
b3Body* ground = m_world.CreateBody(bd);
b3MeshShape ms;
@ -39,7 +38,7 @@ public:
}
for (float32 y = 2.5f; y < 20.0f; y += 2.5f)
for (scalar y = 2.5f; y < 20.0f; y += 2.5f)
{
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
@ -59,18 +58,18 @@ public:
body->CreateShape(sdef);
}
for (float32 y = 2.5f; y < 20.0f; y += 2.5f)
for (scalar y = 2.5f; y < 20.0f; y += 2.5f)
{
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;
bd.position.Set(0.0f, y, 0.0f);
bd.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.5f * B3_PI);
bd.orientation = b3QuatRotationZ(0.5f * B3_PI);
b3Body* body = m_world.CreateBody(bd);
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, -1.0f, 0.0f);
capsule.m_centers[1].Set(0.0f, 1.0f, 0.0f);
capsule.m_vertex1.Set(0.0f, -1.0f, 0.0f);
capsule.m_vertex2.Set(0.0f, 1.0f, 0.0f);
capsule.m_radius = 1.0f;
b3ShapeDef sd;
@ -81,7 +80,7 @@ public:
body->CreateShape(sd);
}
for (float32 y = 2.5f; y < 20.0f; y += 2.5f)
for (scalar y = 2.5f; y < 20.0f; y += 2.5f)
{
b3BodyDef bd;
bd.type = b3BodyType::e_dynamicBody;

View File

@ -0,0 +1,136 @@
/*
* 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 SHEET_H
#define SHEET_H
class Sheet : public Test
{
public:
enum
{
e_w = 10,
e_h = 1,
e_d = 10
};
Sheet()
{
// Downscale the block along the y axis
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
m_mesh.vertices[i].y *= 0.5f;
}
// Create soft body
b3SoftBodyDef def;
def.mesh = &m_mesh;
def.density = 0.3f;
def.E = 200.0f;
def.nu = 0.3f;
m_body = new b3SoftBody(def);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
for (u32 j = 0; j < e_w + 1; ++j)
{
u32 v = m_mesh.GetVertex(0, j, 0);
b3SoftBodyNode* n = m_body->GetNode(v);
n->SetType(e_staticSoftBodyNode);
}
m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body);
}
~Sheet()
{
delete m_bodyDragger;
delete m_body;
}
void Step()
{
Test::Step();
if (m_bodyDragger->IsDragging())
{
m_bodyDragger->Drag();
}
m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_body->Draw();
if (m_bodyDragger->IsDragging())
{
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_bodyDragger->IsDragging() == false)
{
m_bodyDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_bodyDragger->IsDragging() == true)
{
m_bodyDragger->StopDragging();
}
}
static Test* Create()
{
return new Sheet();
}
b3BlockSoftBodyMesh<e_w, e_h, e_d> m_mesh;
b3SoftBody* m_body;
b3SoftBodyDragger* m_bodyDragger;
};
#endif

View File

@ -24,17 +24,15 @@ class SheetStack : public Test
public:
enum
{
e_rowCount = 1,
e_columnCount = 10,
e_depthCount = 1
e_h = 5,
e_w = 1,
e_d = 1
};
SheetStack()
{
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_staticBody;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
@ -44,49 +42,87 @@ public:
sdef.shape = &hs;
sdef.friction = 1.0f;
b3Shape* shape = body->CreateShape(sdef);
body->CreateShape(sdef);
}
static b3Vec3 sheetExtents(4.05f, 2.0f * B3_LINEAR_SLOP, 4.05f);
static b3BoxHull sheetHull(sheetExtents.x, sheetExtents.y, sheetExtents.z);
b3Vec3 stackOrigin;
stackOrigin.Set(0.0f, 4.05f, 0.0f);
b3Vec3 e(4.0f, 2.0f * B3_LINEAR_SLOP, 4.0f);
for (u32 i = 0; i < e_rowCount; ++i)
m_boxHull.SetExtents(e.x, e.y, e.z);
b3Vec3 separation;
separation.x = 1.0f;
separation.y = 1.0f;
separation.z = 1.0f;
b3Vec3 scale;
scale.x = 2.0f * e.x + separation.x;
scale.y = 2.0f * e.y + separation.y;
scale.z = 2.0f * e.z + separation.z;
b3Vec3 size;
size.x = 2.0f * e.x + scale.x * scalar(e_w - 1);
size.y = 2.0f * e.y + scale.y * scalar(e_h - 1);
size.z = 2.0f * e.z + scale.z * scalar(e_d - 1);
b3Vec3 translation;
translation.x = e.x - 0.5f * size.x;
translation.y = e.y - 0.5f * size.y;
translation.z = e.z - 0.5f * size.z;
translation.y += 9.0f;
for (u32 i = 0; i < e_h; ++i)
{
for (u32 j = 0; j < e_columnCount; ++j)
for (u32 j = 0; j < e_w; ++j)
{
for (u32 k = 0; k < e_depthCount; ++k)
for (u32 k = 0; k < e_d; ++k)
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_dynamicBody;
bdef.type = e_dynamicBody;
bdef.position.x = float32(i) * sheetExtents.x;
bdef.position.y = float32(j) * 50.0f * sheetExtents.y;
bdef.position.z = float32(k) * sheetExtents.z;
bdef.position += stackOrigin;
bdef.position.Set(scalar(j), scalar(i), scalar(k));
bdef.position.x *= scale.x;
bdef.position.y *= scale.y;
bdef.position.z *= scale.z;
bdef.position += translation;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &sheetHull;
hs.m_hull = &m_boxHull;
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &hs;
sdef.density = 0.5f;
sdef.friction = 0.2f;
body->CreateShape(sdef);
u32 bodyIndex = GetBodyIndex(i, j, k);
m_bodies[bodyIndex] = body;
}
}
}
}
u32 GetBodyIndex(u32 i, u32 j, u32 k)
{
B3_ASSERT(i < e_h);
B3_ASSERT(j < e_w);
B3_ASSERT(k < e_d);
return k + e_d * (j + e_w * i);
}
static Test* Create()
{
return new SheetStack();
}
b3BoxHull m_boxHull;
b3Body* m_bodies[e_h * e_w * e_d];
};
#endif

View File

@ -19,8 +19,6 @@
#ifndef SMASH_SOFTBODY_H
#define SMASH_SOFTBODY_H
#include <testbed/framework/softbody_dragger.h>
class SmashSoftBody : public Test
{
public:
@ -42,20 +40,13 @@ public:
def.c_yield = 0.6f;
def.c_creep = 1.0f;
def.c_max = 1.0f;
def.radius = 0.05f;
def.friction = 0.2f;
m_body = new b3SoftBody(def);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
m_body->SetWorld(&m_world);
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
b3SoftBodyNode* n = m_body->GetVertexNode(i);
n->SetRadius(0.05f);
n->SetFriction(0.2f);
}
// Create ground
{
@ -71,30 +62,14 @@ public:
sd.shape = &groundShape;
sd.friction = 0.3f;
b->CreateShape(sd);
b3Shape* s = b->CreateShape(sd);
b3SoftBodyWorldShapeDef ssd;
ssd.shape = s;
m_body->CreateWorldShape(ssd);
}
// Create body
{
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.y = 10.0f;
b3Body* b = m_world.CreateBody(bd);
static b3BoxHull boxHull(5.0f, 1.0f, 5.0f);
b3HullShape boxShape;
boxShape.m_hull = &boxHull;
b3ShapeDef sd;
sd.shape = &boxShape;
sd.density = 0.1f;
sd.friction = 0.3f;
b->CreateShape(sd);
}
m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body);
}
@ -122,9 +97,9 @@ public:
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -132,7 +107,7 @@ public:
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
float32 E = m_body->GetEnergy();
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}

View File

@ -0,0 +1,177 @@
/*
* 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 SOFTBODY_ANCHOR_H
#define SOFTBODY_ANCHOR_H
class SoftBodyAnchor : public Test
{
public:
SoftBodyAnchor()
{
m_mesh.SetAsSphere(4.0f, 0);
// Create soft body
b3SoftBodyDef def;
def.mesh = &m_mesh;
def.density = 0.2f;
def.E = 1000.0f;
def.nu = 0.33f;
def.c_yield = 0.1f;
def.c_creep = 0.5f;
def.c_max = 1.0f;
def.massDamping = 0.2f;
m_body = new b3SoftBody(def);
u32 pinIndex = ~0;
scalar pinDot = -B3_MAX_SCALAR;
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
scalar dot = b3Dot(m_mesh.vertices[i], b3Vec3_y);
if (dot > pinDot)
{
pinDot = dot;
pinIndex = i;
}
}
b3SoftBodyNode* pinNode = m_body->GetNode(pinIndex);
pinNode->SetType(e_staticSoftBodyNode);
u32 anchorIndex = ~0;
scalar anchorDot = -B3_MAX_SCALAR;
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
scalar dot = b3Dot(m_mesh.vertices[i], -b3Vec3_y);
if (dot > anchorDot)
{
anchorDot = dot;
anchorIndex = i;
}
}
b3SoftBodyNode* anchorNode = m_body->GetNode(anchorIndex);
{
b3BodyDef bd;
bd.type = e_dynamicBody;
bd.position.y = -10.0f;
b3Body* b = m_world.CreateBody(bd);
b3CapsuleShape cs;
cs.m_vertex1.Set(0.0f, -1.0f, 0.0f);
cs.m_vertex2.Set(0.0f, 1.0f, 0.0f);
cs.m_radius = 1.0f;
b3ShapeDef sd;
sd.shape = &cs;
sd.density = 0.1f;
m_shape = b->CreateShape(sd);
// Create anchor
b3SoftBodyAnchorDef ad;
ad.Initialize(b, anchorNode, anchorNode->GetPosition());
m_body->CreateAnchor(ad);
}
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body);
}
~SoftBodyAnchor()
{
delete m_bodyDragger;
delete m_body;
}
void Step()
{
Test::Step();
if (m_bodyDragger->IsDragging())
{
m_bodyDragger->Drag();
}
m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_body->Draw();
if (m_bodyDragger->IsDragging())
{
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_bodyDragger->IsDragging() == false)
{
m_bodyDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_bodyDragger->IsDragging() == true)
{
m_bodyDragger->StopDragging();
}
}
static Test* Create()
{
return new SoftBodyAnchor();
}
b3QSoftBodyMesh m_mesh;
b3SoftBody* m_body;
b3SoftBodyDragger* m_bodyDragger;
b3Shape* m_shape;
};
#endif

View File

@ -24,70 +24,103 @@ class SphereStack : public Test
public:
enum
{
e_rowCount = 1,
e_columnCount = 5,
e_depthCount = 1
e_h = 5,
e_w = 1,
e_d = 1
};
SphereStack()
{
{
b3BodyDef bd;
bd.type = e_staticBody;
b3Body* ground = m_world.CreateBody(bd);
b3BodyDef bdef;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &hs;
sd.density = 0.0f;
sd.friction = 1.0f;
sd.restitution = 0.0f;
b3Shape* groundShape = ground->CreateShape(sd);
b3ShapeDef sdef;
sdef.shape = &hs;
sdef.friction = 1.0f;
body->CreateShape(sdef);
}
b3Vec3 stackOrigin;
stackOrigin.Set(0.0f, 5.0f, 0.0f);
float32 radius = 1.0f;
float32 diameter = 2.0f * radius;
scalar e = 1.0f;
for (u32 i = 0; i < e_rowCount; ++i)
b3SphereShape sphere;
sphere.m_center.SetZero();
sphere.m_radius = e;
b3Vec3 separation;
separation.x = 1.0f;
separation.y = 1.0f;
separation.z = 1.0f;
b3Vec3 scale;
scale.x = 2.0f * e + separation.x;
scale.y = 2.0f * e + separation.y;
scale.z = 2.0f * e + separation.z;
b3Vec3 size;
size.x = 2.0f * e + scale.x * scalar(e_w - 1);
size.y = 2.0f * e + scale.y * scalar(e_h - 1);
size.z = 2.0f * e + scale.z * scalar(e_d - 1);
b3Vec3 translation;
translation.x = e - 0.5f * size.x;
translation.y = e - 0.5f * size.y;
translation.z = e - 0.5f * size.z;
translation.y += 9.0f;
for (u32 i = 0; i < e_h; ++i)
{
for (u32 j = 0; j < e_columnCount; ++j)
for (u32 j = 0; j < e_w; ++j)
{
for (u32 k = 0; k < e_depthCount; ++k)
for (u32 k = 0; k < e_d; ++k)
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_dynamicBody;
bdef.position.x = float32(i) * diameter;
bdef.position.y = float32(j) * diameter;
bdef.position.z = float32(k) * diameter;
bdef.position += stackOrigin;
bdef.linearVelocity.Set(0.0f, -50.0f, 0.0f);
bdef.type = e_dynamicBody;
bdef.position.Set(scalar(j), scalar(i), scalar(k));
bdef.position.x *= scale.x;
bdef.position.y *= scale.y;
bdef.position.z *= scale.z;
bdef.position += translation;
b3Body* body = m_world.CreateBody(bdef);
b3SphereShape sphere;
sphere.m_center.SetZero();
sphere.m_radius = radius;
b3ShapeDef sdef;
sdef.shape = &sphere;
sdef.density = 1.0f;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &sphere;
b3Shape* shape = body->CreateShape(sdef);
body->CreateShape(sdef);
u32 bodyIndex = GetBodyIndex(i, j, k);
m_bodies[bodyIndex] = body;
}
}
}
}
u32 GetBodyIndex(u32 i, u32 j, u32 k)
{
B3_ASSERT(i < e_h);
B3_ASSERT(j < e_w);
B3_ASSERT(k < e_d);
return k + e_d * (j + e_w * i);
}
static Test* Create()
{
return new SphereStack();
}
b3Body* m_bodies[e_h * e_w * e_d];
};
#endif
#endif

View File

@ -16,13 +16,13 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SPRING_H
#define SPRING_H
#ifndef SPRING_TEST_H
#define SPRING_TEST_H
class Spring : public Test
class SpringTest : public Test
{
public:
Spring()
SpringTest()
{
{
b3BodyDef bd;
@ -33,18 +33,12 @@ public:
b3ShapeDef sd;
sd.shape = &hs;
ground->CreateShape(sd);
}
// Car frame shape
{
b3Transform xf;
xf.SetIdentity();
xf.rotation = b3Diagonal(2.0f, 0.5f, 5.0f);
m_frameHull.SetTransform(xf);
}
// Car frame shape
m_frameHull.SetExtents(2.0f, 0.5f, 5.0f);
b3HullShape box;
box.m_hull = &m_frameHull;
@ -60,22 +54,22 @@ public:
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(0.0f, 10.0f, 0.0f);
frame = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &box;
frame->CreateShape(sdef);
}
b3Body* wheelLF;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(-1.0f, 7.0f, -4.5f);
bdef.position.Set(-1.0f, 7.0f, 4.5f);
bdef.fixedRotationY = true;
wheelLF = m_world.CreateBody(bdef);
@ -84,17 +78,17 @@ public:
sdef.shape = &sphere;
sdef.density = 0.1f;
sdef.friction = 1.0f;
wheelLF->CreateShape(sdef);
}
{
b3SpringJointDef def;
def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, -4.5), b3Vec3(-1.0f, 9.0f, -4.5f));
def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, 4.5), b3Vec3(-1.0f, 9.0f, 4.5f));
def.collideLinked = true;
def.dampingRatio = 0.5f;
def.frequencyHz = 4.0f;
m_world.CreateJoint(def);
}
@ -102,7 +96,7 @@ public:
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(1.0f, 7.0, -4.5f);
bdef.position.Set(1.0f, 7.0, 4.5f);
bdef.fixedRotationY = true;
wheelRF = m_world.CreateBody(bdef);
@ -111,25 +105,25 @@ public:
sdef.density = 0.1f;
sdef.friction = 1.0f;
sdef.shape = &sphere;
wheelRF->CreateShape(sdef);
}
{
b3SpringJointDef def;
def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, -4.5), b3Vec3(1.0f, 9.0, -4.5f));
def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, 4.5), b3Vec3(1.0f, 9.0, 4.5f));
def.collideLinked = true;
def.dampingRatio = 0.5f;
def.frequencyHz = 4.0f;
m_world.CreateJoint(def);
}
b3Body* wheelLB;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(-1.0f, 7.0f, 4.5f);
bdef.position.Set(-1.0f, 7.0f, -4.5f);
bdef.fixedRotationY = true;
wheelLB = m_world.CreateBody(bdef);
@ -144,7 +138,7 @@ public:
{
b3SpringJointDef def;
def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, 4.5f), b3Vec3(-1.0f, 9.0f, 4.5f));
def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, -4.5f), b3Vec3(-1.0f, 9.0f, -4.5f));
def.collideLinked = true;
def.dampingRatio = 0.8f;
def.frequencyHz = 4.0f;
@ -156,7 +150,7 @@ public:
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(1.0f, 7.0f, 4.5f);
bdef.position.Set(1.0f, 7.0f, -4.5f);
bdef.fixedRotationY = true;
wheelRB = m_world.CreateBody(bdef);
@ -171,7 +165,7 @@ public:
{
b3SpringJointDef def;
def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, 4.5f), b3Vec3(1.0f, 9.0f, 4.5f));
def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, -4.5f), b3Vec3(1.0f, 9.0f, -4.5f));
def.collideLinked = true;
def.frequencyHz = 4.0f;
def.dampingRatio = 0.8f;
@ -182,7 +176,7 @@ public:
static Test* Create()
{
return new Spring();
return new SpringTest();
}
b3BoxHull m_frameHull;

View File

@ -22,6 +22,12 @@
class TableCloth : public Test
{
public:
enum
{
e_w = 10,
e_h = 10
};
TableCloth()
{
// Translate the mesh
@ -35,15 +41,13 @@ public:
def.mesh = &m_clothMesh;
def.density = 0.2f;
def.streching = 10000.0f;
//def.shearing = 10000.0f;
def.damping = 100.0f;
def.strechDamping = 100.0f;
def.thickness = 0.2f;
def.friction = 0.1f;
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_cloth->SetWorld(&m_world);
{
b3BodyDef bd;
@ -51,7 +55,7 @@ public:
b3Body* b = m_world.CreateBody(bd);
m_tableHull.SetAsCylinder(5.0f, 2.0f);
m_tableHull.SetExtents(5.0f, 2.0f);
b3HullShape tableShape;
tableShape.m_hull = &m_tableHull;
@ -60,7 +64,12 @@ public:
sd.shape = &tableShape;
sd.friction = 1.0f;
b->CreateShape(sd);
b3Shape* shape = b->CreateShape(sd);
b3ClothWorldShapeDef csd;
csd.shape = shape;
m_cloth->CreateWorldShape(csd);
}
m_clothDragger = new b3ClothDragger(&m_ray, m_cloth);
@ -85,9 +94,9 @@ public:
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -95,7 +104,7 @@ public:
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
float32 E = m_cloth->GetEnergy();
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
@ -134,11 +143,11 @@ public:
return new TableCloth();
}
b3GridClothMesh<10, 10> m_clothMesh;
b3GridClothMesh<e_w, e_h> m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
b3QHull m_tableHull;
b3CylinderHull m_tableHull;
};
#endif

View File

@ -21,11 +21,11 @@
// Hot/Cold color map
// See http://paulbourke.net/miscellaneous/colourspace/
static inline b3Color Color(float32 x, float32 a, float32 b)
static inline b3Color Color(scalar x, scalar a, scalar b)
{
x = b3Clamp(x, a, b);
float32 d = b - a;
scalar d = b - a;
b3Color c(1.0f, 1.0f, 1.0f);
@ -58,6 +58,12 @@ static inline b3Color Color(float32 x, float32 a, float32 b)
class TensionMapping : public Test
{
public:
enum
{
e_w = 10,
e_h = 10
};
TensionMapping()
{
// Create cloth
@ -65,24 +71,25 @@ public:
def.mesh = &m_clothMesh;
def.density = 0.2f;
def.streching = 10000.0f;
def.shearing = 5000.0f;
def.damping = 100.0f;
def.strechDamping = 100.0f;
def.shearing = 1000.0f;
def.shearDamping = 10.0f;
def.bending = 1000.0f;
def.bendDamping = 10.0f;
m_cloth = new b3Cloth(def);
m_cloth->SetGravity(b3Vec3(0.0f, -9.8f, 0.0f));
m_cloth->SetWorld(&m_world);
// Freeze some particles
b3AABB3 aabb;
aabb.m_lower.Set(-5.0f, -1.0f, -6.0f);
aabb.m_upper.Set(5.0f, 1.0f, -4.0f);
for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
for (u32 i = 0; i < 2; ++i)
{
if (aabb.Contains(p->GetPosition()))
for (u32 j = 0; j < e_w + 1; ++j)
{
p->SetType(e_staticParticle);
u32 v = m_clothMesh.GetVertex(i, j);
b3ClothParticle* p = m_cloth->GetParticle(v);
p->SetType(e_staticClothParticle);
}
}
@ -103,8 +110,7 @@ public:
const b3ClothMesh* mesh = m_cloth->GetMesh();
b3StackArray<b3Vec3, 256> tension;
tension.Resize(mesh->vertexCount);
b3Vec3 tension[(e_h + 1) * (e_w + 1)];
for (u32 i = 0; i < mesh->vertexCount; ++i)
{
tension[i].SetZero();
@ -112,66 +118,100 @@ public:
for (b3Force* f = m_cloth->GetForceList().m_head; f; f = f->GetNext())
{
if (f->GetType() == e_strechForce)
if (f->GetType() == e_stretchForce)
{
b3StrechForce* s = (b3StrechForce*)f;
b3ClothTriangle* triangle = s->GetTriangle();
u32 triangleIndex = triangle->GetTriangle();
b3ClothMeshTriangle* mesh_triangle = m_clothMesh.triangles + triangleIndex;
u32 v1 = mesh_triangle->v1;
u32 v2 = mesh_triangle->v2;
u32 v3 = mesh_triangle->v3;
b3StretchForce* s = (b3StretchForce*)f;
b3Vec3 f1 = s->GetActionForce1();
b3Vec3 f2 = s->GetActionForce2();
b3Vec3 f3 = s->GetActionForce3();
b3ClothParticle* p1 = s->GetParticle1();
b3ClothParticle* p2 = s->GetParticle2();
b3ClothParticle* p3 = s->GetParticle3();
u32 v1 = p1->GetMeshIndex();
u32 v2 = p2->GetMeshIndex();
u32 v3 = p3->GetMeshIndex();
tension[v1] += f1;
tension[v2] += f2;
tension[v3] += f3;
}
}
for (b3ClothParticle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext())
{
if (p->GetType() == e_staticClothParticle)
{
b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_white);
}
if (p->GetType() == e_kinematicClothParticle)
{
b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_blue);
}
if (p->GetType() == e_dynamicClothParticle)
{
b3Draw_draw->DrawPoint(p->GetPosition(), 4.0f, b3Color_green);
}
}
for (u32 i = 0; i < mesh->triangleCount; ++i)
{
b3ClothMeshTriangle* t = mesh->triangles + i;
b3ClothMeshTriangle* triangle = mesh->triangles + i;
b3Vec3 v1 = m_cloth->GetParticle(triangle->v1)->GetPosition();
b3Vec3 v2 = m_cloth->GetParticle(triangle->v2)->GetPosition();
b3Vec3 v3 = m_cloth->GetParticle(triangle->v3)->GetPosition();
b3Vec3 v1 = m_cloth->GetParticle(t->v1)->GetPosition();
b3Vec3 v2 = m_cloth->GetParticle(t->v2)->GetPosition();
b3Vec3 v3 = m_cloth->GetParticle(t->v3)->GetPosition();
g_draw->DrawTriangle(v1, v2, v3, b3Color_black);
b3Vec3 c = (v1 + v2 + v3) / 3.0f;
float32 s = 0.9f;
scalar s = 0.9f;
v1 = s * (v1 - c) + c;
v2 = s * (v2 - c) + c;
v3 = s * (v3 - c) + c;
b3Vec3 f1 = tension[t->v1];
float32 L1 = b3Length(f1);
b3Vec3 f1 = tension[triangle->v1];
scalar L1 = b3Length(f1);
b3Vec3 f2 = tension[t->v2];
float32 L2 = b3Length(f2);
b3Vec3 f2 = tension[triangle->v2];
scalar L2 = b3Length(f2);
b3Vec3 f3 = tension[t->v3];
float32 L3 = b3Length(f3);
b3Vec3 f3 = tension[triangle->v3];
scalar L3 = b3Length(f3);
float32 L = (L1 + L2 + L3) / 3.0f;
scalar L = (L1 + L2 + L3) / 3.0f;
const float32 kMaxT = 10000.0f;
const scalar kMaxT = 10000.0f;
b3Color color = Color(L, 0.0f, kMaxT);
b3Vec3 n1 = b3Cross(v2 - v1, v3 - v1);
n1.Normalize();
g_draw->DrawSolidTriangle(n1, v1, v2, v3, color);
b3Vec3 n2 = -n1;
g_draw->DrawSolidTriangle(n2, v3, v2, v1, color);
scalar r = 0.05f;
{
b3Vec3 x1 = v1 + r * n1;
b3Vec3 x2 = v2 + r * n1;
b3Vec3 x3 = v3 + r * n1;
g_draw->DrawSolidTriangle(n1, x1, x2, x3, color);
}
{
b3Vec3 n2 = -n1;
b3Vec3 x1 = v1 + r * n2;
b3Vec3 x2 = v2 + r * n2;
b3Vec3 x3 = v3 + r * n2;
g_draw->DrawSolidTriangle(n2, x3, x2, x1, color);
}
}
if (m_clothDragger->IsDragging())
@ -179,9 +219,9 @@ public:
b3Vec3 pA = m_clothDragger->GetPointA();
b3Vec3 pB = m_clothDragger->GetPointB();
g_draw->DrawPoint(pA, 2.0f, b3Color_green);
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 2.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
@ -189,7 +229,7 @@ public:
extern u32 b3_clothSolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_clothSolverIterations);
float32 E = m_cloth->GetEnergy();
scalar E = m_cloth->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
@ -228,7 +268,7 @@ public:
return new TensionMapping();
}
b3GridClothMesh<10, 10> m_clothMesh;
b3GridClothMesh<e_w, e_h> m_clothMesh;
b3Cloth* m_cloth;
b3ClothDragger* m_clothDragger;
};

View File

@ -0,0 +1,413 @@
/*
* 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 TETGEN_SOFTBODY_H
#define TETGEN_SOFTBODY_H
#include <fstream>
struct TetGenMesh : public b3SoftBodyMesh
{
TetGenMesh()
{
vertexCount = 0;
vertices = nullptr;
triangleCount = 0;
triangles = nullptr;
tetrahedronCount = 0;
tetrahedrons = nullptr;
}
~TetGenMesh()
{
free(vertices);
free(triangles);
free(tetrahedrons);
}
bool Load(const char* node_filename, const char* face_filename, const char* ele_filename)
{
{
std::ifstream file(node_filename);
if (!file.good())
{
printf("Could not open %s \n", node_filename);
return false;
}
int nodeCount, nodeDimensions, attributeCount, boundaryMarkCount;
std::string line;
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
std::stringstream line_stream(line);
line_stream >> nodeCount >> nodeDimensions >> attributeCount >> boundaryMarkCount;
break;
}
if (nodeDimensions != 3)
{
printf(".node file: Only 3 dimensional nodes supported\n");
return false;
}
if (attributeCount != 0)
{
printf(".node file: Only nodes with 0 attributes supported\n");
return false;
}
if (boundaryMarkCount != 0)
{
printf(".node file: Only nodes with 0 markers supported\n");
return false;
}
assert(vertexCount == 0);
vertices = (b3Vec3*)malloc(sizeof(b3Vec3) * nodeCount);
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
int nodeId;
float x, y, z;
std::stringstream line_stream(line);
line_stream >> nodeId >> x >> y >> z;
assert(nodeId > 0);
assert(nodeId <= nodeCount);
assert(b3IsValid(x));
assert(b3IsValid(y));
assert(b3IsValid(z));
vertices[vertexCount].x = x;
vertices[vertexCount].y = y;
vertices[vertexCount].z = z;
++vertexCount;
}
assert(vertexCount == nodeCount);
}
{
std::ifstream file(face_filename);
if (!file.good())
{
printf("Could not open %s \n", face_filename);
return false;
}
int faceCount, boundaryMarkerCount;
std::string line;
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
std::stringstream line_stream(line);
line_stream >> faceCount >> boundaryMarkerCount;
break;
}
assert(triangleCount == 0);
triangles = (b3SoftBodyMeshTriangle*)malloc(sizeof(b3SoftBodyMeshTriangle) * faceCount);
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
int faceId;
int v1, v2, v3;
int corner;
std::stringstream line_stream(line);
line_stream >> faceId >> v1 >> v2 >> v3 >> corner;
assert(faceId > 0);
assert(faceId <= faceCount);
// Make CCW
b3Swap(v2, v3);
triangles[triangleCount].v1 = u32(v1 - 1);
triangles[triangleCount].v2 = u32(v2 - 1);
triangles[triangleCount].v3 = u32(v3 - 1);
++triangleCount;
}
assert(triangleCount == faceCount);
}
{
std::ifstream file(ele_filename);
if (!file.good())
{
printf("Could not open %s \n", ele_filename);
return false;
}
int tetCount, nodesPerTet, attributeCount;
std::string line;
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
std::stringstream line_stream(line);
line_stream >> tetCount >> nodesPerTet >> attributeCount;
break;
}
if (nodesPerTet != 4)
{
printf(".ele file: Only 4 nodes per tetrahedran supported\n");
return false;
}
if (attributeCount != 0)
{
printf(".ele file: Only elements with 0 attributes supported\n");
return false;
}
assert(tetrahedronCount == 0);
tetrahedrons = (b3SoftBodyMeshTetrahedron*)malloc(sizeof(b3SoftBodyMeshTetrahedron) * tetCount);
while (std::getline(file, line))
{
if (line[0] == '#')
{
continue;
}
if (line[0] == 0)
{
continue;
}
int tetId;
int v1, v2, v3, v4;
std::stringstream line_stream(line);
line_stream >> tetId >> v1 >> v2 >> v3 >> v4;
assert(tetId > 0);
assert(tetId <= tetCount);
// Make CCW
b3Swap(v2, v3);
tetrahedrons[tetrahedronCount].v1 = u32(v1 - 1);
tetrahedrons[tetrahedronCount].v2 = u32(v2 - 1);
tetrahedrons[tetrahedronCount].v3 = u32(v3 - 1);
tetrahedrons[tetrahedronCount].v4 = u32(v4 - 1);
++tetrahedronCount;
}
assert(tetrahedronCount == tetCount);
}
return true;
}
};
class TetGenSoftBody : public Test
{
public:
TetGenSoftBody()
{
{
bool ok = m_mesh.Load("data/octopus.node", "data/octopus.face", "data/octopus.ele");
assert(ok);
}
for (u32 i = 0; i < m_mesh.vertexCount; ++i)
{
m_mesh.vertices[i].y += 10.0f;
}
// Create soft body
b3SoftBodyDef def;
def.mesh = &m_mesh;
def.density = 0.2f;
def.E = 1000.0f;
def.nu = 0.3f;
def.radius = 0.05f;
def.friction = 0.2f;
m_body = new b3SoftBody(def);
b3Vec3 gravity(0.0f, -9.8f, 0.0f);
m_body->SetGravity(gravity);
// Create ground
{
b3BodyDef bd;
bd.type = e_staticBody;
b3Body* b = m_world.CreateBody(bd);
b3HullShape groundShape;
groundShape.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &groundShape;
sd.friction = 0.3f;
b3Shape* s = b->CreateShape(sd);
b3SoftBodyWorldShapeDef ssd;
ssd.shape = s;
m_body->CreateWorldShape(ssd);
}
m_bodyDragger = new b3SoftBodyDragger(&m_ray, m_body);
}
~TetGenSoftBody()
{
delete m_bodyDragger;
delete m_body;
}
void Step()
{
Test::Step();
if (m_bodyDragger->IsDragging())
{
m_bodyDragger->Drag();
}
m_body->Step(g_testSettings->inv_hertz, g_testSettings->velocityIterations, g_testSettings->positionIterations);
m_body->Draw();
if (m_bodyDragger->IsDragging())
{
b3Vec3 pA = m_bodyDragger->GetPointA();
b3Vec3 pB = m_bodyDragger->GetPointB();
g_draw->DrawPoint(pA, 4.0f, b3Color_green);
g_draw->DrawPoint(pB, 4.0f, b3Color_green);
g_draw->DrawSegment(pA, pB, b3Color_white);
}
extern u32 b3_softBodySolverIterations;
g_draw->DrawString(b3Color_white, "Iterations = %d", b3_softBodySolverIterations);
scalar E = m_body->GetEnergy();
g_draw->DrawString(b3Color_white, "E = %f", E);
}
void MouseMove(const b3Ray3& pw)
{
Test::MouseMove(pw);
}
void MouseLeftDown(const b3Ray3& pw)
{
Test::MouseLeftDown(pw);
if (m_bodyDragger->IsDragging() == false)
{
m_bodyDragger->StartDragging();
}
}
void MouseLeftUp(const b3Ray3& pw)
{
Test::MouseLeftUp(pw);
if (m_bodyDragger->IsDragging() == true)
{
m_bodyDragger->StopDragging();
}
}
static Test* Create()
{
return new TetGenSoftBody();
}
TetGenMesh m_mesh;
b3SoftBody* m_body;
b3SoftBodyDragger* m_bodyDragger;
};
#endif

View File

@ -0,0 +1,237 @@
/*
* 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 TIME_OF_IMPACT_H
#define TIME_OF_IMPACT_H
class TimeOfImpact : public Test
{
public:
TimeOfImpact()
{
m_shapeA.m_hull = &b3BoxHull_identity;
m_shapeA.m_radius = 0.0f;
m_shapeB.m_hull = &b3BoxHull_identity;
m_shapeB.m_radius = 0.0f;
m_sweepA.localCenter.SetZero();
m_sweepA.worldCenter0.Set(0.0f, 0.0f, 5.0f);
m_sweepA.worldCenter.Set(0.0f, 0.0f, -5.0f);
m_sweepA.orientation0.SetIdentity();
m_sweepA.orientation.SetIdentity();
m_sweepB.localCenter.SetZero();
m_sweepB.worldCenter0.Set(5.0f, 0.0f, 0.0f);
m_sweepB.worldCenter.Set(-5.0f, 0.0f, 0.0f);
m_sweepB.orientation0.SetIdentity();
m_sweepB.orientation.SetIdentity();
m_proxyA.Set(&m_shapeA, 0);
m_proxyB.Set(&m_shapeB, 0);
m_time = 0.0f;
}
void Step()
{
b3Color colorA0(1.0f, 0.0f, 0.0f, 1.0f);
b3Color colorB0(0.0f, 1.0f, 0.0f, 1.0f);
// t0
b3Transform xfA0 = m_sweepA.GetTransform(0.0f);
b3Transform xfB0 = m_sweepB.GetTransform(0.0f);
g_draw->DrawTransform(xfA0);
g_draw->DrawTransform(xfB0);
m_world.DrawShape(xfA0, &m_shapeA, b3Color_black);
m_world.DrawShape(xfB0, &m_shapeB, b3Color_black);
m_world.DrawSolidShape(xfA0, &m_shapeA, colorA0);
m_world.DrawSolidShape(xfB0, &m_shapeB, colorB0);
// t1
b3Transform xfA1 = m_sweepA.GetTransform(1.0f);
b3Transform xfB1 = m_sweepB.GetTransform(1.0f);
g_draw->DrawTransform(xfA1);
g_draw->DrawTransform(xfB1);
m_world.DrawShape(xfA1, &m_shapeA, b3Color_black);
m_world.DrawShape(xfB1, &m_shapeB, b3Color_black);
m_world.DrawSolidShape(xfA1, &m_shapeA, colorA0);
m_world.DrawSolidShape(xfB1, &m_shapeB, colorB0);
// time
b3Color colorAt(1.0f, 0.0f, 0.0f, 0.5f);
b3Color colorBt(0.0f, 1.0f, 0.0f, 0.5f);
b3Transform xfAx = m_sweepA.GetTransform(m_time);
b3Transform xfBx = m_sweepB.GetTransform(m_time);
g_draw->DrawTransform(xfAx);
g_draw->DrawTransform(xfBx);
m_world.DrawShape(xfAx, &m_shapeA, b3Color_black);
m_world.DrawShape(xfBx, &m_shapeB, b3Color_black);
m_world.DrawSolidShape(xfAx, &m_shapeA, colorAt);
m_world.DrawSolidShape(xfBx, &m_shapeB, colorBt);
b3TOIInput input;
input.proxyA = m_proxyA;
input.sweepA = m_sweepA;
input.proxyB = m_proxyB;
input.sweepB = m_sweepB;
input.tMax = 1.0f;
b3TOIOutput output = b3TimeOfImpact(input);
if (output.state == b3TOIOutput::e_touching)
{
b3Transform xfAt = m_sweepA.GetTransform(output.t);
b3Transform xfBt = m_sweepB.GetTransform(output.t);
m_world.DrawShape(xfAt, &m_shapeA, b3Color_black);
m_world.DrawShape(xfBt, &m_shapeB, b3Color_black);
}
g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow/W/S - Translate shape");
g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape");
g_draw->DrawString(b3Color_white, "F/B - Advance Time Forwards/Backwards");
g_draw->DrawString(b3Color_white, "Iterations = %d", output.iterations);
if (output.state == b3TOIOutput::e_failed)
{
g_draw->DrawString(b3Color_white, "State = Failed");
}
else if (output.state == b3TOIOutput::e_overlapped)
{
g_draw->DrawString(b3Color_white, "State = Overlapped");
}
else if (output.state == b3TOIOutput::e_separated)
{
g_draw->DrawString(b3Color_white, "State = Separated!");
}
else if (output.state == b3TOIOutput::e_touching)
{
g_draw->DrawString(b3Color_white, "State = Touching!");
}
g_draw->DrawString(b3Color_white, m_sweepA.worldCenter0, "t0");
g_draw->DrawString(b3Color_white, m_sweepA.worldCenter, "t1");
g_draw->DrawString(b3Color_white, m_sweepB.worldCenter0, "t0");
g_draw->DrawString(b3Color_white, m_sweepB.worldCenter, "t1");
}
void KeyDown(int key)
{
const scalar dt = 0.01f;
const scalar d = 0.15f;
const scalar theta = 0.05f * B3_PI;
if (key == GLFW_KEY_F)
{
m_time += dt;
if (m_time > 1.0f)
{
m_time = 0.0f;
}
}
if (key == GLFW_KEY_B)
{
m_time -= dt;
if (m_time < 0.0f)
{
m_time = 1.0f;
}
}
if (key == GLFW_KEY_LEFT)
{
m_sweepB.worldCenter0.x -= d;
}
if (key == GLFW_KEY_RIGHT)
{
m_sweepB.worldCenter0.x += d;
}
if (key == GLFW_KEY_UP)
{
m_sweepB.worldCenter0.y += d;
}
if (key == GLFW_KEY_DOWN)
{
m_sweepB.worldCenter0.y -= d;
}
if (key == GLFW_KEY_S)
{
m_sweepB.worldCenter0.z += d;
}
if (key == GLFW_KEY_W)
{
m_sweepB.worldCenter0.z -= d;
}
if (key == GLFW_KEY_X)
{
b3Quat qx = b3QuatRotationX(theta);
m_sweepB.orientation0 = m_sweepB.orientation0 * qx;
}
if (key == GLFW_KEY_Y)
{
b3Quat qy = b3QuatRotationY(theta);
m_sweepB.orientation0 = m_sweepB.orientation0 * qy;
}
if (key == GLFW_KEY_Z)
{
b3Quat qz = b3QuatRotationZ(theta);
m_sweepB.orientation0 = m_sweepB.orientation0 * qz;
}
}
static Test* Create()
{
return new TimeOfImpact();
}
scalar m_time;
b3HullShape m_shapeA;
b3Sweep m_sweepA;
b3ShapeGJKProxy m_proxyA;
b3HullShape m_shapeB;
b3Sweep m_sweepB;
b3ShapeGJKProxy m_proxyB;
};
#endif

View File

@ -16,45 +16,55 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef DEGENERATE_CAPSULE_H
#define DEGENERATE_CAPSULE_H
#ifndef TRIANGLE_CONTACT_TEST_H
#define TRIANGLE_CONTACT_TEST_H
class DegenerateCapsule : public Collide
class TriangleContactTest : public Test
{
public:
DegenerateCapsule()
TriangleContactTest()
{
m_xfA.position.Set(0.0f, 0.0f, 0.0f);
m_xfA.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.55f * B3_PI));
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_staticBody;
m_sA.m_centers[0].Set(0.0f, 0.0f, 0.0f);
m_sA.m_centers[1].Set(0.0f, 0.0f, 0.0f);
m_sA.m_radius = 0.05f;
b3Body* body = m_world.CreateBody(bdef);
m_xfB.position.Set(0.f, 0.0f, 0.0f);
m_xfB.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.0f * B3_PI));
b3TriangleShape ts;
ts.m_vertex1.Set(-5.0f, 0.0f, 5.0f);
ts.m_vertex2.Set(5.0f, 0.0f, 5.0f);
ts.m_vertex3.Set(0.0f, 0.0f, -5.0f);
b3Transform xf;
xf.SetIdentity();
xf.rotation = b3Diagonal(4.0f, 1.0f, 4.0f);
b3ShapeDef sdef;
sdef.shape = &ts;
sdef.friction = 1.0f;
m_box.SetTransform(xf);
body->CreateShape(sdef);
}
m_sB.m_hull = &m_box;
{
b3BodyDef bdef;
bdef.type = b3BodyType::e_dynamicBody;
bdef.position.Set(0.0f, 5.0f, 0.0f);
m_shapeA = &m_sA;
m_shapeB = &m_sB;
m_cache.count = 0;
b3Body* body = m_world.CreateBody(bdef);
b3HullShape hs;
hs.m_hull = &b3BoxHull_identity;
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.1f;
sdef.shape = &hs;
body->CreateShape(sdef);
}
}
static Test* Create()
{
return new DegenerateCapsule();
return new TriangleContactTest();
}
b3CapsuleShape m_sA;
b3HullShape m_sB;
b3BoxHull m_box;
};
#endif
#endif

View File

@ -39,11 +39,10 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(0.0f, -45.0f, 0.0f);
m.rotation = b3Diagonal(50.0f, 1.0f, 200.0f);
box.SetTransform(m);
box.SetExtents(50.0f, 1.0f, 200.0f);
b3Vec3 translation(0.0f, -45.0f, 0.0f);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -58,11 +57,10 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(0.0f, 50.0f, 0.0f);
m.rotation = b3Diagonal(50.0f, 1.0f, 200.0f);
box.SetTransform(m);
box.SetExtents(50.0f, 1.0f, 200.0f);
b3Vec3 translation(0.0f, 50.0f, 0.0f);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -77,11 +75,10 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(0.0f, 5.0f, -200.0f);
m.rotation = b3Diagonal(50.0f, 50.0f, 1.0f);
box.SetTransform(m);
box.SetExtents(50.0f, 50.0f, 1.0f);
b3Vec3 translation(0.0f, 5.0f, -200.0f);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -96,11 +93,10 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(0.0f, 5.0f, 200.0f);
m.rotation = b3Diagonal(50.0f, 50.0f, 1.0f);
box.SetTransform(m);
box.SetExtents(50.0f, 50.0f, 1.0f);
b3Vec3 translation(0.0f, 5.0f, 200.0f);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -115,11 +111,10 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(-50.0f, 5.0f, 0.0f);
m.rotation = b3Diagonal(1.0f, 50.0f, 200.0f);
box.SetTransform(m);
box.SetExtents(1.0f, 50.0f, 200.0f);
b3Vec3 translation(-50.0f, 5.0f, 0.0f);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -134,11 +129,11 @@ public:
{
static b3BoxHull box;
b3Transform m;
m.position.Set(50.0f, 5.0f, 0.0f);
m.rotation = b3Diagonal(1.0f, 50.0f, 200.0f);
box.SetExtents(1.0f, 50.0f, 200.0f);
b3Vec3 translation(50.0f, 5.0f, 0.0f);
box.SetTransform(m);
box.Translate(translation);
b3HullShape hs;
hs.m_hull = &box;
@ -161,8 +156,8 @@ public:
}
}
m_coneHull.SetAsCone();
m_cylinderHull.SetAsCylinder();
m_coneHull.SetExtents(1.0f, 1.0f);
m_cylinderHull.SetExtents(1.0f, 1.0f);
m_count = 0;
}
@ -204,8 +199,8 @@ public:
b3Body* body = m_world.CreateBody(bdef);
b3CapsuleShape capsule;
capsule.m_centers[0].Set(0.0f, 0.0f, -1.0f);
capsule.m_centers[1].Set(0.0f, 0.0f, 1.0f);
capsule.m_vertex1.Set(0.0f, 0.0f, -1.0f);
capsule.m_vertex2.Set(0.0f, 0.0f, 1.0f);
capsule.m_radius = 1.0f;
b3ShapeDef sdef;
@ -279,8 +274,8 @@ public:
}
u32 m_count;
b3QHull m_coneHull;
b3QHull m_cylinderHull;
b3ConeHull m_coneHull;
b3CylinderHull m_cylinderHull;
};
#endif

View File

@ -36,19 +36,12 @@ public:
ground->CreateShape(sd);
}
static b3BoxHull rampHull;
{
b3Transform xf;
xf.position.SetZero();
xf.rotation = b3Diagonal(25.0f, 0.5f, 25.0f);
rampHull.SetTransform(xf);
}
static b3BoxHull rampHull(25.0f, 0.5f, 25.0f);
{
b3BodyDef bdef;
bdef.position.Set(-20.0f, 20.0f, 0.0f);
bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), -0.1f * B3_PI);
bdef.orientation = b3QuatRotationZ(-0.1f * B3_PI);
b3Body* ramp = m_world.CreateBody(bdef);
@ -64,7 +57,7 @@ public:
{
b3BodyDef bdef;
bdef.position.Set(20.0f, 30.0f, 0.0f);
bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.1f * B3_PI);
bdef.orientation = b3QuatRotationZ(0.1f * B3_PI);
b3Body* ramp = m_world.CreateBody(bdef);
@ -80,7 +73,7 @@ public:
{
b3BodyDef bdef;
bdef.position.Set(-20.0f, 40.0f, 0.0f);
bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), -0.1f * B3_PI);
bdef.orientation = b3QuatRotationZ(-0.1f * B3_PI);
b3Body* ramp = m_world.CreateBody(bdef);
@ -96,7 +89,7 @@ public:
{
b3BodyDef bdef;
bdef.position.Set(20.0f, 50.0f, 0.0f);
bdef.orientation = b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.1f * B3_PI);
bdef.orientation = b3QuatRotationZ(0.1f * B3_PI);
b3Body* ramp = m_world.CreateBody(bdef);

View File

@ -46,8 +46,8 @@ public:
bA = m_world.CreateBody(bd);
b3CapsuleShape shape;
shape.m_centers[0].Set(0.0f, -3.5f, 0.0f);
shape.m_centers[1].Set(0.0f, 3.5f, 0.0f);
shape.m_vertex1.Set(0.0f, -3.5f, 0.0f);
shape.m_vertex2.Set(0.0f, 3.5f, 0.0f);
shape.m_radius = 0.5f;
b3ShapeDef sd;
@ -64,13 +64,7 @@ public:
bB = m_world.CreateBody(bd);
static b3BoxHull doorHull;
{
b3Transform xf;
xf.position.SetZero();
xf.rotation = b3Diagonal(2.0f, 4.0f, 0.5f);
doorHull.SetTransform(xf);
}
static b3BoxHull doorHull(2.0f, 4.0f, 0.5f);
b3HullShape hull;
hull.m_hull = &doorHull;
@ -86,14 +80,15 @@ public:
b3WeldJointDef jd;
jd.Initialize(bA, bB, anchor);
jd.frequencyHz = 2.0f;
jd.dampingRatio = 0.3f;
b3WeldJoint* wj = (b3WeldJoint*)m_world.CreateJoint(jd);
}
// Invalidate the orientation
b3Vec3 axis(1.0f, 0.0f, 0.0f);
float32 angle = B3_PI;
bB->SetTransform(bB->GetPosition(), axis, angle);
b3Quat q = b3QuatRotationX(B3_PI);
bB->SetTransform(bB->GetPosition(), q);
}
}

View File

@ -0,0 +1,204 @@
/*
* 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 WHEEL_TEST_H
#define WHEEL_TEST_H
class WheelTest : public Test
{
public:
WheelTest()
{
{
b3BodyDef bd;
b3Body* ground = m_world.CreateBody(bd);
b3HullShape hs;
hs.m_hull = &m_groundHull;
b3ShapeDef sd;
sd.shape = &hs;
ground->CreateShape(sd);
}
m_chassisHull.SetExtents(2.0f, 0.5f, 5.0f);
b3HullShape chassisShape;
chassisShape.m_hull = &m_chassisHull;
m_wheelHull.SetExtents(1.0f, 0.5f);
b3HullShape wheelShape;
wheelShape.m_hull = &m_wheelHull;
// Chassis
b3Body* chassis;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(0.0f, 10.0f, 0.0f);
chassis = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 0.3f;
sdef.shape = &chassisShape;
chassis->CreateShape(sdef);
}
b3Quat orientation = b3QuatRotationZ(0.5f * B3_PI);
b3Body* wheelLF;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(-1.0f, 7.0f, 4.5f);
bdef.orientation = orientation;
wheelLF = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.shape = &wheelShape;
sdef.density = 0.1f;
sdef.friction = 1.0f;
wheelLF->CreateShape(sdef);
}
{
b3WheelJointDef def;
def.Initialize(chassis, wheelLF, wheelLF->GetPosition(), b3Vec3_y, b3Vec3_x);
def.motorSpeed = 0.25f * B3_PI;
def.maxMotorTorque = 1000.0f;
m_joint1 = (b3WheelJoint*)m_world.CreateJoint(def);
}
b3Body* wheelRF;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(1.0f, 7.0, 4.5f);
bdef.orientation = orientation;
wheelRF = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 1.0f;
sdef.shape = &wheelShape;
wheelRF->CreateShape(sdef);
}
{
b3WheelJointDef def;
def.Initialize(chassis, wheelRF, wheelRF->GetPosition(), b3Vec3_y, b3Vec3_x);
def.motorSpeed = 0.25f * B3_PI;
def.maxMotorTorque = 1000.0f;
m_joint2 = (b3WheelJoint*)m_world.CreateJoint(def);
}
b3Body* wheelLB;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(-1.0f, 7.0f, -4.5f);
bdef.orientation = orientation;
wheelLB = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.shape = &wheelShape;
sdef.density = 0.1f;
sdef.friction = 1.0f;
wheelLB->CreateShape(sdef);
}
{
b3WheelJointDef def;
def.Initialize(chassis, wheelLB, wheelLB->GetPosition(), b3Vec3_y, b3Vec3_x);
m_world.CreateJoint(def);
}
b3Body* wheelRB;
{
b3BodyDef bdef;
bdef.type = e_dynamicBody;
bdef.position.Set(1.0f, 7.0f, -4.5f);
bdef.orientation = orientation;
wheelRB = m_world.CreateBody(bdef);
b3ShapeDef sdef;
sdef.density = 0.1f;
sdef.friction = 1.0f;
sdef.shape = &wheelShape;
wheelRB->CreateShape(sdef);
}
{
b3WheelJointDef def;
def.Initialize(chassis, wheelRB, wheelRB->GetPosition(), b3Vec3_y, b3Vec3_x);
m_world.CreateJoint(def);
}
}
void Step()
{
Test::Step();
g_draw->DrawString(b3Color_white, "M - Enable Motor");
g_draw->DrawString(b3Color_white, "S - Flip Motor Speed");
}
void KeyDown(int button)
{
if (button == GLFW_KEY_M)
{
m_joint1->EnableMotor(!m_joint1->IsMotorEnabled());
m_joint2->EnableMotor(!m_joint2->IsMotorEnabled());
}
if (button == GLFW_KEY_S)
{
m_joint1->SetMotorSpeed(-m_joint1->GetMotorSpeed());
m_joint2->SetMotorSpeed(-m_joint2->GetMotorSpeed());
}
}
static Test* Create()
{
return new WheelTest();
}
b3BoxHull m_chassisHull;
b3CylinderHull m_wheelHull;
b3WheelJoint* m_joint1;
b3WheelJoint* m_joint2;
};
#endif