Non functional collision

This commit is contained in:
tovjemam 2025-08-10 18:45:06 +02:00
parent d10ffb17f0
commit 30d70e178e
10 changed files with 241 additions and 30 deletions

View File

@ -1,6 +1,7 @@
#include "app.hpp" #include "app.hpp"
#include <iostream> #include <iostream>
#include "collision/capsule_triangle_sweep.hpp"
App::App() App::App()
{ {
@ -21,27 +22,140 @@ App::App()
world_.LinkPortals(s1, "NDoor", s2, "WDoor"); world_.LinkPortals(s1, "NDoor", s2, "WDoor");
world_.LinkPortals(s2, "NDoor", s2, "SDoor"); world_.LinkPortals(s2, "NDoor", s2, "SDoor");
player_ = world_.Spawn<game::Entity>(s1, glm::vec3(0.0f, 0.0f, 1.0f));
} }
void App::Frame() void App::Frame()
{ {
float aspect = static_cast<float>(m_viewport_size.x) / static_cast<float>(m_viewport_size.y); float delta_time = time_ - prev_time_;
prev_time_ = time_;
renderer_.Begin(m_viewport_size.x, m_viewport_size.y); if (delta_time < 0.0f)
{
delta_time = 0.0f; // Prevent negative delta time
}
else if (delta_time > 0.1f)
{
delta_time = 0.1f; // Cap delta time to avoid large jumps
}
float cameraDistance = 2.0f; float aspect = static_cast<float>(viewport_size_.x) / static_cast<float>(viewport_size_.y);
float angle = m_time * 0.1f; // Rotate over time
renderer_.Begin(viewport_size_.x, viewport_size_.y);
//float cameraDistance = 2.0f;
//float angle = time_ * 0.1f; // Rotate over time
//
//glm::vec3 cameraPos = glm::vec3(
// cameraDistance * cos(angle),
// cameraDistance * sin(angle),
// cameraDistance * 0.13f
//);
//glm::vec3 center(0.0f, 0.0f, 1.5f);
//glm::vec3 up(0.0f, 0.0f, 1.0f);
//renderer_.DrawWorld(world_, 1, center + cameraPos, -cameraPos, up, aspect, 60.0f);
static glm::vec3 position(0.0f, 0.0f, 1.5f);
glm::vec3 velocity(0.0f);
if (input_ & game::PI_FORWARD)
velocity.y += 1.0f;
if (input_ & game::PI_BACKWARD)
velocity.y -= 1.0f;
if (input_ & game::PI_LEFT)
velocity.x -= 1.0f;
if (input_ & game::PI_RIGHT)
velocity.x += 1.0f;
if (input_ & game::PI_JUMP)
velocity.z += 1.0f;
if (input_ & game::PI_CROUCH)
velocity.z -= 1.0f;
//velocity.z = -1.0f;
glm::vec3 cameraDir = glm::vec3(1.0f, 0.0f, 0.0f);
auto tris = world_.GetSector(0).GetMesh()->GetCollisionMesh()->GetTriangles();
glm::vec3 cameraPos = glm::vec3( glm::vec3 c0 = position;
cameraDistance * cos(angle), c0.z -= 0.1f;
cameraDistance * sin(angle), glm::vec3 c1 = position;
cameraDistance * 0.13f c1.z += 0.1f;
);
glm::vec3 center(0.0f, 0.0f, 1.5f);
glm::vec3 up(0.0f, 0.0f, 1.0f);
renderer_.DrawWorld(world_, 1, center + cameraPos, -cameraPos, up, aspect, 60.0f); bool found = false;
glm::vec3 u = velocity * delta_time;
if (glm::length(velocity) > 0.001f)
{
//velocity = glm::normalize(velocity);
//collision::ResolveCollisions(
// position,
// velocity,
// 0.5f,
// 0.2f,
// delta_time,
// tris
//);
Sweep sweep;
static std::vector<collision::Triangle> sweep_tris;
sweep_tris.clear();
for (const auto& tri : tris) {
float dot = glm::dot(tri.verts[1] - tri.verts[0], tri.verts[2] - tri.verts[0]);
if (glm::abs(dot) < 0.001f) {
printf("degen!!!!!!!!!\n");
continue; // Skip degenerate triangles
}
//found = found || collision::SweepCapsuleTriangle(
// sweep,
// c0,
// c1,
// 0.2f,
// u,
// tri.verts[0], tri.verts[1], tri.verts[2]
//);
sweep_tris.push_back(tri);
}
collision::ResolveCollisions(
position,
velocity,
0.5f, // Capsule radius
0.2f, // Capsule height
delta_time,
sweep_tris
);
}
if (!found)
{
position += velocity * delta_time;
}
printf("position: %.2f, %.2f, %.2f\n", position.x, position.y, position.z);
printf("found: %s\n", found ? "true" : "false");
renderer_.DrawWorld(world_, 0, position, cameraDir, glm::vec3(0.0f, 0.0f, 1.0f), aspect, 60.0f);
}
void App::MouseMove(const glm::vec2& delta)
{
} }

View File

@ -3,14 +3,19 @@
#include "assets/sectordef.hpp" #include "assets/sectordef.hpp"
#include "game/world.hpp" #include "game/world.hpp"
#include "game/player_input.hpp"
#include "gfx/renderer.hpp" #include "gfx/renderer.hpp"
class App class App
{ {
float m_time = 0.0f; float time_ = 0.0f;
glm::ivec2 m_viewport_size = { 800, 600 }; glm::ivec2 viewport_size_ = { 800, 600 };
game::PlayerInputFlags input_ = 0;
float prev_time_ = 0.0f;
game::World world_; game::World world_;
game::Entity* player_ = nullptr;
gfx::Renderer renderer_; gfx::Renderer renderer_;
@ -19,8 +24,10 @@ public:
void Frame(); void Frame();
void SetTime(float time) { m_time = time; } void SetTime(float time) { time_ = time; }
void SetViewportSize(int width, int height) { m_viewport_size = { width, height }; } void SetViewportSize(int width, int height) { viewport_size_ = { width, height }; }
void SetInput(game::PlayerInputFlags input) { input_ = input; }
void MouseMove(const glm::vec2& delta);
~App(); ~App();
}; };

View File

@ -2,14 +2,6 @@
#define EPSILON 1e-5f // Used to test if float is close to 0. Tweak this if you get problems. #define EPSILON 1e-5f // Used to test if float is close to 0. Tweak this if you get problems.
struct Sweep
{
float time; // Non-negative time of first contact.
float depth; // Non-negative penetration depth if objects start initially colliding.
glm::vec3 point; // Point of first-contact. Only updated when contact occurs.
glm::vec3 normal; // Unit-length collision normal. Only updated when contact occurs.
};
// Return whether point P is contained inside 3D region delimited by triangle T0,T1,T2 edges. // Return whether point P is contained inside 3D region delimited by triangle T0,T1,T2 edges.
static bool PointInsideTriangle(const glm::vec3& p, const glm::vec3& t0, const glm::vec3& t1, const glm::vec3& t2) static bool PointInsideTriangle(const glm::vec3& p, const glm::vec3& t0, const glm::vec3& t1, const glm::vec3& t2)
{ {
@ -59,8 +51,8 @@ static bool PointInsideTriangularPrism(
glm::vec3 faces[5][3] = { { a0,a1,a2 }, { b0,b2,b1 }, { a0,b0,a1 }, { a1,b1,a2 }, { a2,b2,a0 } }; glm::vec3 faces[5][3] = { { a0,a1,a2 }, { b0,b2,b1 }, { a0,b0,a1 }, { a1,b1,a2 }, { a2,b2,a0 } };
float sgn = 0; float sgn = 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
const glm::vec3& p0 = faces[i][0]; const glm::vec3& p0 = faces[i][1];
const glm::vec3& p1 = faces[i][1]; const glm::vec3& p1 = faces[i][0];
const glm::vec3& p2 = faces[i][2]; const glm::vec3& p2 = faces[i][2];
// Check which side of plane point is in. If it's always on the same side, it's colliding. // Check which side of plane point is in. If it's always on the same side, it's colliding.
@ -284,7 +276,7 @@ static bool SweepPointUncappedCylinder(
// v capsule velocity // v capsule velocity
// t0,t1,t2 3 triangle vertices // t0,t1,t2 3 triangle vertices
// returns whether the capsule and triangle intersect // returns whether the capsule and triangle intersect
static bool SweepCapsuleTriangle( bool collision::SweepCapsuleTriangle(
Sweep& s, Sweep& s,
const glm::vec3& c0, const glm::vec3& c0,
const glm::vec3& c1, const glm::vec3& c1,
@ -398,7 +390,7 @@ static bool SweepCapsuleTriangle(
// r - capsule radius // r - capsule radius
// dt - time-step length // dt - time-step length
// triangles - list of triangles to collide with // triangles - list of triangles to collide with
void ResolveCollisions(glm::vec3& p, glm::vec3& v, float h, float r, float dt, std::span<collision::Triangle> triangles) { void collision::ResolveCollisions(glm::vec3& p, glm::vec3& v, float h, float r, float dt, std::span<const collision::Triangle> triangles) {
// Store the leftover movement in this vector. // Store the leftover movement in this vector.
glm::vec3 u = dt * v; glm::vec3 u = dt * v;

View File

@ -3,7 +3,26 @@
#include "capsule.hpp" #include "capsule.hpp"
#include "trianglemesh.hpp" #include "trianglemesh.hpp"
struct Sweep
{
float time = 1.0f; // Non-negative time of first contact.
float depth = 0.0f; // Non-negative penetration depth if objects start initially colliding.
glm::vec3 point = glm::vec3(0.0f); // Point of first-contact. Only updated when contact occurs.
glm::vec3 normal = glm::vec3(0.0f); // Unit-length collision normal. Only updated when contact occurs.
};
namespace collision namespace collision
{ {
bool SweepCapsuleTriangle(
Sweep& s,
const glm::vec3& c0,
const glm::vec3& c1,
float r,
const glm::vec3& v,
const glm::vec3& t0,
const glm::vec3& t1,
const glm::vec3& t2);
void ResolveCollisions(glm::vec3& p, glm::vec3& v, float h, float r, float dt, std::span<const collision::Triangle> triangles);
} }

6
src/game/entity.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "entity.hpp"
game::Entity::Entity(World* world, size_t sector_idx, const glm::vec3& position)
{
}

View File

@ -1,9 +1,36 @@
#pragma once #pragma once
#include <memory>
#include "sector.hpp"
namespace game namespace game
{ {
class World;
class EntityOccurrence
{
const Sector* sector_;
float radius_;
glm::vec3 position_;
glm::vec3 up_;
glm::mat3 trans_;
glm::mat3 inv_trans_;
};
class Entity class Entity
{ {
World* world_;
std::unique_ptr<EntityOccurrence> occu_;
std::unique_ptr<EntityOccurrence> other_occu_;
glm::vec3 velocity_;
public:
Entity(World* world, size_t sector_idx, const glm::vec3& position);
}; };

18
src/game/player_input.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
namespace game
{
enum PlayerInput
{
PI_FORWARD = 1 << 0,
PI_BACKWARD = 1 << 1,
PI_LEFT = 1 << 2,
PI_RIGHT = 1 << 3,
PI_JUMP = 1 << 4,
PI_CROUCH = 1 << 5,
PI_USE = 1 << 6,
PI_ATTACK = 1 << 7,
};
using PlayerInputFlags = unsigned int;
}

View File

@ -132,7 +132,7 @@ void gfx::Renderer::DrawSector(const DrawSectorParams& params)
void gfx::Renderer::DrawPortal(const DrawSectorParams& params, const game::Portal& portal) void gfx::Renderer::DrawPortal(const DrawSectorParams& params, const game::Portal& portal)
{ {
if (params.recursion > 10) if (params.recursion > max_portal_recursion_)
{ {
return; // Recursion limit reached return; // Recursion limit reached
} }

View File

@ -42,6 +42,8 @@ namespace gfx
std::shared_ptr<VertexArray> portal_vao_; std::shared_ptr<VertexArray> portal_vao_;
void SetupPortalVAO(); void SetupPortalVAO();
size_t max_portal_recursion_ = 24;
glm::mat4 proj_; glm::mat4 proj_;
void DrawSector(const DrawSectorParams& params); void DrawSector(const DrawSectorParams& params);

View File

@ -94,7 +94,7 @@ static bool InitGL()
glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(GLDebugCallback, 0); glDebugMessageCallback(GLDebugCallback, 0);
SDL_GL_SetSwapInterval(0); SDL_GL_SetSwapInterval(1);
#endif #endif
@ -143,6 +143,32 @@ static void Frame()
int width, height; int width, height;
SDL_GetWindowSize(s_window, &width, &height); SDL_GetWindowSize(s_window, &width, &height);
s_app->SetViewportSize(width, height); s_app->SetViewportSize(width, height);
game::PlayerInputFlags input = 0;
const uint8_t* state = SDL_GetKeyboardState(nullptr);
if (state[SDL_GetScancodeFromKey(SDLK_w)])
input |= game::PI_FORWARD;
if (state[SDL_GetScancodeFromKey(SDLK_s)])
input |= game::PI_BACKWARD;
if (state[SDL_GetScancodeFromKey(SDLK_a)])
input |= game::PI_LEFT;
if (state[SDL_GetScancodeFromKey(SDLK_d)])
input |= game::PI_RIGHT;
if (state[SDL_GetScancodeFromKey(SDLK_SPACE)])
input |= game::PI_JUMP;
if (state[SDL_GetScancodeFromKey(SDLK_LCTRL)])
input |= game::PI_CROUCH;
if (state[SDL_GetScancodeFromKey(SDLK_e)])
input |= game::PI_USE;
s_app->SetInput(input);
s_app->Frame(); s_app->Frame();
SDL_GL_SwapWindow(s_window); SDL_GL_SwapWindow(s_window);