123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #include "UnitTestFramework.h"
- #include "PhysicsTestContext.h"
- #include "Layers.h"
- #include <Jolt/Physics/Collision/Shape/BoxShape.h>
- #include <Jolt/Physics/Collision/Shape/SphereShape.h>
- #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
- #include <Jolt/Physics/Collision/Shape/CylinderShape.h>
- #include <Jolt/Physics/Collision/Shape/TaperedCapsuleShape.h>
- #include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
- #include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
- #include <Jolt/Physics/Collision/Shape/ScaledShape.h>
- #include <Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h>
- #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
- #include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
- #include <Jolt/Physics/Collision/Shape/MeshShape.h>
- #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
- #include <Jolt/Physics/Collision/CollidePointResult.h>
- TEST_SUITE("CollidePointTests")
- {
- // Probe directions in the direction of the faces
- static Vec3 cube_probes[] = {
- Vec3(-1.0f, 0, 0),
- Vec3(1.0f, 0, 0),
- Vec3(0, -1.0f, 0),
- Vec3(0, 1.0f, 0),
- Vec3(0, 0, -1.0f),
- Vec3(0, 0, 1.0f)
- };
- // Probe directions in the direction of the faces
- static Vec3 cube_and_zero_probes[] = {
- Vec3(0, 0, 0),
- Vec3(-1.0f, 0, 0),
- Vec3(1.0f, 0, 0),
- Vec3(0, -1.0f, 0),
- Vec3(0, 1.0f, 0),
- Vec3(0, 0, -1.0f),
- Vec3(0, 0, 1.0f)
- };
- // Probes in the xy-plane
- static Vec3 xy_probes[] = {
- Vec3(-1.0f, 0, 0),
- Vec3(1.0f, 0, 0),
- Vec3(0, 0, -1.0f),
- Vec3(0, 0, 1.0f)
- };
- // Probes in the xy-plane and zero
- static Vec3 xy_and_zero_probes[] = {
- Vec3(0, 0, 0),
- Vec3(-1.0f, 0, 0),
- Vec3(1.0f, 0, 0),
- Vec3(0, 0, -1.0f),
- Vec3(0, 0, 1.0f)
- };
- // Vertices of a cube
- static Vec3 cube_vertices[] = {
- Vec3(-1.0f, -1.0f, -1.0f),
- Vec3( 1.0f, -1.0f, -1.0f),
- Vec3(-1.0f, -1.0f, 1.0f),
- Vec3( 1.0f, -1.0f, 1.0f),
- Vec3(-1.0f, 1.0f, -1.0f),
- Vec3( 1.0f, 1.0f, -1.0f),
- Vec3(-1.0f, 1.0f, 1.0f),
- Vec3( 1.0f, 1.0f, 1.0f)
- };
- static void sTestHit(const Shape *inShape, Vec3Arg inPosition)
- {
- AllHitCollisionCollector<CollidePointCollector> collector;
- inShape->CollidePoint(inPosition - inShape->GetCenterOfMass(), SubShapeIDCreator(), collector);
- CHECK(collector.mHits.size() == 1);
- }
- static void sTestHit(const NarrowPhaseQuery &inNarrowPhase, Vec3Arg inPosition, const BodyID &inBodyID)
- {
- AllHitCollisionCollector<CollidePointCollector> collector;
- inNarrowPhase.CollidePoint(inPosition, collector);
- CHECK(collector.mHits.size() == 1);
- CHECK(collector.mHits[0].mBodyID == inBodyID);
- }
- static void sTestMiss(const Shape *inShape, Vec3Arg inPosition)
- {
- AllHitCollisionCollector<CollidePointCollector> collector;
- inShape->CollidePoint(inPosition - inShape->GetCenterOfMass(), SubShapeIDCreator(), collector);
- CHECK(collector.mHits.empty());
- }
- static void sTestMiss(const NarrowPhaseQuery &inNarrowPhase, Vec3Arg inPosition)
- {
- AllHitCollisionCollector<CollidePointCollector> collector;
- inNarrowPhase.CollidePoint(inPosition, collector);
- CHECK(collector.mHits.empty());
- }
- TEST_CASE("TestCollidePointVsBox")
- {
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- ShapeRefC shape = new BoxShape(half_box_size);
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, 0.99f * half_box_size * probe);
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, 1.01f * half_box_size * probe);
- }
- TEST_CASE("TestCollidePointVsSphere")
- {
- const float radius = 0.1f;
- ShapeRefC shape = new SphereShape(radius);
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, 0.99f * Vec3::sReplicate(radius) * probe);
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, 1.01f * Vec3::sReplicate(radius) * probe);
- }
- TEST_CASE("TestCollidePointVsCapsule")
- {
- const float half_height = 0.2f;
- const float radius = 0.1f;
- ShapeRefC shape = new CapsuleShape(half_height, radius);
- // Top hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * radius * probe + Vec3(0, half_height, 0));
- // Center hit
- sTestHit(shape, Vec3::sZero());
- // Bottom hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * radius * probe + Vec3(0, -half_height, 0));
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, 1.01f * Vec3(radius, half_height + radius, radius) * probe);
- }
- TEST_CASE("TestCollidePointVsTaperedCapsule")
- {
- const float half_height = 0.4f;
- const float top_radius = 0.1f;
- const float bottom_radius = 0.2f;
- TaperedCapsuleShapeSettings settings(half_height, top_radius, bottom_radius);
- ShapeRefC shape = settings.Create().Get();
- // Top hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * top_radius * probe + Vec3(0, half_height, 0));
- // Center hit
- sTestHit(shape, Vec3::sZero());
- // Bottom hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * bottom_radius * probe + Vec3(0, -half_height, 0));
- // Top misses
- sTestMiss(shape, Vec3(0, half_height + top_radius + 0.01f, 0));
- for (Vec3 probe : xy_probes)
- sTestMiss(shape, 1.01f * top_radius * probe + Vec3(0, half_height, 0));
- // Bottom misses
- sTestMiss(shape, Vec3(0, -half_height - bottom_radius - 0.01f, 0));
- for (Vec3 probe : xy_probes)
- sTestMiss(shape, 1.01f * bottom_radius * probe + Vec3(0, -half_height, 0));
- }
- TEST_CASE("TestCollidePointVsCylinder")
- {
- const float half_height = 0.2f;
- const float radius = 0.1f;
- ShapeRefC shape = new CylinderShape(half_height, radius);
- // Top hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * (radius * probe + Vec3(0, half_height, 0)));
- // Center hit
- sTestHit(shape, Vec3::sZero());
- // Bottom hits
- for (Vec3 probe : xy_and_zero_probes)
- sTestHit(shape, 0.99f * (radius * probe + Vec3(0, -half_height, 0)));
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, 1.01f * Vec3(radius, half_height, radius) * probe);
- }
- TEST_CASE("TestCollidePointVsConvexHull")
- {
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- Vec3 offset(10.0f, 11.0f, 12.0f);
- ConvexHullShapeSettings settings;
- for (uint i = 0; i < size(cube_vertices); ++i)
- settings.mPoints.push_back(offset + cube_vertices[i] * half_box_size);
- ShapeRefC shape = settings.Create().Get();
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, offset + 0.99f * half_box_size * probe);
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, offset + 1.01f * half_box_size * probe);
- }
- TEST_CASE("TestCollidePointVsRotatedTranslated")
- {
- Vec3 translation(10.0f, 11.0f, 12.0f);
- Quat rotation = Quat::sRotation(Vec3(1, 2, 3).Normalized(), 0.3f * JPH_PI);
- Mat44 transform = Mat44::sRotationTranslation(rotation, translation);
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- RotatedTranslatedShapeSettings settings(translation, rotation, new BoxShape(half_box_size));
- ShapeRefC shape = settings.Create().Get();
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, transform * (0.99f * half_box_size * probe));
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, transform * (1.01f * half_box_size * probe));
- }
- TEST_CASE("TestCollidePointVsScaled")
- {
- Vec3 scale(2.0f, 3.0f, -4.0f);
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- ShapeRefC shape = new ScaledShape(new BoxShape(half_box_size), scale);
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, scale * (0.99f * half_box_size * probe));
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, scale * (1.01f * half_box_size * probe));
- }
- TEST_CASE("TestCollidePointVsOffsetCenterOfMass")
- {
- Vec3 offset(10.0f, 11.0f, 12.0f);
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- OffsetCenterOfMassShapeSettings settings(offset, new BoxShape(half_box_size));
- ShapeRefC shape = settings.Create().Get();
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- sTestHit(shape, 0.99f * half_box_size * probe);
- // Misses
- for (Vec3 probe : cube_probes)
- sTestMiss(shape, 1.01f * half_box_size * probe);
- }
- TEST_CASE("TestCollidePointVsStaticCompound")
- {
- Vec3 translation1(10.0f, 11.0f, 12.0f);
- Quat rotation1 = Quat::sRotation(Vec3(1, 2, 3).Normalized(), 0.3f * JPH_PI);
- Mat44 transform1 = Mat44::sRotationTranslation(rotation1, translation1);
- Vec3 translation2(-1.0f, -2.0f, -3.0f);
- Quat rotation2 = Quat::sRotation(Vec3(4, 5, 6).Normalized(), 0.2f * JPH_PI);
- Mat44 transform2 = Mat44::sRotationTranslation(rotation2, translation2);
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- ShapeRefC box = new BoxShape(half_box_size);
- StaticCompoundShapeSettings settings;
- settings.AddShape(translation1, rotation1, box);
- settings.AddShape(translation2, rotation2, box);
- ShapeRefC shape = settings.Create().Get();
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- {
- Vec3 point = 0.99f * half_box_size * probe;
- sTestHit(shape, transform1 * point);
- sTestHit(shape, transform2 * point);
- }
- // Misses
- for (Vec3 probe : cube_probes)
- {
- Vec3 point = 1.01f * half_box_size * probe;
- sTestMiss(shape, transform1 * point);
- sTestMiss(shape, transform2 * point);
- }
- }
- TEST_CASE("TestCollidePointVsMutableCompound")
- {
- Vec3 translation1(10.0f, 11.0f, 12.0f);
- Quat rotation1 = Quat::sRotation(Vec3(1, 2, 3).Normalized(), 0.3f * JPH_PI);
- Mat44 transform1 = Mat44::sRotationTranslation(rotation1, translation1);
- Vec3 translation2(-1.0f, -2.0f, -3.0f);
- Quat rotation2 = Quat::sRotation(Vec3(4, 5, 6).Normalized(), 0.2f * JPH_PI);
- Mat44 transform2 = Mat44::sRotationTranslation(rotation2, translation2);
- Vec3 half_box_size(0.1f, 0.2f, 0.3f);
- ShapeRefC box = new BoxShape(half_box_size);
- MutableCompoundShapeSettings settings;
- settings.AddShape(translation1, rotation1, box);
- settings.AddShape(translation2, rotation2, box);
- ShapeRefC shape = settings.Create().Get();
- // Hits
- for (Vec3 probe : cube_and_zero_probes)
- {
- Vec3 point = 0.99f * half_box_size * probe;
- sTestHit(shape, transform1 * point);
- sTestHit(shape, transform2 * point);
- }
- // Misses
- for (Vec3 probe : cube_probes)
- {
- Vec3 point = 1.01f * half_box_size * probe;
- sTestMiss(shape, transform1 * point);
- sTestMiss(shape, transform2 * point);
- }
- }
- TEST_CASE("TestCollidePointVsMesh")
- {
- // Face indices of a cube
- int indices[][3] = {
- { 0, 1, 3 },
- { 0, 3, 2 },
- { 4, 7, 5 },
- { 4, 6, 7 },
- { 2, 3, 6 },
- { 3, 7, 6 },
- { 1, 0, 4 },
- { 1, 4, 5 },
- { 1, 7, 3 },
- { 1, 5, 7 },
- { 0, 2, 6 },
- { 0, 6, 4 }
- };
- const int grid_size = 2;
- UnitTestRandom random;
- uniform_real_distribution<float> range(0.1f, 0.3f);
- // Create a grid of closed shapes
- MeshShapeSettings settings;
- settings.SetEmbedded();
- int num_cubes = Cubed(2 * grid_size + 1);
- settings.mTriangleVertices.reserve(num_cubes * size(cube_vertices));
- settings.mIndexedTriangles.reserve(num_cubes * size(indices));
- for (int x = -grid_size; x <= grid_size; ++x)
- for (int y = -grid_size; y <= grid_size; ++y)
- for (int z = -grid_size; z <= grid_size; ++z)
- {
- Vec3 center((float)x, (float)y, (float)z);
- // Create vertices with randomness
- uint vtx = (uint)settings.mTriangleVertices.size();
- settings.mTriangleVertices.resize(vtx + size(cube_vertices));
- for (uint i = 0; i < size(cube_vertices); ++i)
- {
- Vec3 vertex(center + cube_vertices[i] * Vec3(range(random), range(random), range(random)));
- vertex.StoreFloat3(&settings.mTriangleVertices[vtx + i]);
- }
- // Flip inside out? (inside out shapes should act the same as normal shapes for CollidePoint)
- bool flip = (y & 1) == 0;
- // Create face indices
- uint idx = (uint)settings.mIndexedTriangles.size();
- settings.mIndexedTriangles.resize(idx + size(indices));
- for (uint i = 0; i < size(indices); ++i)
- settings.mIndexedTriangles[idx + i] = IndexedTriangle(vtx + indices[i][0], vtx + indices[i][flip? 2 : 1], vtx + indices[i][flip? 1 : 2]);
- }
- // Create body with random orientation
- PhysicsTestContext context;
- Body &mesh_body = context.CreateBody(&settings, Vec3::sRandom(random), Quat::sRandom(random), EMotionType::Static, EMotionQuality::Discrete, Layers::NON_MOVING, EActivation::DontActivate);
- // Get the shape
- ShapeRefC mesh_shape = mesh_body.GetShape();
- // Get narrow phase
- const NarrowPhaseQuery &narrow_phase = context.GetSystem()->GetNarrowPhaseQuery();
- // Get transform
- Mat44 body_transform = mesh_body.GetWorldTransform();
- CHECK(body_transform != Mat44::sIdentity());
- // Test points
- for (int x = -grid_size; x <= grid_size; ++x)
- for (int y = -grid_size; y <= grid_size; ++y)
- for (int z = -grid_size; z <= grid_size; ++z)
- {
- Vec3 center((float)x, (float)y, (float)z);
- // The center point should hit
- sTestHit(mesh_shape, center);
- sTestHit(narrow_phase, body_transform * center, mesh_body.GetID());
- // Points outside the hull should not hit
- for (Vec3 probe : cube_probes)
- {
- Vec3 point = center + 0.4f * probe;
- sTestMiss(mesh_shape, point);
- sTestMiss(narrow_phase, body_transform * point);
- }
- }
- }
- }
|