Skip to content

Commit

Permalink
change voxelshape collisions to use greedy meshing
Browse files Browse the repository at this point in the history
feat(engine): add voxel collision shapes

bla
  • Loading branch information
joaomanita authored and joaomanita committed Oct 8, 2024
1 parent 8cbc722 commit f555261
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 114 deletions.
2 changes: 1 addition & 1 deletion engine/include/cubos/engine/collisions/shapes/voxel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

#include <cubos/core/geom/box.hpp>
#include <cubos/core/log.hpp>
#include <cubos/core/reflection/external/glm.hpp>
#include <cubos/core/reflection/reflect.hpp>

#include <cubos/engine/assets/asset.hpp>
#include <cubos/engine/collisions/octree.hpp>
#include <cubos/engine/voxels/grid.hpp>

namespace cubos::engine
Expand Down
1 change: 1 addition & 0 deletions engine/samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ make_sample(DIR "render/main" ASSETS)
make_sample(DIR "render/shadows" ASSETS)
make_sample(DIR "imgui")
make_sample(DIR "collisions" ASSETS)
make_sample(DIR "voxel-shape-collisions" ASSETS)
make_sample(DIR "scene" ASSETS)
make_sample(DIR "voxels" ASSETS)
make_sample(DIR "gizmos")
Expand Down
Binary file not shown.
3 changes: 3 additions & 0 deletions engine/samples/voxel-shape-collisions/assets/car.grd.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"id": "059c16e7-a439-44c7-9bdc-6e069dba0c75"
}
Binary file not shown.
3 changes: 3 additions & 0 deletions engine/samples/voxel-shape-collisions/assets/main.pal.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"id": "1aa5e234-28cb-4386-99b4-39386b0fc215"
}
179 changes: 179 additions & 0 deletions engine/samples/voxel-shape-collisions/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include <glm/gtc/random.hpp>

#include <cubos/core/geom/box.hpp>
#include <cubos/core/log.hpp>

#include <cubos/engine/assets/plugin.hpp>
#include <cubos/engine/collisions/collider.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/collisions/shapes/voxel.hpp>
#include <cubos/engine/defaults/plugin.hpp>
#include <cubos/engine/fixed_step/plugin.hpp>
#include <cubos/engine/gizmos/plugin.hpp>
#include <cubos/engine/gizmos/target.hpp>
#include <cubos/engine/physics/plugin.hpp>
#include <cubos/engine/physics/solver/plugin.hpp>
#include <cubos/engine/render/camera/draws_to.hpp>
#include <cubos/engine/render/camera/perspective.hpp>
#include <cubos/engine/render/defaults/plugin.hpp>
#include <cubos/engine/render/defaults/target.hpp>
#include <cubos/engine/render/picker/plugin.hpp>
#include <cubos/engine/render/tone_mapping/plugin.hpp>
#include <cubos/engine/render/voxels/grid.hpp>
#include <cubos/engine/render/voxels/palette.hpp>
#include <cubos/engine/settings/plugin.hpp>
#include <cubos/engine/settings/settings.hpp>
#include <cubos/engine/transform/plugin.hpp>
#include <cubos/engine/voxels/plugin.hpp>
#include <cubos/engine/window/plugin.hpp>

using cubos::core::geom::Box;
using cubos::core::io::Key;
using cubos::core::io::Modifiers;
using cubos::core::io::MouseButton;

using namespace cubos::engine;

static CUBOS_DEFINE_TAG(collisionsSampleUpdated);

struct State
{
CUBOS_ANONYMOUS_REFLECT(State);

bool collided = false;

Entity a;
Entity b;

glm::vec3 aRotationAxis;
glm::vec3 bRotationAxis;
};

/// [Get handles to assets]
static const Asset<VoxelGrid> CarAsset = AnyAsset("059c16e7-a439-44c7-9bdc-6e069dba0c75");
static const Asset<VoxelPalette> PaletteAsset = AnyAsset("1aa5e234-28cb-4386-99b4-39386b0fc215");
/// [Get handles to assets]

int main()
{
auto cubos = Cubos();

cubos.plugin(defaultsPlugin);
// cubos.plugin(voxelsPlugin);
// cubos.plugin(inputPlugin);
// cubos.plugin(settingsPlugin);
// cubos.plugin(windowPlugin);
// cubos.plugin(transformPlugin);
// cubos.plugin(assetsPlugin);
// cubos.plugin(fixedStepPlugin);
// cubos.plugin(collisionsPlugin);
// cubos.plugin(physicsPlugin);
// cubos.plugin(solverPlugin);
// cubos.plugin(inputPlugin);
// cubos.plugin(renderDefaultsPlugin);
// cubos.plugin(gizmosPlugin);
cubos.tag(gizmosDrawTag).after(toneMappingTag);

cubos.resource<State>();

cubos.startupSystem("setup camera").call([](Commands commands) {
auto targetEnt = commands.create().add(RenderTargetDefaults{}).add(GizmosTarget{}).entity();
commands.create()
.relatedTo(targetEnt, DrawsTo{})
.add(PerspectiveCamera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F})
.add(LocalToWorld{})
.add(Position{{-35.0F, 1.5F, 0.0F}})
.add(Rotation::lookingAt({3.0F, -1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F}));
});

cubos.startupSystem("configure Assets").tagged(settingsTag).call([](Settings& settings) {
settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER);
});

/// [Set palette]
cubos.startupSystem("set palette").call([](RenderPalette& palette) { palette.asset = PaletteAsset; });
/// [Set palette]

cubos.startupSystem("create colliders").tagged(assetsTag).call([](State& state, Commands commands, Assets& assets) {
auto car = assets.read(CarAsset);
glm::vec3 offset = glm::vec3(car->size().x, car->size().y, car->size().z) / -2.0F;
state.a = commands.create()
.add(Collider{})
.add(RenderVoxelGrid{CarAsset, offset})
.add(VoxelCollisionShape(CarAsset))
.add(LocalToWorld{})
.add(Position{glm::vec3{0.0F, 0.0F, -30.0F}})
.add(Rotation{})
.add(PhysicsBundle{.mass = 500.0F, .velocity = {0.0F, 0.0F, 1.0F}})
.entity();
state.aRotationAxis = glm::sphericalRand(1.0F);

state.b = commands.create()
.add(Collider{})
.add(BoxCollisionShape{})
.add(LocalToWorld{})
.add(Position{glm::vec3{0.0F, 0.0F, 10.0F}})
.add(Rotation{})
.add(PhysicsBundle{.mass = 500.0F, .velocity = {0.0F, 0.0F, -1.0F}})
.entity();
state.bRotationAxis = glm::sphericalRand(1.0F);
});

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

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

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

cubos.tag(collisionsSampleUpdated);

cubos.system("render voxel")
.after(collisionsSampleUpdated)
.call([](Gizmos& gizmos, Query<const LocalToWorld&, const Collider&, const VoxelCollisionShape&> query) {
for (auto [localToWorld, collider, shape] : query)
{
for (const auto box : shape.getBoxes())
{
// Get the current position from the localToWorld matrix
glm::mat4 pos = localToWorld.mat; // Store the matrix

// Create a translation matrix for the shift
glm::mat4 shiftMatrix = glm::translate(glm::mat4(1.0f), -box.shift);

// Combine the matrices (note: order matters)
pos = pos * shiftMatrix;
auto size = box.box.halfSize * 2.0F;
glm::mat4 transform = glm::scale(pos * collider.transform, size);
gizmos.drawWireBox("subboxes", transform);
}
}
});

cubos.system("render")
.after(collisionsSampleUpdated)
.call([](Gizmos& gizmos, Query<const LocalToWorld&, const Collider&> query) {
for (auto [localToWorld, collider] : query)
{
auto size = collider.localAABB.box().halfSize * 2.0F;
glm::mat4 transform = glm::scale(localToWorld.mat * collider.transform, size);
gizmos.color({1.0F, 1.0F, 1.0F});
gizmos.drawWireBox("local AABB", transform);

gizmos.color({1.0F, 0.0F, 0.0F});
gizmos.drawWireBox("world AABB", collider.worldAABB.min(), collider.worldAABB.max());
}
});

cubos.run();
return 0;
}
6 changes: 4 additions & 2 deletions engine/src/collisions/interface/shapes/voxel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@

CUBOS_REFLECT_IMPL(cubos::engine::VoxelCollisionShape)
{
return core::ecs::TypeBuilder<VoxelCollisionShape>("cubos::engine::VoxelCollisionShape").build();
}
return core::ecs::TypeBuilder<VoxelCollisionShape>("cubos::engine::VoxelCollisionShape")
.withField("grid", &VoxelCollisionShape::grid)
.build();
}
62 changes: 38 additions & 24 deletions engine/src/collisions/narrow_phase/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,34 +185,36 @@ void cubos::engine::narrowPhaseCollisionsPlugin(Cubos& cubos)
.after(collisionsBroadTag)
.call(
[](Commands cmds,
Query<Entity, const Position&, const LocalToWorld&, const VoxelCollisionShape&,
PotentiallyCollidingWith&, Entity, const Position&, const LocalToWorld&, const BoxCollisionShape&>
Query<Entity, const Position&, const LocalToWorld&, const BoxCollisionShape&, PotentiallyCollidingWith&,
Entity, const Position&, const LocalToWorld&, const VoxelCollisionShape&>
query) {
for (auto [ent1, position1, localToWorld1, voxelShape, potentiallyCollidingWith, ent2, position2,
localToWorld2, boxShape] : query)
for (auto [ent1, position1, localToWorld1, boxShape, potentiallyCollidingWith, ent2, position2,
localToWorld2, voxelShape] : query)
{
cubos::core::geom::Intersection intersectionInfo{};
intersectionInfo.normal = glm::vec3({0.0F});
intersectionInfo.penetration = std::numeric_limits<float>::infinity();

for (const auto box : voxelShape.getBoxes())
{
auto pos1 = localToWorld1.mat;
pos1[3] += glm::vec4(box.shift, 0.0f);
bool intersects = cubos::core::geom::intersects(box.box, pos1, boxShape.box, localToWorld2.mat,
intersectionInfo);
// Get the current position from the localToWorld matrix
glm::mat4 pos2 = localToWorld2.mat; // Store the matrix

if (intersects)
// Create a translation matrix for the shift
glm::mat4 shiftMatrix = glm::translate(glm::mat4(1.0f), -box.shift);

pos2 = pos2 * shiftMatrix;

bool intersects = cubos::core::geom::intersects(boxShape.box, localToWorld1.mat, box.box, pos2,
intersectionInfo);
if (!intersects)
{
cmds.relate(ent1, ent2,
CollidingWith{.entity = ent1,
.entity1OriginalPosition = position1.vec,
.entity2OriginalPosition = position2.vec,
.penetration = intersectionInfo.penetration,
.position = {0.0F, 0.0F, 0.0F},
.normal = intersectionInfo.normal});
break;
continue;
}
cmds.relate(ent1, ent2,
CollidingWith{.entity = ent1,
.entity1OriginalPosition = position1.vec,
.entity2OriginalPosition = position2.vec,
.penetration = intersectionInfo.penetration,
.position = {0.0F, 0.0F, 0.0F},
.normal = intersectionInfo.normal});
}
}
});
Expand All @@ -233,13 +235,25 @@ void cubos::engine::narrowPhaseCollisionsPlugin(Cubos& cubos)

for (const auto box1 : voxelShape1.getBoxes())
{
auto pos1 = localToWorld1.mat;
pos1[3] += glm::vec4(box1.shift, 0.0f);
// Get the current position from the localToWorld matrix
glm::mat4 pos1 = localToWorld1.mat; // Store the matrix

// Create a translation matrix for the shift
glm::mat4 shiftMatrix = glm::translate(glm::mat4(1.0f), -box1.shift);

pos1 = pos1 * shiftMatrix;

bool intersects = false;
for (const auto box2 : voxelShape2.getBoxes())
{
auto pos2 = localToWorld1.mat;
pos2[3] += glm::vec4(box2.shift, 0.0f);
// Get the current position from the localToWorld matrix
glm::mat4 pos2 = localToWorld2.mat; // Store the matrix

// Create a translation matrix for the shift
glm::mat4 shiftMatrix = glm::translate(glm::mat4(1.0f), -box2.shift);

pos2 = pos2 * shiftMatrix;

intersects = cubos::core::geom::intersects(box1.box, pos1, box2.box, pos2, intersectionInfo);

if (intersects)
Expand Down
Loading

0 comments on commit f555261

Please sign in to comment.