From: Daniel Karbach Date: Mon, 23 Feb 2015 17:18:01 +0000 (+0100) Subject: basic aiming X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=4d0ef1687987a0801469c7262f81efd36636605a;hp=ac8765b510707d77cac9620778f40ddf3a4ad2a2;p=blank.git basic aiming --- diff --git a/src/app.cpp b/src/app.cpp index b398e9c..70c45d4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,5 +1,7 @@ #include "app.hpp" +#include "geometry.hpp" + #include #include @@ -234,6 +236,17 @@ void Application::Update(int dt) { cam.OrientationVelocity(vel); cam.Update(dt); + + Ray aim = cam.Aim(); + int blkid; + float dist; + if (chunk.Intersection(aim, glm::mat4(1.0f), &blkid, &dist)) { + glm::vec3 pos = Chunk::ToCoords(blkid); + std::cout << "pointing at: <" << pos.x << ", " << pos.y << ", " << pos.z << ">, " + "distance: " << dist << std::endl; + } else { + std::cout << "pointing at: nothing" << std::endl; + } } void Application::Render() { diff --git a/src/camera.cpp b/src/camera.cpp index fbf10bc..8804d11 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -52,6 +52,15 @@ void Camera::Clip(float near, float far) { UpdateProjection(); } +Ray Camera::Aim() const { + const glm::mat4 inv_vp(glm::inverse(vp)); + glm::vec4 from = inv_vp * glm::vec4(0.0f, 0.0f, -1.0f, 1.0f); + from /= from.w; + glm::vec4 to = inv_vp * glm::vec4(0.0f, 0.0f, 1.0f, 1.0f); + to /= to.w; + return Ray{ glm::vec3(from), glm::normalize(glm::vec3(to - from)) }; +} + void Camera::Update(int dt) { FPSController::Update(dt); diff --git a/src/camera.hpp b/src/camera.hpp index 7cdd5e5..419922a 100644 --- a/src/camera.hpp +++ b/src/camera.hpp @@ -4,6 +4,7 @@ #include #include "controller.hpp" +#include "geometry.hpp" namespace blank { @@ -28,6 +29,8 @@ public: void Aspect(float w, float h); void Clip(float near, float far); + Ray Aim() const; + const glm::mat4 &Projection() { return projection; } const glm::mat4 &View() { return view; } diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000..c5f8069 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,102 @@ +#include "geometry.hpp" + + +namespace blank { + +bool Intersection(const Ray &ray, const AABB &aabb, const glm::mat4 &M, float *dist) { + float t_min = 0.0f; + float t_max = 1.0e5f; + const glm::vec3 aabb_pos(M[3].x, M[3].y, M[3].z); + const glm::vec3 delta = aabb_pos - ray.orig; + + { // X + const glm::vec3 xaxis(M[0].x, M[0].y, M[0].z); + const float e = glm::dot(xaxis, delta); + const float f = glm::dot(ray.dir, xaxis); + + if (std::abs(f) > 0.001f) { + float t1 = (e + aabb.min.x) / f; + float t2 = (e + aabb.max.x) / f; + + if (t1 > t2) { + std::swap(t1, t2); + } + if (t1 > t_min) { + t_min = t1; + } + if (t2 < t_max) { + t_max = t2; + } + if (t_max < t_min) { + return false; + } + } else { + if (aabb.min.x - e > 0.0f || aabb.max.x < 0.0f) { + return false; + } + } + } + + { // Y + const glm::vec3 yaxis(M[1].x, M[1].y, M[1].z); + const float e = glm::dot(yaxis, delta); + const float f = glm::dot(ray.dir, yaxis); + + if (std::abs(f) > 0.001f) { + float t1 = (e + aabb.min.y) / f; + float t2 = (e + aabb.max.y) / f; + + if (t1 > t2) { + std::swap(t1, t2); + } + if (t1 > t_min) { + t_min = t1; + } + if (t2 < t_max) { + t_max = t2; + } + if (t_max < t_min) { + return false; + } + } else { + if (aabb.min.y - e > 0.0f || aabb.max.y < 0.0f) { + return false; + } + } + } + + { // Z + const glm::vec3 zaxis(M[2].x, M[2].y, M[2].z); + const float e = glm::dot(zaxis, delta); + const float f = glm::dot(ray.dir, zaxis); + + if (std::abs(f) > 0.001f) { + float t1 = (e + aabb.min.z) / f; + float t2 = (e + aabb.max.z) / f; + + if (t1 > t2) { + std::swap(t1, t2); + } + if (t1 > t_min) { + t_min = t1; + } + if (t2 < t_max) { + t_max = t2; + } + if (t_max < t_min) { + return false; + } + } else { + if (aabb.min.z - e > 0.0f || aabb.max.z < 0.0f) { + return false; + } + } + } + + if (dist) { + *dist = t_min; + } + return true; +} + +} diff --git a/src/geometry.hpp b/src/geometry.hpp new file mode 100644 index 0000000..e8ead98 --- /dev/null +++ b/src/geometry.hpp @@ -0,0 +1,30 @@ +#ifndef BLANK_GEOMETRY_H_ +#define BLANK_GEOMETRY_H_ + +#include +#include + + +namespace blank { + +struct AABB { + glm::vec3 min; + glm::vec3 max; + + void Adjust() { + if (max.x < min.x) std::swap(max.x, min.x); + if (max.y < min.y) std::swap(max.y, min.y); + if (max.z < min.z) std::swap(max.z, min.z); + } +}; + +struct Ray { + glm::vec3 orig; + glm::vec3 dir; +}; + +bool Intersection(const Ray &, const AABB &, const glm::mat4 &M, float *dist = nullptr); + +} + +#endif diff --git a/src/world.cpp b/src/world.cpp index 96b48ee..c958a65 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,5 +1,7 @@ #include "world.hpp" +#include + namespace blank { @@ -87,6 +89,54 @@ void Chunk::Draw() { } +bool Chunk::Intersection(const Ray &ray, const glm::mat4 &M, int *blkid, float *dist) const { + { // rough check + const AABB bb{{0, 0, 0}, {Width(), Height(), Depth()}}; + if (!blank::Intersection(ray, bb, M)) { + return false; + } + } + + if (!blkid && !dist) { + return true; + } + + // TODO: should be possible to heavily optimize this + int id = 0; + int closest_id = -1; + float closest_dist = std::numeric_limits::infinity(); + for (int z = 0; z < Depth(); ++z) { + for (int y = 0; y < Height(); ++y) { + for (int x = 0; x < Width(); ++x, ++id) { + if (!blocks[id].type->visible) { + continue; + } + const AABB bb{{x, y, z}, {x+1, y+1, z+1}}; + float cur_dist; + if (blank::Intersection(ray, bb, M, &cur_dist)) { + if (cur_dist < closest_dist) { + closest_id = id; + closest_dist = cur_dist; + } + } + } + } + } + + if (closest_id < 0) { + return false; + } + + if (blkid) { + *blkid = closest_id; + } + if (dist) { + *dist = closest_dist; + } + return true; +} + + int Chunk::VertexCount() const { // TODO: query blocks as soon as type shapes are implemented return Size() * 6 * 6; diff --git a/src/world.hpp b/src/world.hpp index 58f7a25..b7ed84b 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -2,6 +2,7 @@ #define BLANK_WORLD_HPP_ #include "model.hpp" +#include "geometry.hpp" #include #include @@ -95,6 +96,8 @@ public: Block &BlockAt(const glm::vec3 &pos) { return blocks[ToIndex(pos)]; } const Block &BlockAt(const glm::vec3 &pos) const { return blocks[ToIndex(pos)]; } + bool Intersection(const Ray &, const glm::mat4 &M, int *blkid = nullptr, float *dist = nullptr) const; + void Draw(); private: