Upgrade bounce
This commit is contained in:
178
examples/testbed/tests/aabb_time_of_impact.h
Normal file
178
examples/testbed/tests/aabb_time_of_impact.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
215
examples/testbed/tests/cape.h
Normal file
215
examples/testbed/tests/cape.h
Normal 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
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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
|
181
examples/testbed/tests/cloth_element_test.h
Normal file
181
examples/testbed/tests/cloth_element_test.h
Normal 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
|
268
examples/testbed/tests/cloth_sdf.h
Normal file
268
examples/testbed/tests/cloth_sdf.h
Normal 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
|
@ -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;
|
||||
};
|
||||
|
571
examples/testbed/tests/cloth_tearing.h
Normal file
571
examples/testbed/tests/cloth_tearing.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -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()
|
||||
|
282
examples/testbed/tests/convex_cast.h
Normal file
282
examples/testbed/tests/convex_cast.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
119
examples/testbed/tests/conveyor_belt.h
Normal file
119
examples/testbed/tests/conveyor_belt.h
Normal 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
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
171
examples/testbed/tests/linear_time_of_impact.h
Normal file
171
examples/testbed/tests/linear_time_of_impact.h
Normal 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
|
@ -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
|
123
examples/testbed/tests/motor_test.h
Normal file
123
examples/testbed/tests/motor_test.h
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
222
examples/testbed/tests/node_types.h
Normal file
222
examples/testbed/tests/node_types.h
Normal 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
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
135
examples/testbed/tests/prismatic_test.h
Normal file
135
examples/testbed/tests/prismatic_test.h
Normal 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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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;
|
||||
|
136
examples/testbed/tests/sheet.h
Normal file
136
examples/testbed/tests/sheet.h
Normal 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
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
|
177
examples/testbed/tests/softbody_anchor.h
Normal file
177
examples/testbed/tests/softbody_anchor.h
Normal 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
|
@ -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
|
@ -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;
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
413
examples/testbed/tests/tetgen_softbody.h
Normal file
413
examples/testbed/tests/tetgen_softbody.h
Normal 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
|
237
examples/testbed/tests/time_of_impact.h
Normal file
237
examples/testbed/tests/time_of_impact.h
Normal 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
|
@ -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
|
@ -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
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
204
examples/testbed/tests/wheel_test.h
Normal file
204
examples/testbed/tests/wheel_test.h
Normal 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
|
Reference in New Issue
Block a user