diff --git a/examples/testbed/framework/test_entries.cpp b/examples/testbed/framework/test_entries.cpp index d44b574..b2b6596 100644 --- a/examples/testbed/framework/test_entries.cpp +++ b/examples/testbed/framework/test_entries.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -64,7 +63,7 @@ #include #include #include -#include +#include #include #include #include @@ -107,7 +106,6 @@ TestEntry g_tests[] = { "Box Pyramid Rows", &Pyramids::Create }, { "Ray Cast", &RayCast::Create }, { "Sensor Test", &SensorTest::Create }, - { "Character", &CharacterTest::Create }, { "Body Types", &BodyTypes::Create }, { "Varying Friction", &VaryingFriction::Create }, { "Varying Restitution", &VaryingRestitution::Create }, @@ -118,7 +116,7 @@ TestEntry g_tests[] = { "Pinned Cloth", &PinnedCloth::Create }, { "Particle Types", &ParticleTypes::Create }, { "Tension Mapping", &TensionMapping::Create }, - { "Self-Collision", &SelfCollision::Create }, + { "Cloth and Capsule", &ClothCapsule::Create }, { "Beam", &Beam::Create }, { "Pinned Soft Body", &PinnedSoftBody::Create }, { "Smash Soft Body", &SmashSoftBody::Create }, diff --git a/examples/testbed/tests/character_test.h b/examples/testbed/tests/character_test.h deleted file mode 100644 index 93a8f02..0000000 --- a/examples/testbed/tests/character_test.h +++ /dev/null @@ -1,624 +0,0 @@ -/* -* 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 CHARACTER_TEST_H -#define CHARACTER_TEST_H - -struct Plane -{ - b3Vec3 n; - b3Vec3 p; -}; - -class CharacterController -{ -public: - CharacterController(b3SphereShape* shape) - { - m_characterShape = shape; - m_characterBody = m_characterShape->GetBody(); - m_world = m_characterBody->GetWorld(); - m_translation.SetZero(); - m_isGrounded = false; - - UpdateGrounded(); - } - - ~CharacterController() - { - - } - - bool IsGrounded() const - { - return m_isGrounded; - } - - void Move(const b3Vec3& translation) - { - m_translation += translation; - } - - void Step() - { - Solve(); - - UpdateGrounded(); - } -private: - b3Sphere GetCharacterSphere() const - { - b3Sphere sphere; - sphere.vertex = m_characterBody->GetWorldPoint(m_characterShape->m_center); - sphere.radius = m_characterShape->m_radius; - return sphere; - } - - void UpdateGrounded() - { - b3StackArray shapes; - CollectStaticShapes(shapes); - - b3StackArray planes; - CollectOverlapPlanes(planes, shapes); - - m_isGrounded = false; - - for (u32 i = 0; i < planes.Count(); ++i) - { - Plane plane = planes[i]; - - float32 cosine = b3Dot(b3Vec3_y, plane.n); - - // ~80 degrees - const float32 kTol = 0.17f; - - if (cosine > kTol) - { - m_isGrounded = true; - break; - } - } - } - - void CollectStaticShapes(b3Array& shapes) const - { - for (b3Body* b = m_world->GetBodyList().m_head; b; b = b->GetNext()) - { - if (b == m_characterBody) - { - continue; - } - - if (b->GetType() != e_staticBody) - { - continue; - } - - for (b3Shape* s = b->GetShapeList().m_head; s; s = s->GetNext()) - { - shapes.PushBack(s); - } - } - } - - void CollectOverlapPlanes(b3Array& planes, - const b3Array& shapes) const - { - b3Sphere sphere2 = GetCharacterSphere(); - - for (u32 i = 0; i < shapes.Count(); ++i) - { - b3Shape* shape1 = shapes[i]; - b3Body* body1 = shape1->GetBody(); - b3Transform xf1 = body1->GetTransform(); - - if (shape1->GetType() == e_meshShape) - { - b3MeshShape* meshShape1 = (b3MeshShape*)shape1; - const b3Mesh* mesh1 = meshShape1->m_mesh; - - for (u32 j = 0; j < mesh1->triangleCount; ++j) - { - b3TestSphereOutput output; - bool overlap = meshShape1->TestSphere(&output, sphere2, xf1, j); - - if (overlap) - { - Plane plane; - plane.n = output.normal; - plane.p = output.point; - - planes.PushBack(plane); - } - } - } - else - { - b3TestSphereOutput output; - bool overlap = shape1->TestSphere(&output, sphere2, xf1); - - if (overlap) - { - Plane plane; - plane.n = output.normal; - plane.p = output.point; - - planes.PushBack(plane); - } - } - } - } - - void CollectSweepPlanes(b3Array& planes, - const b3Array& shapes, - const b3Vec3& translation2) const - { - if (b3LengthSquared(translation2) < B3_EPSILON * B3_EPSILON) - { - return; - } - - b3Transform xf2 = m_characterBody->GetTransform(); - - b3ShapeGJKProxy proxy2; - proxy2.Set(m_characterShape, 0); - - for (u32 i = 0; i < shapes.Count(); ++i) - { - b3Shape* shape1 = shapes[i]; - b3Body* body1 = shape1->GetBody(); - - b3Transform xf1 = body1->GetTransform(); - - if (shape1->GetType() == e_meshShape) - { - b3MeshShape* meshShape1 = (b3MeshShape*)shape1; - const b3Mesh* mesh1 = meshShape1->m_mesh; - - for (u32 j = 0; j < mesh1->triangleCount; ++j) - { - b3ShapeGJKProxy proxy1; - proxy1.Set(shape1, j); - - b3GJKShapeCastOutput output; - bool hit = b3GJKShapeCast(&output, xf1, proxy1, xf2, proxy2, translation2); - - if (hit) - { - Plane plane; - plane.n = output.normal; - plane.p = output.point; - - planes.PushBack(plane); - } - } - } - else - { - b3ShapeGJKProxy proxy1; - proxy1.Set(shape1, 0); - - b3GJKShapeCastOutput output; - bool hit = b3GJKShapeCast(&output, xf1, proxy1, xf2, proxy2, translation2); - - if (hit) - { - Plane plane; - plane.n = output.normal; - plane.p = output.point; - - planes.PushBack(plane); - } - } - } - } - - b3Vec3 SolvePositionConstraints(const b3Array& planes, const b3Vec3& position) const - { - b3Vec3 localCenter = m_characterBody->GetLocalCenter(); - b3Vec3 c = position; - b3Quat q = m_characterBody->GetOrientation(); - - const u32 kMaxPositionIterations = 10; - - for (u32 i = 0; i < kMaxPositionIterations; ++i) - { - for (u32 j = 0; j < planes.Count(); ++j) - { - Plane nc = planes[j]; - b3Plane plane(nc.n, nc.p); - - b3Transform xf; - xf.rotation = b3QuatMat33(q); - xf.position = c - b3Mul(xf.rotation, localCenter); - - b3Sphere sphere; - sphere.vertex = b3Mul(xf, m_characterShape->m_center); - sphere.radius = m_characterShape->m_radius; - - float32 separation = b3Distance(sphere.vertex, plane); - - if (separation > sphere.radius) - { - continue; - } - - separation -= sphere.radius; - - float32 C = b3Clamp(B3_BAUMGARTE * (separation + B3_LINEAR_SLOP), -B3_MAX_LINEAR_CORRECTION, 0.0f); - - b3Vec3 normal = plane.normal; - b3Vec3 P = C * normal; - - c -= P; - } - } - - return c; - } - - void Solve() - { - b3StackArray shapes; - CollectStaticShapes(shapes); - - // Collect collision planes - b3StackArray planes; - CollectOverlapPlanes(planes, shapes); - - b3Vec3 startPosition = m_characterBody->GetWorldCenter(); - - b3Vec3 targetPosition = startPosition + m_translation; - - m_translation.SetZero(); - - b3Vec3 solvePosition = SolvePositionConstraints(planes, targetPosition); - - b3Vec3 oldSolvePosition = solvePosition; - - for (;;) - { - // Collect collision planes - b3Vec3 translation = solvePosition - startPosition; - - CollectSweepPlanes(planes, shapes, translation); - - solvePosition = SolvePositionConstraints(planes, targetPosition); - - const float32 tolerance = 0.05f; - - if (b3DistanceSquared(oldSolvePosition, solvePosition) < tolerance * tolerance) - { - break; - } - - oldSolvePosition = solvePosition; - } - - // Synchronize body - b3Quat orientation = m_characterBody->GetOrientation(); - - b3Vec3 axis; - float32 angle; - orientation.GetAxisAngle(&axis, &angle); - - m_characterBody->SetTransform(solvePosition, axis, angle); - } - - b3World* m_world; - b3Body* m_characterBody; - b3SphereShape* m_characterShape; - b3Vec3 m_translation; - bool m_isGrounded; -}; - -class CharacterTest : public Test -{ -public: - CharacterTest() - { - { - 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(-10.0f, 3.0f, 0.0f); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 2.0f, 5.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(-10.0f, 9.0f, 0.0f); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(1.0f, 4.0f, 1.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(-10.0f, 2.7f, 7.0f); - bdef.orientation.Set(b3Vec3_x, 0.25f * B3_PI); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 0.25f, 3.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(-10.0f, 2.7f, -7.0f); - bdef.orientation.Set(b3Vec3_x, -0.25f * B3_PI); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 0.25f, 3.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(10.0f, 3.0f, 0.0f); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 2.0f, 5.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(10.0f, 9.0f, 0.0f); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(1.0f, 4.0f, 1.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(10.0f, 2.7f, 7.0f); - bdef.orientation.Set(b3Vec3_x, 0.25f * B3_PI); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 0.25f, 3.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(10.0f, 2.7f, -7.0f); - bdef.orientation.Set(b3Vec3_x, -0.25f * B3_PI); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(2.0f, 0.25f, 3.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.position.Set(0.0f, 4.0f, 0.0f); - - b3Body* body = m_world.CreateBody(bdef); - - static b3BoxHull boxHull; - boxHull.Set(8.0f, 1.0f, 2.0f); - - b3HullShape hs; - hs.m_hull = &boxHull; - - b3ShapeDef sdef; - sdef.shape = &hs; - - b3Shape* shape = body->CreateShape(sdef); - } - - { - b3BodyDef bdef; - bdef.type = b3BodyType::e_kinematicBody; - bdef.position.Set(0.0f, 1.0f, 20.0f); - - b3Body* body = m_world.CreateBody(bdef); - - b3SphereShape sphere; - sphere.m_center.SetZero(); - sphere.m_radius = 1.0f; - - b3ShapeDef sdef; - sdef.shape = &sphere; - - b3SphereShape* shape = (b3SphereShape*)body->CreateShape(sdef); - - m_characterController = new CharacterController(shape); - } - } - - ~CharacterTest() - { - delete m_characterController; - } - - void Step() - { - g_draw->DrawString(b3Color_white, "Arrows - Walk"); - g_draw->DrawString(b3Color_white, "Space - Jump"); - - float32 dt = g_testSettings->inv_hertz; - - const float32 walkSpeed = 10.0f; - const float32 jumpSpeed = 10.0f; - const float32 gravityAcc = 9.8f; - - static b3Vec3 velocity = b3Vec3_zero; - - velocity.x = 0.0f; - velocity.z = 0.0f; - - extern GLFWwindow* g_window; - - bool leftDown = glfwGetKey(g_window, GLFW_KEY_LEFT); - bool rightDown = glfwGetKey(g_window, GLFW_KEY_RIGHT); - bool downDown = glfwGetKey(g_window, GLFW_KEY_DOWN); - bool upDown = glfwGetKey(g_window, GLFW_KEY_UP); - bool spaceDown = glfwGetKey(g_window, GLFW_KEY_SPACE); - - bool isGrounded = m_characterController->IsGrounded(); - - // Walk - if (leftDown) - { - velocity.x -= walkSpeed; - } - - if (rightDown) - { - velocity.x += walkSpeed; - } - - if (upDown) - { - velocity.z -= walkSpeed; - } - - if (downDown) - { - velocity.z += walkSpeed; - } - - if (isGrounded) - { - velocity.y = 0.0f; - - // Jump - if (spaceDown) - { - velocity.y += jumpSpeed; - } - } - else - { - // Integrate gravity - velocity.y -= dt * gravityAcc; - } - - // Compute translation - b3Vec3 translation = dt * velocity; - - // Move character - m_characterController->Move(translation); - - // Step controllers - m_characterController->Step(); - - // Step world - Test::Step(); - } - - static Test* Create() - { - return new CharacterTest(); - } - - CharacterController* m_characterController; -}; - -#endif \ No newline at end of file diff --git a/examples/testbed/tests/self_collision.h b/examples/testbed/tests/cloth_capsule.h similarity index 94% rename from examples/testbed/tests/self_collision.h rename to examples/testbed/tests/cloth_capsule.h index 3051748..0a816e3 100644 --- a/examples/testbed/tests/self_collision.h +++ b/examples/testbed/tests/cloth_capsule.h @@ -16,13 +16,13 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SELF_COLLISION_H -#define SELF_COLLISION_H +#ifndef CLOTH_CAPSULE_H +#define CLOTH_CAPSULE_H -class SelfCollision : public Test +class ClothCapsule : public Test { public: - SelfCollision() : m_rectangleGarment(5.0f, 5.0f) + ClothCapsule() : m_rectangleGarment(5.0f, 5.0f) { // Generate 2D mesh m_rectangleGarmentMesh.Set(&m_rectangleGarment, 1.0f); @@ -76,7 +76,7 @@ public: m_clothDragger = new b3ClothDragger(&m_ray, m_cloth); } - ~SelfCollision() + ~ClothCapsule() { delete m_cloth; delete m_clothDragger; @@ -141,7 +141,7 @@ public: static Test* Create() { - return new SelfCollision(); + return new ClothCapsule(); } b3RectangleGarment m_rectangleGarment; diff --git a/examples/testbed/tests/table_cloth.h b/examples/testbed/tests/table_cloth.h index 32fd016..9b9c147 100644 --- a/examples/testbed/tests/table_cloth.h +++ b/examples/testbed/tests/table_cloth.h @@ -53,7 +53,7 @@ public: for (b3Particle* p = m_cloth->GetParticleList().m_head; p; p = p->GetNext()) { - p->SetRadius(0.05f); + p->SetRadius(0.1f); p->SetFriction(0.2f); } diff --git a/src/bounce/dynamics/shapes/mesh_shape.cpp b/src/bounce/dynamics/shapes/mesh_shape.cpp index 99af62f..88f3f3d 100644 --- a/src/bounce/dynamics/shapes/mesh_shape.cpp +++ b/src/bounce/dynamics/shapes/mesh_shape.cpp @@ -17,9 +17,7 @@ */ #include -#include #include -#include b3MeshShape::b3MeshShape() { @@ -92,20 +90,11 @@ bool b3MeshShape::TestSphere(b3TestSphereOutput* output, const b3Sphere& sphere, bool b3MeshShape::TestSphere(b3TestSphereOutput* output, const b3Sphere& sphere, const b3Transform& xf, u32 index) const { - B3_ASSERT(index < m_mesh->triangleCount); - b3Triangle* triangle = m_mesh->triangles + index; - b3Vec3 v1 = m_mesh->vertices[triangle->v1]; - b3Vec3 v2 = m_mesh->vertices[triangle->v2]; - b3Vec3 v3 = m_mesh->vertices[triangle->v3]; - - b3TriangleHull hull(v1, v2, v3); - - b3HullShape hullShape; - hullShape.m_body = m_body; - hullShape.m_hull = &hull; - hullShape.m_radius = B3_HULL_RADIUS; - - return hullShape.TestSphere(output, sphere, xf); + B3_NOT_USED(output); + B3_NOT_USED(sphere); + B3_NOT_USED(xf); + B3_NOT_USED(index); + return false; } bool b3MeshShape::RayCast(b3RayCastOutput* output, const b3RayCastInput& input, const b3Transform& xf, u32 index) const @@ -137,7 +126,7 @@ bool b3MeshShape::RayCast(b3RayCastOutput* output, const b3RayCastInput& input, return false; } -struct b3MeshRayCastCallback +struct b3MeshShapeRayCastCallback { float32 Report(const b3RayCastInput& subInput, u32 proxyId) { @@ -169,7 +158,7 @@ struct b3MeshRayCastCallback bool b3MeshShape::RayCast(b3RayCastOutput* output, const b3RayCastInput& input, const b3Transform& xf) const { - b3MeshRayCastCallback callback; + b3MeshShapeRayCastCallback callback; callback.input = input; callback.mesh = this; callback.xf = xf;