diff --git a/ECS/Systems/CollisionSystem.h b/ECS/Systems/CollisionSystem.h index 368baf7..adaa947 100644 --- a/ECS/Systems/CollisionSystem.h +++ b/ECS/Systems/CollisionSystem.h @@ -8,6 +8,8 @@ #include "../Components/Transform.h" #include "../ECS.h" +#include + using namespace ECS; class CollisionSystem : public EntitySystem { @@ -16,7 +18,6 @@ class CollisionSystem : public EntitySystem { // Initialize the kdtree void build() { - std::vector triangles; std::vector points; // ObjMesh @@ -25,7 +26,11 @@ class CollisionSystem : public EntitySystem { std::vector indices = mesh->indices; std::vector vertices = mesh->vertices; + std::map triangle_map; + + // TODO: Iterate over vertices, add triangles by also iterating over indices for (int i = 0; i < mesh->vertex_count; i += 3) { + // Build vertices from this triangle float v0p0 = vertices[indices[i + 0] * 14 + 0]; float v0p1 = vertices[indices[i + 0] * 14 + 1]; float v0p2 = vertices[indices[i + 0] * 14 + 2]; @@ -53,12 +58,30 @@ class CollisionSystem : public EntitySystem { Vector v3(v3glm.x, v3glm.y, v3glm.z); Triangle *triangle = new Triangle(v1, v2, v3); - triangles.emplace_back(triangle); - points.emplace_back(new Point(v1, triangle)); - points.emplace_back(new Point(v2, triangle)); - points.emplace_back(new Point(v3, triangle)); + if (triangle_map.count(v1) == 0) { + triangle_map[v1] = new Point(v1, std::list{triangle}); + } else { + triangle_map[v1]->triangles.emplace_back(triangle); + } + + if (triangle_map.count(v2) == 0) { + triangle_map[v2] = new Point(v2, std::list{triangle}); + } else { + triangle_map[v2]->triangles.emplace_back(triangle); + } + + if (triangle_map.count(v3) == 0) { + triangle_map[v3] = new Point(v3, std::list{triangle}); + } else { + triangle_map[v3]->triangles.emplace_back(triangle); + } } + + // Convert to list + std::transform( + triangle_map.begin(), triangle_map.end(), back_inserter(points), + [](const std::map::value_type &val) { return val.second; }); }); // LODObjMesh @@ -70,8 +93,6 @@ class CollisionSystem : public EntitySystem { std::cout << "Start building kdtree with " << points.size() << " points" << std::endl; kdtree = new KDTree(points); std::cout << "Done" << std::endl; - - std::cout << kdtree->to_string() << std::endl; } void tick(World *pWorld, float deltaTime) override { @@ -86,7 +107,7 @@ class CollisionSystem : public EntitySystem { Ray ray(origin, direction); Vector collision_position(0, 0, 0); - Triangle *result = kdtree->intersect_ray(ray, collision_position); + const Triangle *result = kdtree->intersect_ray(ray, collision_position); if (result) { // Output to console diff --git a/Util/geometry.h b/Util/geometry.h index 9c28655..f52683f 100644 --- a/Util/geometry.h +++ b/Util/geometry.h @@ -1,5 +1,6 @@ #pragma once +#include #include // Forward declarations @@ -21,6 +22,14 @@ struct Vector { return Vector(c[0] - other.c[0], c[1] - other.c[1], c[2] - other.c[2]); } + bool operator<(const Vector &other) const { + if ((c[2] < other.c[2])) { return true; } + if ((c[2] == other.c[2]) && (c[1] < other.c[1])) { return true; } + if ((c[2] == other.c[2]) && (c[1] == other.c[1]) && (c[0] < other.c[0])) { return true; } + + return false; + } + Vector operator*(float scalar) const { return Vector(c[0] * scalar, c[1] * scalar, c[2] * scalar); } @@ -36,18 +45,22 @@ struct Vector { }; struct Point { - Point(Vector pos, Triangle *triangle) : pos(pos), triangle(triangle) {} + Point(Vector pos) : pos(pos) {} + + Point(Vector pos, std::list triangles) : pos(pos), triangles(triangles) {} Vector pos; - Triangle *triangle; + std::list triangles; }; struct Triangle { Triangle(Vector p1, Vector p2, Vector p3) : p1(p1), p2(p2), p3(p3) {} std::vector create_point_objects() { - return std::vector{new Point(p1, this), new Point(p2, this), new Point(p3, this)}; + return std::vector{new Point(p1, std::list{this}), + new Point(p2, std::list{this}), + new Point(p3, std::list{this})}; } Vector p1; @@ -74,7 +87,7 @@ struct Ray { Vector direction; - bool intersects_triangle(Triangle *triangle, Vector &result) { + bool intersects_triangle(const Triangle *triangle, Vector &result, float &t) { // Ray-triangle-intersection with the Möller–Trumbore algorithm // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm const float EPSILON = 0.0000001; @@ -103,7 +116,7 @@ struct Ray { // At this stage we can compute t to find out where the intersection point is on the // line. - float t = f * edge2.dot(q); + t = f * edge2.dot(q); if (t > EPSILON) { result = origin + direction * t; return true; diff --git a/Util/kdtree.h b/Util/kdtree.h index 24ff907..c55c0b4 100644 --- a/Util/kdtree.h +++ b/Util/kdtree.h @@ -11,7 +11,7 @@ class KDTree { ~KDTree() = default; // TODO: Delete all allocated Nodes - Triangle *intersect_ray(Ray ray, Vector &result) { + const Triangle *intersect_ray(const Ray ray, Vector &result) { return intersect_ray_recurse(result, ray, root, 1000.0, 0); } @@ -87,8 +87,8 @@ class KDTree { build(right_of_median, depth + 1)); } - Triangle *intersect_ray_recurse(Vector &result, Ray ray, Node *node, float max_distance, - int depth) { + const Triangle *intersect_ray_recurse(Vector &result, Ray ray, Node *node, float max_distance, + int depth) { // Exit condition: There was no collision if (node == nullptr) { return nullptr; } @@ -108,18 +108,32 @@ class KDTree { ? (node->point->pos[node->axis] - ray.origin[node->axis]) / ray.direction[node->axis] : max_distance; - Triangle *near_result = intersect_ray_recurse(result, ray, near, t, depth + 1); + const Triangle *near_result = intersect_ray_recurse(result, ray, near, t, depth + 1); // If the nearer segment had a collision, we're done! We're only interested in the closest // collision. if (near_result != nullptr) { return near_result; } // No collision in the nearer side, so check for a collision directly here - if (ray.intersects_triangle(node->point->triangle, result)) { - // We do have a collision here, so we're done and can return this point! - return node->point->triangle; + float nearest = 100000; // FIXME + const Triangle *nearest_triangle = nullptr; + + for (const Triangle *triangle : node->point->triangles) { + Vector current_result(0, 0, 0); + float current_distance; + if (ray.intersects_triangle(triangle, current_result, current_distance)) { + std::cout << "tested with " << current_distance << std::endl; + + if (current_distance < nearest) { + nearest = current_distance; + nearest_triangle = triangle; + result = current_result; + } + } } + if (nearest_triangle) { return nearest_triangle; } + // No collision here either. Does it make sense to also check the far node? // Only if the axes are not parallel and if that area is not behind us if (ray.direction[node->axis] != 0.0) { // FIXME: should include && t >= 0.0