Compare commits

...

3 commits

Author SHA1 Message Date
ba241417a2 Use Raylib's Ray/Triangle collision fn
All checks were successful
Build and Publish WASM version of demo / Build-And-Deploy (push) Successful in 16s
2023-08-09 14:00:54 +09:00
7f73388943 Refactorings
Use bounding boxes for collision checks, and only check collision
against triangles when bounding box collides.

Use const where applicable.
2023-08-09 13:54:56 +09:00
cab92d140b Clamp dt: mitigate weird regain focus behavior 2023-08-09 13:39:43 +09:00
5 changed files with 48 additions and 43 deletions

View file

@ -160,30 +160,3 @@ std::optional<Vector3> ray_to_plane(const Ray &ray, const Ray &plane) {
ray.position.y + ray.direction.y * amount,
ray.position.z + ray.direction.z * amount};
}
std::optional<Vector3> ray_collision_triangle(const Ray &ray, const Vector3 &a,
const Vector3 &b,
const Vector3 &c) {
const Vector3 ab = Vector3Subtract(a, b);
const Vector3 cb = Vector3Subtract(c, b);
Vector3 ortho = Vector3CrossProduct(ab, cb);
ortho = Vector3Normalize(ortho);
Ray plane{.position = b, .direction = ortho};
auto result = ray_to_plane(ray, plane);
if (!result.has_value()) {
return std::nullopt;
}
Vector3 bary = Vector3Barycenter(result.value(), a, b, c);
if (bary.x >= 0.0F && bary.x <= 1.0F && bary.y >= 0.0F && bary.y <= 1.0F &&
bary.z >= 0.0F && bary.z <= 1.0F) {
float sum = bary.x + bary.y + bary.z;
if (sum > 0.999F && sum < 1.001) {
return result;
}
}
return std::nullopt;
}

View file

@ -27,11 +27,6 @@ extern bool ray_to_xz_plane(const Ray &ray, float &x_out, float &z_out);
/// plane.direction is plane normal, plane.position is position on plane.
extern std::optional<Vector3> ray_to_plane(const Ray &ray, const Ray &plane);
extern std::optional<Vector3> ray_collision_triangle(const Ray &ray,
const Vector3 &a,
const Vector3 &b,
const Vector3 &c);
// Unimplemented as this function isn't really needed and it exposes some
// weirdness regarding column-major matrices.
// extern Vector4 operator*(const Matrix &m, const Vector4 &v);

View file

@ -3,6 +3,9 @@
// local includes
#include "screen_trunner.h"
// third party includes
#include <raymath.h>
Game::Game()
: screen_stack(ScreenStack::new_instance()),
prev_time(std::chrono::steady_clock::now()) {
@ -14,7 +17,7 @@ void Game::update() {
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
next_time - prev_time);
prev_time = next_time;
screen_stack->update(((float)duration.count()) / 1000000);
screen_stack->update(Clamp(((float)duration.count()) / 1000000, 0.0F, 1.0F));
}
void Game::draw() { screen_stack->draw(); }

View file

@ -159,6 +159,38 @@ TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
}
surface.at(idx) = current;
// Calculate bounding boxes.
int x = idx % SURFACE_UNIT_WIDTH;
int y = idx / SURFACE_UNIT_WIDTH;
float xf = (float)(x)-SURFACE_X_OFFSET;
float zf = (float)(y)-SURFACE_Y_OFFSET;
surface_bbs.at(idx).min.x = xf - 0.5F;
surface_bbs.at(idx).min.z = zf - 0.5F;
surface_bbs.at(idx).max.x = xf + 0.5F;
surface_bbs.at(idx).max.z = zf + 0.5F;
surface_bbs.at(idx).min.y = current.nw;
if (current.ne < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.ne;
}
if (current.sw < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.sw;
}
if (current.se < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.se;
}
surface_bbs.at(idx).max.y = current.nw;
if (current.ne > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.ne;
}
if (current.sw > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.sw;
}
if (current.se > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.se;
}
}
#ifndef NDEBUG
@ -207,7 +239,7 @@ bool TRunnerScreen::update(float dt) {
#ifndef NDEBUG
std::cout << "idx_hit set to " << idx_hit << std::endl;
#endif
this->mouse_hit = collision.value();
this->mouse_hit = collision;
this->camera_target.x = xf;
this->camera_target.y =
@ -226,14 +258,15 @@ bool TRunnerScreen::update(float dt) {
}
};
if (auto collision = ray_collision_triangle(ray, nw, sw, ne);
collision.has_value()) {
on_collide_fn(collision);
break;
} else if (auto collision = ray_collision_triangle(ray, ne, sw, se);
collision.has_value()) {
on_collide_fn(collision);
break;
if (auto bb_collision = GetRayCollisionBox(ray, surface_bbs[idx]);
bb_collision.hit) {
if (auto collision = GetRayCollisionTriangle(ray, nw, sw, ne);
collision.hit) {
on_collide_fn(collision.point);
} else if (auto collision = GetRayCollisionTriangle(ray, ne, sw, se);
collision.hit) {
on_collide_fn(collision.point);
}
}
}
}
@ -260,7 +293,7 @@ bool TRunnerScreen::draw() {
? RAYWHITE
: Color{(unsigned char)(200 + ox * 2),
(unsigned char)(150 + oy * 2), 20, 255};
auto &current = surface[idx].value();
const auto &current = surface[idx].value();
DrawTriangle3D(Vector3{xf - 0.5F, current.nw, zf - 0.5F},
Vector3{xf - 0.5F, current.sw, zf + 0.5F},
Vector3{xf + 0.5F, current.ne, zf - 0.5F}, color);

View file

@ -56,6 +56,7 @@ class TRunnerScreen : public Screen {
std::array<std::optional<SurfaceUnit>,
SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT>
surface;
std::array<BoundingBox, SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT> surface_bbs;
Camera3D camera;
std::bitset<64> flags;
Model TEMP_cube_model;