diff options
| author | Mel <einebeere@gmail.com> | 2024-02-02 16:16:25 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2024-02-02 16:16:25 +0100 |
| commit | a4a61ac2e6389af0968ac4fb305b82c6eb90bf0e (patch) | |
| tree | 800749ed6a5d503837a6bf0c389c133fcb59143d /src/World/VoxelTraversal.hpp | |
| parent | 250e37c742f3ad46f093f4534098cdf8f68a29a9 (diff) | |
| download | meowcraft-a4a61ac2e6389af0968ac4fb305b82c6eb90bf0e.tar.zst meowcraft-a4a61ac2e6389af0968ac4fb305b82c6eb90bf0e.zip | |
Placing blocks
Diffstat (limited to 'src/World/VoxelTraversal.hpp')
| -rw-r--r-- | src/World/VoxelTraversal.hpp | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/src/World/VoxelTraversal.hpp b/src/World/VoxelTraversal.hpp index 1638901..08a53eb 100644 --- a/src/World/VoxelTraversal.hpp +++ b/src/World/VoxelTraversal.hpp @@ -6,11 +6,22 @@ namespace MC::World::VoxelTraversal { +struct TraversalResult { + // Whether the ray hit a block. + Bool hit{}; + // The block that was hit. + Position::BlockWorld block; + // The vector from the ray origin to where the block that was hit. + Position::WorldOffset approach; + // The normal of the collision. + Position::BlockWorldOffset normal; +}; + // 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) { +TraversalResult traverse(Ray ray, P&& predicate, Real max_distance = 0) { // 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 = { @@ -31,30 +42,48 @@ Position::BlockWorld traverse(Ray ray, Real max_distance, P&& predicate) { TO(Real, step.z()) / ray.direction.z() }; + // The original algorithm does not mention calculating the normal of the + // block that was hit. When we increment t_max to a collision on one of the axes + // of the voxel grid, the axis gives us the normal of the current block. + Position::BlockWorldOffset normal = {}; + + // Also not mentioned in the original algorithm, but we need to keep track of + // how far along we have traversed the voxel grid. + // This just means we add the direction of the ray at the axis we have progressed along. + Position::WorldOffset approach = {}; + while (!predicate(block_pos)) { - // TODO: Calculate distance exactly. - if (ray.origin.distance(Vec3(block_pos)) > max_distance) return {}; + if (max_distance > 0 && approach.magnitude() > 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(); + normal = {-step.x(), 0, 0}; + approach.x() += ray.direction.x(); } else { block_pos.z() += step.z(); t_max.z() += t_delta.z(); + normal = {0, 0, -step.z()}; + approach.z() += ray.direction.z(); } } else { if (t_max.y() < t_max.z()) { block_pos.y() += step.y(); t_max.y() += t_delta.y(); + normal = {0, -step.y(), 0}; + approach.y() += ray.direction.y(); } else { block_pos.z() += step.z(); t_max.z() += t_delta.z(); + normal = {0, 0, -step.z()}; + approach.z() += ray.direction.z(); } } } - return block_pos; + return {true, block_pos, approach, normal}; } } |
