summary refs log tree commit diff
path: root/src/World/VoxelTraversal.hpp
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-02-02 03:03:36 +0100
committerMel <einebeere@gmail.com>2024-02-02 03:03:36 +0100
commit250e37c742f3ad46f093f4534098cdf8f68a29a9 (patch)
tree29bb86a24e5a987959a455cae13818cf0def8646 /src/World/VoxelTraversal.hpp
parent7b061aee2b4c15d242bb9f18101d6b9ea776c5cd (diff)
downloadmeowcraft-250e37c742f3ad46f093f4534098cdf8f68a29a9.tar.zst
meowcraft-250e37c742f3ad46f093f4534098cdf8f68a29a9.zip
Breaking blocks
Diffstat (limited to 'src/World/VoxelTraversal.hpp')
-rw-r--r--src/World/VoxelTraversal.hpp60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/World/VoxelTraversal.hpp b/src/World/VoxelTraversal.hpp
new file mode 100644
index 0000000..1638901
--- /dev/null
+++ b/src/World/VoxelTraversal.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "../Common/Casts.hpp"
+#include "../Math/Ray.hpp"
+#include "Position.hpp"
+
+namespace MC::World::VoxelTraversal {
+
+// Amanatides, John, and Andrew Woo. 1987.
+// "A Fast Voxel Traversal Algorithm for Ray Tracing."
+// https://doi.org/10.2312/EGTP.19871000.
+template <typename P>
+Position::BlockWorld traverse(Ray ray, Real max_distance, P&& predicate) {
+    // Find the voxel grid cell containing the origin of the ray.
+    Position::BlockWorld block_pos = Position::World(ray.origin).round_to_block();
+    Position::BlockWorldOffset const step = {
+        Math::sign(ray.direction.x()),
+        Math::sign(ray.direction.y()),
+        Math::sign(ray.direction.z()),
+    };
+
+    Position::WorldOffset t_max = {
+        (TO(Real, block_pos.x()) + TO(Real, step.x() > 0) - ray.origin.x()) / ray.direction.x(),
+        (TO(Real, block_pos.y()) + TO(Real, step.y() > 0) - ray.origin.y()) / ray.direction.y(),
+        (TO(Real, block_pos.z()) + TO(Real, step.z() > 0) - ray.origin.z()) / ray.direction.z()
+    };
+
+    Position::WorldOffset const t_delta = {
+        TO(Real, step.x()) / ray.direction.x(),
+        TO(Real, step.y()) / ray.direction.y(),
+        TO(Real, step.z()) / ray.direction.z()
+    };
+
+    while (!predicate(block_pos)) {
+        // TODO: Calculate distance exactly.
+        if (ray.origin.distance(Vec3(block_pos)) > max_distance) return {};
+
+        if (t_max.x() < t_max.y()) {
+            if (t_max.x() < t_max.z()) {
+                block_pos.x() += step.x();
+                t_max.x() += t_delta.x();
+            } else {
+                block_pos.z() += step.z();
+                t_max.z() += t_delta.z();
+            }
+        } else {
+            if (t_max.y() < t_max.z()) {
+                block_pos.y() += step.y();
+                t_max.y() += t_delta.y();
+            } else {
+                block_pos.z() += step.z();
+                t_max.z() += t_delta.z();
+            }
+        }
+    }
+
+    return block_pos;
+}
+
+}