Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add box to box collision solver #953

Merged
merged 6 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ephemeral trait, used to indicate that relations and components shouldn't be persisted.
- Collider gizmos plugin, used to view collision shapes.
- Delta Time multiplier, can be used to adjust simulation speed (#866).
- Collision Solver plugin (#532)

### Changed

Expand Down
1 change: 1 addition & 0 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ set(CUBOS_ENGINE_SOURCE

"src/physics/plugin.cpp"
"src/physics/gravity.cpp"
"src/physics/solver.cpp"

"src/input/plugin.cpp"
"src/input/input.cpp"
Expand Down
24 changes: 24 additions & 0 deletions engine/include/cubos/engine/physics/physics_bundle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// @file
/// @brief Component @ref cubos::engine::PhysicsBundle.
/// @ingroup physics-plugin

#pragma once

#include <glm/vec3.hpp>

#include <cubos/core/reflection/reflect.hpp>

namespace cubos::engine
{
/// @brief Component which encapsulates the creation all components required for physics.
/// @ingroup physics-plugin
struct PhysicsBundle
{
CUBOS_REFLECT;

float mass = 1.0F;
glm::vec3 velocity = {0.0F, 0.0F, 0.0F};
glm::vec3 force = {0.0F, 0.0F, 0.0F};
glm::vec3 impulse = {0.0F, 0.0F, 0.0F};
};
} // namespace cubos::engine
2 changes: 2 additions & 0 deletions engine/include/cubos/engine/physics/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <cubos/engine/physics/components/mass.hpp>
#include <cubos/engine/physics/components/previous_position.hpp>
#include <cubos/engine/physics/components/velocity.hpp>
#include <cubos/engine/physics/physics_bundle.hpp>
#include <cubos/engine/physics/plugins/gravity.hpp>
#include <cubos/engine/physics/resources/damping.hpp>
#include <cubos/engine/physics/resources/fixed_delta_time.hpp>
Expand All @@ -39,6 +40,7 @@ namespace cubos::engine
/// - @ref Substeps - holds the amount of substeps for the physics update.
///
/// ## Components
/// - @ref PhysicsBundle - bundle that holds the physics information to give to a new entity.
/// - @ref Velocity - holds the information for moving an object straight.
/// - @ref Force - holds forces applied on a particle.
/// - @ref Impulse - holds impulses applied on a particle.
Expand Down
23 changes: 23 additions & 0 deletions engine/include/cubos/engine/physics/solver/solver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// @file
/// @brief Solver plugin, resource @ref cubos::engine::Solver.
/// @ingroup physics-solver-plugin

#pragma once

#include <cubos/engine/physics/components/force.hpp>
#include <cubos/engine/physics/components/impulse.hpp>
#include <cubos/engine/physics/components/mass.hpp>
#include <cubos/engine/physics/components/velocity.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
{
/// @defgroup physics-solver-plugin Solver
/// @ingroup physics-plugin
/// @brief Adds solver for constraints.

/// @brief Plugin entry function.
/// @param cubos @b CUBOS. main class
/// @ingroup physics-gravity-plugin
void solverPlugin(Cubos& cubos);
} // namespace cubos::engine
24 changes: 16 additions & 8 deletions engine/samples/collisions/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
#include <cubos/core/log.hpp>

#include <cubos/engine/collisions/collider.hpp>
#include <cubos/engine/collisions/narrow_phase/colliding_with.hpp>
#include <cubos/engine/collisions/colliding_with.hpp>
#include <cubos/engine/collisions/plugin.hpp>
#include <cubos/engine/collisions/shapes/box.hpp>
#include <cubos/engine/collisions/shapes/capsule.hpp>
#include <cubos/engine/input/plugin.hpp>
#include <cubos/engine/physics/plugin.hpp>
#include <cubos/engine/renderer/plugin.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/transform/plugin.hpp>
Expand All @@ -36,6 +37,7 @@ int main()
auto cubos = Cubos();

cubos.addPlugin(collisionsPlugin);
cubos.addPlugin(physicsPlugin);
cubos.addPlugin(rendererPlugin);
cubos.addPlugin(inputPlugin);

Expand Down Expand Up @@ -63,13 +65,14 @@ int main()
.entity();
});

cubos.startupSystem("create colliders").call([](State& state, Commands commands) {
cubos.startupSystem("create colliders").call([](State& state, Commands commands, Gravity& gravity) {
state.a = commands.create()
.add(Collider{})
.add(BoxCollisionShape{})
.add(LocalToWorld{})
.add(Position{glm::vec3{0.0F, 0.0F, -2.0F}})
.add(Rotation{})
.add(PhysicsBundle{.mass = 500.0F, .velocity = {0.0F, 0.0F, 1.0F}})
.entity();
state.aRotationAxis = glm::sphericalRand(1.0F);

Expand All @@ -79,15 +82,19 @@ int main()
.add(LocalToWorld{})
.add(Position{glm::vec3{0.0F, 0.0F, 2.0F}})
.add(Rotation{})
.add(PhysicsBundle{.mass = 500.0F, .velocity = {0.0F, 0.0F, -1.0F}})
.entity();
state.bRotationAxis = glm::sphericalRand(1.0F);

gravity.value = glm::vec3{0.0F, 0.0F, 0.0F};
});

cubos.system("move colliders")
.before("cubos.transform.update")
.call([](State& state, const Input& input, Query<Position&, Rotation&> query) {
auto [aPos, aRot] = *query.at(state.a);
auto [bPos, bRot] = *query.at(state.b);
.after("cubos.physics.unpack_bundle")
.call([](State& state, const Input& input, Query<Position&, Rotation&, Velocity&> query) {
auto [aPos, aRot, aVel] = *query.at(state.a);
auto [bPos, bRot, bVel] = *query.at(state.b);

if (state.collided)
{
Expand All @@ -97,20 +104,21 @@ int main()

aPos.vec = glm::vec3{0.0F, 0.0F, -2.0F};
aRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F};
aVel.vec = glm::vec3{0.0F, 0.0F, 1.0F};
state.aRotationAxis = glm::sphericalRand(1.0F);

bPos.vec = glm::vec3{0.0F, 0.0F, 2.0F};
bRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F};
bVel.vec = glm::vec3{0.0F, 0.0F, -1.0F};
state.bRotationAxis = glm::sphericalRand(1.0F);
}
return;
}

aRot.quat = glm::rotate(aRot.quat, 0.001F, state.aRotationAxis);
aPos.vec += glm::vec3{0.0F, 0.0F, 0.001F};
aVel.vec += glm::vec3{0.0F, 0.0F, 0.01F};

bRot.quat = glm::rotate(bRot.quat, 0.001F, state.bRotationAxis);
bPos.vec += glm::vec3{0.0F, 0.0F, -0.001F};
bVel.vec -= glm::vec3{0.0F, 0.0F, 0.01F};
});

cubos.system("check collisions")
Expand Down
2 changes: 1 addition & 1 deletion engine/src/collisions/narrow_phase/colliding_with.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <cubos/core/reflection/external/glm.hpp>
#include <cubos/core/reflection/external/primitives.hpp>

#include <cubos/engine/collisions/narrow_phase/colliding_with.hpp>
#include <cubos/engine/collisions/colliding_with.hpp>

CUBOS_REFLECT_IMPL(cubos::engine::CollidingWith)
{
Expand Down
2 changes: 1 addition & 1 deletion engine/src/collisions/narrow_phase/plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#pragma once

#include <cubos/engine/collisions/narrow_phase/colliding_with.hpp>
#include <cubos/engine/collisions/colliding_with.hpp>
#include <cubos/engine/prelude.hpp>

namespace cubos::engine
Expand Down
47 changes: 43 additions & 4 deletions engine/src/physics/plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <glm/glm.hpp>

#include <cubos/engine/physics/plugin.hpp>
#include <cubos/engine/physics/solver/solver.hpp>
#include <cubos/engine/settings/plugin.hpp>
#include <cubos/engine/transform/plugin.hpp>

Expand Down Expand Up @@ -49,6 +50,16 @@
.build();
}

CUBOS_REFLECT_IMPL(PhysicsBundle)

Check warning on line 53 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L53

Added line #L53 was not covered by tests
{
return cubos::core::ecs::TypeBuilder<PhysicsBundle>("cubos::engine::PhysicsBundle")
.withField("mass", &PhysicsBundle::mass)
.withField("velocity", &PhysicsBundle::velocity)
.withField("force", &PhysicsBundle::force)
.withField("impulse", &PhysicsBundle::impulse)
.build();

Check warning on line 60 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L55-L60

Added lines #L55 - L60 were not covered by tests
}

static bool simulatePhysicsStep(PhysicsAccumulator& accumulator, const FixedDeltaTime& fixedDeltaTime)
{
return accumulator.value >= fixedDeltaTime.value;
Expand All @@ -67,8 +78,32 @@
cubos.addComponent<Mass>();
cubos.addComponent<AccumulatedCorrection>();
cubos.addComponent<PreviousPosition>();
cubos.addComponent<PhysicsBundle>();

Check warning on line 81 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L81

Added line #L81 was not covered by tests

cubos.addPlugin(gravityPlugin);
cubos.addPlugin(solverPlugin);

Check warning on line 84 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L84

Added line #L84 was not covered by tests

// add components to entities created with PhysicsBundle
cubos.system("unpack PhysicsBundle's")
.tagged("cubos.physics.unpack_bundle")
.call([](Commands cmds, Query<Entity, const PhysicsBundle&> query) {
for (auto [ent, bundle] : query)

Check warning on line 90 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L87-L90

Added lines #L87 - L90 were not covered by tests
{
cmds.add(ent, PreviousPosition{});
cmds.add(ent, Mass{.mass = bundle.mass, .inverseMass = 1.0F / bundle.mass});
cmds.add(ent, Velocity{.vec = bundle.velocity});

Check warning on line 94 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L92-L94

Added lines #L92 - L94 were not covered by tests

auto force = Force{};
force.add(bundle.force);
cmds.add(ent, force);

Check warning on line 98 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L96-L98

Added lines #L96 - L98 were not covered by tests

auto impulse = Impulse{};
impulse.add(bundle.impulse);
cmds.add(ent, impulse);

Check warning on line 102 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L100-L102

Added lines #L100 - L102 were not covered by tests

cmds.add(ent, AccumulatedCorrection{});

Check warning on line 104 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L104

Added line #L104 was not covered by tests
}
});

Check warning on line 106 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L106

Added line #L106 was not covered by tests

// executed every frame
cubos.system("increase fixed-step accumulator")
Expand Down Expand Up @@ -107,7 +142,7 @@

if (mass.inverseMass <= 0.0F)
{
return;
continue;

Check warning on line 145 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L145

Added line #L145 was not covered by tests
}

// Apply damping
Expand All @@ -125,10 +160,14 @@
.tagged("cubos.physics.simulation.substeps.correct_position")
.after("cubos.physics.simulation.substeps.integrate")
.onlyIf(simulatePhysicsStep)
.call([](Query<Position&, AccumulatedCorrection&> query) {
for (auto [position, correction] : query)
.call([](Query<Position&, AccumulatedCorrection&, Mass&> query) {
for (auto [position, correction, mass] : query)

Check warning on line 164 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L163-L164

Added lines #L163 - L164 were not covered by tests
{
position.vec += correction.vec;
if (mass.inverseMass <= 0.0F)

Check warning on line 166 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L166

Added line #L166 was not covered by tests
{
continue;

Check warning on line 168 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L168

Added line #L168 was not covered by tests
}
position.vec += correction.vec; // lagrange * correction * inverseMass

Check warning on line 170 in engine/src/physics/plugin.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/plugin.cpp#L170

Added line #L170 was not covered by tests
correction.vec = glm::vec3(0, 0, 0);
}
});
Expand Down
32 changes: 32 additions & 0 deletions engine/src/physics/solver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <glm/glm.hpp>

#include <cubos/engine/collisions/colliding_with.hpp>
#include <cubos/engine/physics/components/accumulated_correction.hpp>
#include <cubos/engine/physics/solver/solver.hpp>

using namespace cubos::engine;

void cubos::engine::solverPlugin(Cubos& cubos)

Check warning on line 9 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L9

Added line #L9 was not covered by tests
{
cubos.system("solve collision")
.tagged("cubos.physics.solve")
.after("cubos.physics.simulation.substeps.integrate")
.after("cubos.collisions.narrow")
.before("cubos.physics.simulation.substeps.correct_position")
.call([](Query<Entity, AccumulatedCorrection&, const CollidingWith&, Entity, AccumulatedCorrection&> query) {
for (auto [ent1, correction1, colliding, ent2, correction2] : query)

Check warning on line 17 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L11-L17

Added lines #L11 - L17 were not covered by tests
{
auto penetration = colliding.penetration;
if (ent1 == colliding.entity)

Check warning on line 20 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L19-L20

Added lines #L19 - L20 were not covered by tests
{
correction1.vec -= colliding.normal * (penetration / 1.0F);
correction2.vec += colliding.normal * (penetration / 1.0F);

Check warning on line 23 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L22-L23

Added lines #L22 - L23 were not covered by tests
}
else
{
correction1.vec += colliding.normal * (penetration / 1.0F);
correction2.vec -= colliding.normal * (penetration / 1.0F);

Check warning on line 28 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L27-L28

Added lines #L27 - L28 were not covered by tests
}
}
});

Check warning on line 31 in engine/src/physics/solver.cpp

View check run for this annotation

Codecov / codecov/patch

engine/src/physics/solver.cpp#L31

Added line #L31 was not covered by tests
}
Loading