Browse Source

Add new geometric primitive types. Improve terrain mesh calculation. Update C++ version to C++20

master
C. J. Howard 2 years ago
parent
commit
444c46a226
25 changed files with 1049 additions and 106 deletions
  1. +3
    -7
      CMakeLists.txt
  2. +5
    -5
      src/color/cat.hpp
  3. +4
    -8
      src/game/ant/swarm.cpp
  4. +2
    -2
      src/game/component/picking.hpp
  5. +14
    -0
      src/game/load.cpp
  6. +1
    -1
      src/game/state/boot.cpp
  7. +9
    -1
      src/game/state/nuptial-flight.cpp
  8. +10
    -13
      src/game/system/collision.cpp
  9. +2
    -2
      src/game/system/collision.hpp
  10. +88
    -63
      src/game/system/terrain.cpp
  11. +3
    -1
      src/game/system/terrain.hpp
  12. +35
    -0
      src/geom/primitive/box.hpp
  13. +35
    -0
      src/geom/primitive/circle.hpp
  14. +75
    -0
      src/geom/primitive/hyperplane.hpp
  15. +162
    -0
      src/geom/primitive/hyperrectangle.hpp
  16. +139
    -0
      src/geom/primitive/hypersphere.hpp
  17. +199
    -0
      src/geom/primitive/intersection.hpp
  18. +59
    -0
      src/geom/primitive/line-segment.hpp
  19. +35
    -0
      src/geom/primitive/line.hpp
  20. +35
    -0
      src/geom/primitive/plane.hpp
  21. +61
    -0
      src/geom/primitive/ray.hpp
  22. +35
    -0
      src/geom/primitive/rectangle.hpp
  23. +35
    -0
      src/geom/primitive/sphere.hpp
  24. +1
    -1
      src/scene/camera.cpp
  25. +2
    -2
      src/scene/camera.hpp

+ 3
- 7
CMakeLists.txt View File

@ -77,15 +77,11 @@ else()
target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE NDEBUG) target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE NDEBUG)
endif() endif()
# Set C++17 standard
# Set C++20 standard
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES set_target_properties(${EXECUTABLE_TARGET} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF) CXX_EXTENSIONS OFF)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "-std=c++17")
elseif(MSVC)
set_target_properties(${EXECUTABLE_TARGET} PROPERTIES COMPILE_FLAGS "/std:c++17")
endif()
# Set link flags to show console window on debug builds and hide it on release builds # Set link flags to show console window on debug builds and hide it on release builds
if(MSVC) if(MSVC)

+ 5
- 5
src/color/cat.hpp View File

@ -49,8 +49,8 @@ constexpr math::matrix bradford =
template <class T> template <class T>
constexpr math::matrix<T, 3, 3> von_kries = constexpr math::matrix<T, 3, 3> von_kries =
{ {
0.40024, -0.22630, 0.00000
0.70760, 1.16532, 0.00000
0.40024, -0.22630, 0.00000,
0.70760, 1.16532, 0.00000,
-0.08081, 0.04570, 0.91822 -0.08081, 0.04570, 0.91822
}; };
@ -62,9 +62,9 @@ constexpr math::matrix von_kries =
template <class T> template <class T>
constexpr math::matrix<T, 3, 3> xyz_scaling = constexpr math::matrix<T, 3, 3> xyz_scaling =
{ {
T{1}, T{0}. T{0},
T{0}, T{1}. T{0},
T{0}, T{0}. T{1}
T{1}, T{0}, T{0},
T{0}, T{1}, T{0},
T{0}, T{0}, T{1}
}; };
/** /**

+ 4
- 8
src/game/ant/swarm.cpp View File

@ -40,15 +40,11 @@ static math::vector3 sphere_random(Generator& rng)
{ {
const std::uniform_real_distribution<T> distribution(T{-1}, T{1}); const std::uniform_real_distribution<T> distribution(T{-1}, T{1});
const T x = distribution(rng);
const T y = distribution(rng);
const T z = distribution(rng);
math::vector3<T> position;
for (std::size_t i = 0; i < 3; ++i)
position[i] = distribution(rng);
const T cbrt_u = std::cbrt(distribution(rng));
const T scale = (T{1} / std::sqrt(x * x + y * y + z * z)) * cbrt_u;
return {x * scale, y * scale, z * scale};
return math::normalize(position) * std::cbrt(distribution(rng));
} }
entity::id create_swarm(game::context& ctx) entity::id create_swarm(game::context& ctx)

+ 2
- 2
src/game/component/picking.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_COMPONENT_PICKING_HPP #ifndef ANTKEEPER_GAME_COMPONENT_PICKING_HPP
#define ANTKEEPER_GAME_COMPONENT_PICKING_HPP #define ANTKEEPER_GAME_COMPONENT_PICKING_HPP
#include "geom/sphere.hpp"
#include "geom/primitive/sphere.hpp"
#include <cstdint> #include <cstdint>
namespace game { namespace game {
@ -29,7 +29,7 @@ namespace component {
struct picking struct picking
{ {
/// Picking sphere. /// Picking sphere.
geom::sphere<float> sphere;
geom::primitive::sphere<float> sphere;
/// Picking flags. /// Picking flags.
std::uint32_t flags; std::uint32_t flags;

+ 14
- 0
src/game/load.cpp View File

@ -195,6 +195,7 @@ void biome(game::context& ctx, const std::filesystem::path& path)
( (
[](float x, float z) -> float [](float x, float z) -> float
{ {
/*
float frequency = 0.01f; float frequency = 0.01f;
std::size_t octaves = 4; std::size_t octaves = 4;
float lacunarity = 3.0f; float lacunarity = 3.0f;
@ -219,6 +220,19 @@ void biome(game::context& ctx, const std::filesystem::path& path)
float f1_distance = std::sqrt(f1_sqr_distance); float f1_distance = std::sqrt(f1_sqr_distance);
float y = f1_distance * 5.0f + fbm * 0.5f; float y = f1_distance * 5.0f + fbm * 0.5f;
*/
float2 position = float2{x, z} * 0.05f;
auto
[
f1_sqr_distance,
f1_displacement,
f1_id
] = math::noise::voronoi::f1(position);
float f1_distance = std::sqrt(f1_sqr_distance);
float y = f1_distance * 3.0f;
return y; return y;
} }

+ 1
- 1
src/game/state/boot.cpp View File

@ -837,7 +837,7 @@ void boot::setup_systems()
// Setup terrain system // Setup terrain system
ctx.terrain_system = new game::system::terrain(*ctx.entity_registry); ctx.terrain_system = new game::system::terrain(*ctx.entity_registry);
ctx.terrain_system->set_patch_side_length(31.0f); ctx.terrain_system->set_patch_side_length(31.0f);
ctx.terrain_system->set_patch_subdivisions(30);
ctx.terrain_system->set_patch_subdivisions(31);
ctx.terrain_system->set_scene_collection(ctx.surface_scene); ctx.terrain_system->set_scene_collection(ctx.surface_scene);
// Setup vegetation system // Setup vegetation system

+ 9
- 1
src/game/state/nuptial-flight.cpp View File

@ -56,6 +56,9 @@
#include "color/color.hpp" #include "color/color.hpp"
#include "application.hpp" #include "application.hpp"
#include "input/mouse.hpp" #include "input/mouse.hpp"
#include "geom/primitive/sphere.hpp"
#include "geom/primitive/rectangle.hpp"
#include "geom/primitive/hyperplane.hpp"
#include <iostream> #include <iostream>
using namespace game::ant; using namespace game::ant;
@ -66,6 +69,11 @@ namespace state {
nuptial_flight::nuptial_flight(game::context& ctx): nuptial_flight::nuptial_flight(game::context& ctx):
game::state::base(ctx) game::state::base(ctx)
{ {
geom::primitive::rectangle<float> rect;
rect.intersects(rect);
geom::primitive::hyperplane<float, 4> plane;
plane.distance({0, 0, 0, 0});
ctx.logger->push_task("Entering nuptial flight state"); ctx.logger->push_task("Entering nuptial flight state");
// Init selected picking flag // Init selected picking flag
@ -637,7 +645,7 @@ void nuptial_flight::enable_controls()
}; };
// Get picking ray from camera // Get picking ray from camera
const geom::ray<float> ray = ctx.surface_camera->pick(mouse_ndc);
const geom::primitive::ray<float, 3> ray = ctx.surface_camera->pick(mouse_ndc);
// Pick entity // Pick entity
entity::id picked_eid = ctx.collision_system->pick_nearest(ray, ~selected_picking_flag); entity::id picked_eid = ctx.collision_system->pick_nearest(ray, ~selected_picking_flag);

+ 10
- 13
src/game/system/collision.cpp View File

@ -20,8 +20,8 @@
#include "collision.hpp" #include "collision.hpp"
#include "game/component/transform.hpp" #include "game/component/transform.hpp"
#include "game/component/picking.hpp" #include "game/component/picking.hpp"
#include "geom/intersection.hpp"
#include "geom/plane.hpp"
#include "geom/primitive/intersection.hpp"
#include "geom/primitive/plane.hpp"
#include <limits> #include <limits>
namespace game { namespace game {
@ -42,7 +42,7 @@ void collision::update(double t, double dt)
registry.on_destroy<component::collision>().disconnect<&collision::on_collision_destroy>(this); registry.on_destroy<component::collision>().disconnect<&collision::on_collision_destroy>(this);
} }
entity::id collision::pick_nearest(const geom::ray<float>& ray, std::uint32_t flags) const
entity::id collision::pick_nearest(const geom::primitive::ray<float, 3>& ray, std::uint32_t flags) const
{ {
entity::id nearest_eid = entt::null; entity::id nearest_eid = entt::null;
float nearest_distance = std::numeric_limits<float>::infinity(); float nearest_distance = std::numeric_limits<float>::infinity();
@ -57,21 +57,18 @@ entity::id collision::pick_nearest(const geom::ray& ray, std::uint32_t fl
return; return;
// Transform picking sphere // Transform picking sphere
const geom::sphere<float> sphere =
const geom::primitive::sphere<float> sphere =
{ {
transform.world * picking.sphere.center, transform.world * picking.sphere.center,
picking.sphere.radius * std::max(std::max(transform.world.scale[0], transform.world.scale[1]), transform.world.scale[2]) picking.sphere.radius * std::max(std::max(transform.world.scale[0], transform.world.scale[1]), transform.world.scale[2])
}; };
// Test for intersection between ray and sphere // Test for intersection between ray and sphere
auto result = geom::ray_sphere_intersection(ray, sphere);
if (std::get<0>(result))
auto result = geom::primitive::intersection(ray, sphere);
if (result && std::get<0>(*result) < nearest_distance)
{ {
if (std::get<1>(result) < nearest_distance)
{
nearest_eid = entity_id;
nearest_distance = std::get<1>(result);
}
nearest_eid = entity_id;
nearest_distance = std::get<0>(*result);
} }
} }
); );
@ -85,7 +82,7 @@ entity::id collision::pick_nearest(const float3& origin, const float3& normal, s
float nearest_distance_squared = std::numeric_limits<float>::infinity(); float nearest_distance_squared = std::numeric_limits<float>::infinity();
// Construct picking plane // Construct picking plane
const geom::plane<float> picking_plane = geom::plane<float>(normal, origin);
const geom::primitive::plane<float> picking_plane = geom::primitive::plane<float>(origin, normal);
// For each entity with picking and transform components // For each entity with picking and transform components
registry.view<component::picking, component::transform>().each registry.view<component::picking, component::transform>().each
@ -100,7 +97,7 @@ entity::id collision::pick_nearest(const float3& origin, const float3& normal, s
float3 picking_sphere_center = transform.world * picking.sphere.center; float3 picking_sphere_center = transform.world * picking.sphere.center;
// Skip entity if picking sphere center has negative distance from picking plane // Skip entity if picking sphere center has negative distance from picking plane
if (picking_plane.signed_distance(picking_sphere_center) < 0.0f)
if (picking_plane.distance(picking_sphere_center) < 0.0f)
return; return;
// Measure distance from picking plane origin to picking sphere center // Measure distance from picking plane origin to picking sphere center

+ 2
- 2
src/game/system/collision.hpp View File

@ -23,7 +23,7 @@
#include "game/system/updatable.hpp" #include "game/system/updatable.hpp"
#include "entity/id.hpp" #include "entity/id.hpp"
#include "game/component/collision.hpp" #include "game/component/collision.hpp"
#include "geom/ray.hpp"
#include "geom/primitive/ray.hpp"
namespace game { namespace game {
namespace system { namespace system {
@ -45,7 +45,7 @@ public:
* *
* @return ID of the picked entity, or `entt::null` if no entity was picked. * @return ID of the picked entity, or `entt::null` if no entity was picked.
*/ */
entity::id pick_nearest(const geom::ray<float>& ray, std::uint32_t flags) const;
entity::id pick_nearest(const geom::primitive::ray<float, 3>& ray, std::uint32_t flags) const;
/** /**
* Picks the nearest entity with the specified picking flags that has a non-negative distance from a plane. * Picks the nearest entity with the specified picking flags that has a non-negative distance from a plane.

+ 88
- 63
src/game/system/terrain.cpp View File

@ -24,6 +24,7 @@
#include "geom/mesh-functions.hpp" #include "geom/mesh-functions.hpp"
#include "geom/morton.hpp" #include "geom/morton.hpp"
#include "geom/quadtree.hpp" #include "geom/quadtree.hpp"
#include "geom/primitive/ray.hpp"
#include "gl/vertex-attribute.hpp" #include "gl/vertex-attribute.hpp"
#include "math/quaternion-operators.hpp" #include "math/quaternion-operators.hpp"
#include "render/vertex-attribute.hpp" #include "render/vertex-attribute.hpp"
@ -89,7 +90,7 @@ void terrain::update(double t, double dt)
// for (int i = 0; i < 8; ++i) // for (int i = 0; i < 8; ++i)
// std::cout << "corner " << i << ": " << cam.get_view_frustum().get_corners()[i] << std::endl; // std::cout << "corner " << i << ": " << cam.get_view_frustum().get_corners()[i] << std::endl;
geom::ray<float> rays[8];
geom::primitive::ray<float, 3> rays[8];
rays[0] = cam.pick({-1, -1}); rays[0] = cam.pick({-1, -1});
rays[1] = cam.pick({-1, 1}); rays[1] = cam.pick({-1, 1});
rays[2] = cam.pick({ 1, 1}); rays[2] = cam.pick({ 1, 1});
@ -160,7 +161,7 @@ void terrain::set_patch_subdivisions(std::size_t n)
// Recalculate patch properties // Recalculate patch properties
patch_cell_count = (patch_subdivisions + 1) * (patch_subdivisions + 1); patch_cell_count = (patch_subdivisions + 1) * (patch_subdivisions + 1);
patch_triangle_count = patch_cell_count * 4;
patch_triangle_count = patch_cell_count * 2;
// Resize patch vertex data buffer // Resize patch vertex data buffer
delete[] patch_vertex_data; delete[] patch_vertex_data;
@ -169,7 +170,7 @@ void terrain::set_patch_subdivisions(std::size_t n)
// Resize patch buffers // Resize patch buffers
std::size_t vertex_buffer_row_size = patch_subdivisions + 4; std::size_t vertex_buffer_row_size = patch_subdivisions + 4;
std::size_t vertex_buffer_column_size = vertex_buffer_row_size * 2;
std::size_t vertex_buffer_column_size = vertex_buffer_row_size;
patch_vertex_buffer.resize(vertex_buffer_row_size); patch_vertex_buffer.resize(vertex_buffer_row_size);
for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i) for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
@ -370,7 +371,7 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
patch_bounds.max_point.y() = -std::numeric_limits<float>::infinity(); patch_bounds.max_point.y() = -std::numeric_limits<float>::infinity();
patch_bounds.max_point.z() = patch_center.z() + patch_size * 0.5f; patch_bounds.max_point.z() = patch_center.z() + patch_size * 0.5f;
// Calculate positions of patch vertices and immediately neighboring vertices
// Calculate positions and UVs of patch vertices and immediately neighboring vertices
float3 first_vertex_position = float3 first_vertex_position =
{ {
patch_bounds.min_point.x() - cell_size, patch_bounds.min_point.x() - cell_size,
@ -381,17 +382,27 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i) for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
{ {
// For each column // For each column
for (std::size_t j = 0; j < patch_vertex_buffer[i].size(); j += 2)
for (std::size_t j = 0; j < patch_vertex_buffer[i].size(); ++j)
{ {
// Get elevation of vertex
// Calculate vertex elevation
vertex_position.y() = elevation_function(vertex_position.x(), vertex_position.z()); vertex_position.y() = elevation_function(vertex_position.x(), vertex_position.z());
// Update patch bounds // Update patch bounds
patch_bounds.min_point.y() = std::min(patch_bounds.min_point.y(), vertex_position.y()); patch_bounds.min_point.y() = std::min(patch_bounds.min_point.y(), vertex_position.y());
patch_bounds.max_point.y() = std::max(patch_bounds.max_point.y(), vertex_position.y()); patch_bounds.max_point.y() = std::max(patch_bounds.max_point.y(), vertex_position.y());
// Update patch vertex position
patch_vertex_buffer[i][j].position = vertex_position; patch_vertex_buffer[i][j].position = vertex_position;
// Calculate patch vertex UV
patch_vertex_buffer[i][j].uv.x() = (vertex_position.x() - patch_bounds.min_point.x()) / patch_size;
patch_vertex_buffer[i][j].uv.y() = (vertex_position.z() - patch_bounds.min_point.z()) / patch_size;
// Init patch vertex normal, tangent, and bitangent
patch_vertex_buffer[i][j].normal = {0, 0, 0};
patch_vertex_buffer[i][j].tangent = {0, 0, 0};
patch_vertex_buffer[i][j].bitangent = {0, 0, 0};
vertex_position.x() += cell_size; vertex_position.x() += cell_size;
} }
@ -399,51 +410,69 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
vertex_position.x() = first_vertex_position.x(); vertex_position.x() = first_vertex_position.x();
} }
first_vertex_position.x() += cell_size * 0.5f;
first_vertex_position.z() += cell_size * 0.5f;
vertex_position = first_vertex_position;
for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
// Accumulate normals, tangents, and bitangents
for (std::size_t i = 0; i < patch_vertex_buffer.size() - 1; ++i)
{ {
// For each column
for (std::size_t j = 1; j < patch_vertex_buffer[i].size(); j += 2)
for (std::size_t j = 0; j < patch_vertex_buffer[i].size() - 1; ++j)
{ {
// Get elevation of vertex
vertex_position.y() = elevation_function(vertex_position.x(), vertex_position.z());
// Update patch bounds
patch_bounds.min_point.y() = std::min(patch_bounds.min_point.y(), vertex_position.y());
patch_bounds.max_point.y() = std::max(patch_bounds.max_point.y(), vertex_position.y());
patch_vertex& a = patch_vertex_buffer[i ][j];
patch_vertex& b = patch_vertex_buffer[i+1][j];
patch_vertex& c = patch_vertex_buffer[i ][j+1];
patch_vertex& d = patch_vertex_buffer[i+1][j+1];
patch_vertex_buffer[i][j].position = vertex_position;
auto add_ntb = [](auto& a, auto& b, auto& c)
{
const float3 ba = b.position - a.position;
const float3 ca = c.position - a.position;
const float2 uvba = b.uv - a.uv;
const float2 uvca = c.uv - a.uv;
const float3 normal = math::normalize(math::cross(ba, ca));
const float f = 1.0f / (uvba.x() * uvca.y() - uvca.x() * uvba.y());
const float3 tangent = (ba * uvca.y() - ca * uvba.y()) * f;
const float3 bitangent = (ba * -uvca.x() + ca * uvba.x()) * f;
a.normal += normal;
a.tangent += tangent;
a.bitangent += bitangent;
b.normal += normal;
b.tangent += tangent;
b.bitangent += bitangent;
c.normal += normal;
c.tangent += tangent;
c.bitangent += bitangent;
};
vertex_position.x() += cell_size;
if ((j + i) % 2)
{
add_ntb(a, b, c);
add_ntb(c, b, d);
}
else
{
add_ntb(a, b, d);
add_ntb(a, d, c);
}
} }
vertex_position.z() += cell_size;
vertex_position.x() = first_vertex_position.x();
} }
// Calculate tangents, bitangents, and normals of patch vertices
// Finalize normals, tangents, and bitangent signs of patch vertices
for (std::size_t i = 1; i < patch_vertex_buffer.size() - 1; ++i) for (std::size_t i = 1; i < patch_vertex_buffer.size() - 1; ++i)
{ {
// For each column
for (std::size_t j = 2; j < patch_vertex_buffer[i].size() - 3; ++j)
for (std::size_t j = 1; j < patch_vertex_buffer[i].size() - 1; ++j)
{ {
const float3& c = patch_vertex_buffer[i ][j ].position;
const float3& n = patch_vertex_buffer[i+1][j ].position;
const float3& s = patch_vertex_buffer[i-1][j ].position;
const float3& e = patch_vertex_buffer[i ][j+2].position;
const float3& w = patch_vertex_buffer[i ][j-2].position;
auto& vertex = patch_vertex_buffer[i][j];
const float3 tangent = math::normalize(float3{2.0f, (e.y() - w.y()) / cell_size, 0.0f});
const float3 bitangent = math::normalize(float3{0.0f, (n.y() - s.y()) / cell_size, 2.0f});
const float3 normal = math::cross(bitangent, tangent);
const float bitangent_sign = std::copysign(1.0f, math::dot(math::cross(normal, tangent), bitangent));
// Normalize normal
vertex.normal = math::normalize(vertex.normal);
patch_vertex_buffer[i][j].uv.x() = (c.x() - patch_bounds.min_point.x()) / patch_size;
patch_vertex_buffer[i][j].uv.y() = (c.z() - patch_bounds.min_point.z()) / patch_size;
patch_vertex_buffer[i][j].normal = normal;
patch_vertex_buffer[i][j].tangent = {tangent.x(), tangent.y(), tangent.z(), bitangent_sign};
// Gram-Schmidt orthogonalize tangent
vertex.tangent = math::normalize(vertex.tangent - vertex.normal * math::dot(vertex.normal, vertex.tangent));
// Calculate bitangent sign
vertex.bitangent_sign = std::copysign(1.0f, math::dot(math::cross(vertex.normal, vertex.tangent), vertex.bitangent));
} }
} }
@ -471,17 +500,16 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
2 subdivisions: 2 subdivisions:
+---+---+---+---+---+ +---+---+---+---+---+
| x x x x x | x
| |
+ +---+---+---+ + + +---+---+---+ +
| x | x | x | x | x | x
| | | | | |
+ +---+---+---+ + + +---+---+---+ +
| x | x | x | x | x | x
| | | | | |
+ +---+---+---+ + + +---+---+---+ +
| x | x | x | x | x | x
| | | | | |
+ +---+---+---+ + + +---+---+---+ +
| x x x x x | x
| |
+---+---+---+---+---+ +---+---+---+---+---+
x x x x x x
*/ */
// For each row // For each row
@ -489,20 +517,16 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
for (std::size_t i = 1; i < patch_vertex_buffer.size() - 2; ++i) for (std::size_t i = 1; i < patch_vertex_buffer.size() - 2; ++i)
{ {
// For each column // For each column
for (std::size_t j = 3; j < patch_vertex_buffer[i].size() - 4; j += 2)
for (std::size_t j = 1; j < patch_vertex_buffer[i].size() - 2; ++j)
{ {
// a---c // a---c
// | x |
// | |
// b---d // b---d
const patch_vertex& x = patch_vertex_buffer[i ][j ];
const patch_vertex& a = patch_vertex_buffer[i ][j-1];
const patch_vertex& b = patch_vertex_buffer[i+1][j-1];
const patch_vertex& a = patch_vertex_buffer[i ][j];
const patch_vertex& b = patch_vertex_buffer[i+1][j];
const patch_vertex& c = patch_vertex_buffer[i ][j+1]; const patch_vertex& c = patch_vertex_buffer[i ][j+1];
const patch_vertex& d = patch_vertex_buffer[i+1][j+1]; const patch_vertex& d = patch_vertex_buffer[i+1][j+1];
const float4& td = patch_vertex_buffer[i+1][j+1].tangent;
auto add_triangle = [&v](const patch_vertex& a, const patch_vertex& b, const patch_vertex& c) auto add_triangle = [&v](const patch_vertex& a, const patch_vertex& b, const patch_vertex& c)
{ {
auto add_vertex = [&v](const patch_vertex& vertex, const float3& barycentric) auto add_vertex = [&v](const patch_vertex& vertex, const float3& barycentric)
@ -525,7 +549,7 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
*(v++) = vertex.tangent[0]; *(v++) = vertex.tangent[0];
*(v++) = vertex.tangent[1]; *(v++) = vertex.tangent[1];
*(v++) = vertex.tangent[2]; *(v++) = vertex.tangent[2];
*(v++) = vertex.tangent[3];
*(v++) = vertex.bitangent_sign;
// Barycentric // Barycentric
*(v++) = barycentric[0]; *(v++) = barycentric[0];
@ -543,15 +567,16 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
add_vertex(c, float3{0, 0, 1}); add_vertex(c, float3{0, 0, 1});
}; };
add_triangle(x, a, b);
add_triangle(x, b, d);
add_triangle(x, d, c);
add_triangle(x, c, a);
// add_triangle(a, b, c);
// add_triangle(c, b, d);
if ((j + i) % 2)
{
add_triangle(a, b, c);
add_triangle(c, b, d);
}
else
{
add_triangle(a, b, d);
add_triangle(a, d, c);
}
} }
} }

+ 3
- 1
src/game/system/terrain.hpp View File

@ -132,7 +132,9 @@ private:
float3 position; float3 position;
float2 uv; float2 uv;
float3 normal; float3 normal;
float4 tangent;
float3 tangent;
float3 bitangent;
float bitangent_sign;
}; };
mutable std::vector<std::vector<patch_vertex>> patch_vertex_buffer; mutable std::vector<std::vector<patch_vertex>> patch_vertex_buffer;

+ 35
- 0
src/geom/primitive/box.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_BOX_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_BOX_HPP
#include "geom/primitive/hyperrectangle.hpp"
namespace geom {
namespace primitive {
/// 3-dimensional hyperrectangle.
template <class T>
using box = hyperrectangle<T, 3>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_BOX_HPP

+ 35
- 0
src/geom/primitive/circle.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_CIRCLE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_CIRCLE_HPP
#include "geom/primitive/hypersphere.hpp"
namespace geom {
namespace primitive {
/// 2-dimensional hypersphere.
template <class T>
using circle = hypersphere<T, 2>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_CIRCLE_HPP

+ 75
- 0
src/geom/primitive/hyperplane.hpp View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_HYPERPLANE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_HYPERPLANE_HPP
#include "math/vector.hpp"
namespace geom {
namespace primitive {
/**
* *n*-dimensional plane.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
struct hyperplane
{
typedef math::vector<T, N> vector_type;
/// Hyperplane normal.
vector_type normal;
/// Hyperplane constant.
T constant;
/// Constructs a hyperplane.
constexpr hyperplane() noexcept = default;
/**
* Constructs a hyperplane given a point and a normal.
*
* @param point Point.
* @param normal Normal.
*/
constexpr hyperplane(const vector_type& point, const vector_type& normal) noexcept:
normal(normal),
constant(-math::dot(normal, point))
{}
/**
* Calculates the signed distance from the hyperplane to a point.
*
* @param point Input point.
*
* @return Signed distance from the hyperplane to @p point.
*/
constexpr T distance(const vector_type& point) const noexcept
{
return math::dot(normal, point) + constant;
}
};
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_HYPERPLANE_HPP

+ 162
- 0
src/geom/primitive/hyperrectangle.hpp View File

@ -0,0 +1,162 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_HYPERRECTANGLE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_HYPERRECTANGLE_HPP
#include "math/vector.hpp"
#include <algorithm>
namespace geom {
namespace primitive {
/**
* *n*-dimensional axis-aligned rectangle.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
struct hyperrectangle
{
typedef math::vector<T, N> vector_type;
/// Minimum extent of the hyperrectangle.
vector_type min;
/// Maximum extent of the hyperrectangle.
vector_type max;
/**
* Tests whether a point is contained within this hyperrectangle.
*
* @param point Point to test for containment.
*
* @return `true` if the point is contained within this hyperrectangle, `false` otherwise.
*/
constexpr bool contains(const vector_type& point) const noexcept
{
for (std::size_t i = 0; i < N; ++i)
if (point[i] < min[i] || point[i] > max[i])
return false;
return true;
}
/**
* Tests whether another hyperrectangle is contained within this hyperrectangle.
*
* @param other Hyperrectangle to test for containment.
*
* @return `true` if the hyperrectangle is contained within this hyperrectangle, `false` otherwise.
*/
constexpr bool contains(const hyperrectangle& other) const noexcept
{
for (std::size_t i = 0; i < N; ++i)
if (other.min[i] < min[i] || other.max[i] > max[i])
return false;
return true;
}
/// Returns the center position of the hyperrectangle.
constexpr vector_type center() const noexcept
{
return (min + max) * T{0.5};
}
/**
* Calculates the signed distance from the hyperrectangle to a point.
*
* @param point Input point.
*
* @return Signed distance from the hyperrectangle to @p point.
*/
T distance(const vector_type& point) const noexcept
{
vector_type d = math::abs(point - center()) - size() * T{0.5};
return math::length(math::max(vector_type::zero(), d)) + std::min<T>(T{0}, math::max(d));
}
/**
* Extends the hyperrectangle to include a point.
*
* @param point Point to include in the hyperrectangle.
*/
void extend(const vector_type& point) noexcept
{
min = math::min(min, point);
max = math::max(max, point);
}
/**
* Extends the hyperrectangle to include another hyperrectangle.
*
* @param other Hyperrectangle to include in this hyperrectangle.
*/
void extend(const hyperrectangle& other) noexcept
{
min = math::min(min, other.min);
max = math::max(max, other.max);
}
/**
* Tests whether another hyperrectangle intersects this hyperrectangle.
*
* @param other Hyperrectangle to test for intersection.
*
* @return `true` if the hyperrectangle intersects this hyperrectangle, `false` otherwise.
*/
constexpr bool intersects(const hyperrectangle& other) const noexcept
{
for (std::size_t i = 0; i < N; ++i)
if (other.min[i] > max[i] || other.max[i] < min[i])
return false;
return true;
}
/// Returns the size of the hyperrectangle.
constexpr vector_type size() const noexcept
{
return max - min;
}
/**
* Returns `false` if any coordinates of `min` are greater than `max`.
*/
constexpr bool valid() const noexcept
{
for (std::size_t i = 0; i < N; ++i)
if (min[i] > max[i])
return false;
return true;
}
/// Calculates the volume of the hyperrectangle.
constexpr T volume() const noexcept
{
T v = max[0] - min[0];
for (std::size_t i = 1; i < N; ++i)
v *= max[i] - min[i];
return v;
}
};
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_HYPERRECTANGLE_HPP

+ 139
- 0
src/geom/primitive/hypersphere.hpp View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_HYPERSPHERE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_HYPERSPHERE_HPP
#include "math/constants.hpp"
#include "math/vector.hpp"
namespace geom {
namespace primitive {
/**
* *n*-dimensional sphere.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
struct hypersphere
{
typedef math::vector<T, N> vector_type;
/// Hypersphere center.
vector_type center;
/// Hypersphere radius.
T radius;
/**
* Tests whether a point is contained within this hypersphere.
*
* @param point Point to test for containment.
*
* @return `true` if the point is contained within this hypersphere, `false` otherwise.
*/
constexpr bool contains(const vector_type& point) const noexcept
{
return math::distance_squared(center, point) <= radius * radius;
}
/**
* Tests whether another hypersphere is contained within this hypersphere.
*
* @param other Hypersphere to test for containment.
*
* @return `true` if the hypersphere is contained within this hypersphere, `false` otherwise.
*/
constexpr bool contains(const hypersphere& other) const noexcept
{
const T containment_radius = radius - other.radius;
if (containment_radius < T{0})
return false;
return math::distance_squared(center, other.center) <= containment_radius * containment_radius;
}
/**
* Calculates the signed distance from the hypersphere to a point.
*
* @param point Input point.
*
* @return Signed distance from the hypersphere to @p point.
*/
T distance(const vector_type& point) const noexcept
{
return math::distance(center, point) - radius;
}
/**
* Tests whether another hypersphere intersects this hypersphere.
*
* @param other Hypersphere to test for intersection.
*
* @return `true` if the hypersphere intersects this hypersphere, `false` otherwise.
*/
constexpr bool intersects(const hypersphere& other) const noexcept
{
const T intersection_radius = radius + other.radius;
return math::distance_squared(center, other.center) <= intersection_radius * intersection_radius;
}
/**
* Volume calculation helper function.
*
* @tparam M Dimension.
*
* @param r Radius.
*
* @return Volume.
*/
/// @private
/// @{
template <std::size_t M>
static constexpr T volume(T r) noexcept
{
return (math::two_pi<T> / static_cast<T>(M)) * r * r * volume<M - 2>(r);
}
template <>
static constexpr T volume<1>(T r) noexcept
{
return r * T{2};
}
template <>
static constexpr T volume<0>(T r) noexcept
{
return T{1};
}
/// @}
/// Calculates the volume of the hypersphere.
inline constexpr T volume() const noexcept
{
return volume<N>(radius);
}
};
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_HYPERSPHERE_HPP

+ 199
- 0
src/geom/primitive/intersection.hpp View File

@ -0,0 +1,199 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP
#include "geom/primitive/hyperplane.hpp"
#include "geom/primitive/hyperrectangle.hpp"
#include "geom/primitive/hypersphere.hpp"
#include "geom/primitive/ray.hpp"
#include <algorithm>
#include <optional>
namespace geom {
namespace primitive {
/**
* Ray-hyperplane intersection test.
*
* @param ray Ray.
* @param hyperplane Hyperplane.
*
* @return Distance along the ray to the point of intersection, or `std::nullopt` if no intersection occurred.
*/
/// @{
template <class T, std::size_t N>
constexpr std::optional<T> intersection(const ray<T, N>& ray, const hyperplane<T, N>& hyperplane) noexcept
{
const T cos_theta = math::dot(ray.direction, hyperplane.normal);
if (cos_theta != T{0})
{
const T t = -hyperplane.distance(ray.origin) / cos_theta;
if (t >= T{0})
return t;
}
return std::nullopt;
}
template <class T, std::size_t N>
constexpr inline std::optional<T> intersection(const hyperplane<T, N>& hyperplane, const ray<T, N>& ray) noexcept
{
return intersection<T, N>(ray, hyperplane);
}
/// @}
/**
* Ray-hyperrectangle intersection test.
*
* @param ray Ray.
* @param hyperrectangle Hyperrectangle.
*
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
*/
/// @{
template <class T, std::size_t N>
constexpr std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hyperrectangle<T, N>& hyperrectangle) noexcept
{
T t0 = -std::numeric_limits<T>::infinity();
T t1 = std::numeric_limits<T>::infinity();
for (std::size_t i = 0; i < N; ++i)
{
if (!ray.direction[i])
{
if (ray.origin[i] < hyperrectangle.min[i] || ray.origin[i] > hyperrectangle.max[i])
return std::nullopt;
}
else
{
T min = (hyperrectangle.min[i] - ray.origin[i]) / ray.direction[i];
T max = (hyperrectangle.max[i] - ray.origin[i]) / ray.direction[i];
t0 = std::max(t0, std::min(min, max));
t1 = std::min(t1, std::max(min, max));
}
}
if (t0 > t1 || t1 < T{0})
return std::nullopt;
return {t0, t1};
}
template <class T, std::size_t N>
constexpr inline std::optional<std::tuple<T, T>> intersection(const hyperrectangle<T, N>& hyperrectangle, const ray<T, N>& ray) noexcept
{
return intersection<T, N>(ray, hyperrectangle);
}
/// @}
/**
* Ray-hypersphere intersection test.
*
* @param ray Ray.
* @param hypersphere Hypersphere.
*
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred.
*/
template <class T, std::size_t N>
std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hypersphere<T, N>& hypersphere) noexcept
{
const math::vector<T, N> displacement = ray.origin - hypersphere.center;
const T b = math::dot(displacement, ray.direction);
const T c = math::length_squared(displacement) - hypersphere.radius * hypersphere.radius;
T h = b * b - c;
if (h < T{0})
return std::nullopt;
h = std::sqrt(h);
return std::tuple<float, float>{-b - h, -b + h};
}
/**
* Hyperrectangle-hyperrectangle intersection test.
*
* @param a First hyperrectangle.
* @param b Second hyperrectangle.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
template <class T, std::size_t N>
constexpr inline bool intersection(const hyperrectangle<T, N>& a, const hyperrectangle<T, N>& b) noexcept
{
return a.intersects(b);
}
/**
* Hyperrectangle-hypersphere intersection test.
*
* @param hyperrectangle Hyperrectangle.
* @param hypersphere Hypersphere.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
/// @{
template <class T, std::size_t N>
constexpr bool intersection(const hyperrectangle<T, N>& hyperrectangle, const hypersphere<T, N>& hypersphere) noexcept
{
T sqr_distance{0};
for (std::size_t i = 0; i < N; ++i)
{
if (hypersphere.center[i] < hyperrectangle.min[i])
{
const T difference = hyperrectangle.min[i] - hypersphere.center[i];
sqr_distance += difference * difference;
}
else if (hypersphere.center[i] > hyperrectangle.max[i])
{
const T difference = hypersphere.center[i] - hyperrectangle.max[i];
sqr_distance += difference * difference;
}
}
return sqr_distance <= hypersphere.radius * hypersphere.radius;
}
template <class T, std::size_t N>
constexpr inline bool intersection(const hypersphere<T, N>& hypersphere, const hyperrectangle<T, N>& hyperrectangle) noexcept
{
return intersection<T, N>(hyperrectangle, hypersphere);
}
/// @}
/**
* Hypersphere-hypersphere intersection test.
*
* @param a First hypersphere.
* @param b Second hypersphere.
*
* @return `true` if an intersection occurred, `false` otherwise.
*/
template <class T, std::size_t N>
constexpr inline bool intersection(const hypersphere<T, N>& a, const hypersphere<T, N>& b) noexcept
{
return a.intersects(b);
}
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP

+ 59
- 0
src/geom/primitive/line-segment.hpp View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_LINE_SEGMENT_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_LINE_SEGMENT_HPP
#include "math/vector.hpp"
namespace geom {
namespace primitive {
/**
* *n*-dimensional line segment.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
struct line_segment
{
typedef math::vector<T, N> vector_type;
/// First endpoint.
vector_type a;
/// Second endpoint.
vector_type b;
/**
* Calculates the length of the line segment.
*
* @return Length of the line segment.
*/
T length() const noexcept
{
return math::distance(a, b);
}
};
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_LINE_SEGMENT_HPP

+ 35
- 0
src/geom/primitive/line.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_LINE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_LINE_HPP
#include "geom/primitive/hyperplane.hpp"
namespace geom {
namespace primitive {
/// 2-dimensional hyperplane.
template <class T>
using line = hyperplane<T, 2>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_LINE_HPP

+ 35
- 0
src/geom/primitive/plane.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_PLANE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_PLANE_HPP
#include "geom/primitive/hyperplane.hpp"
namespace geom {
namespace primitive {
/// 3-dimensional hyperplane.
template <class T>
using plane = hyperplane<T, 3>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_PLANE_HPP

+ 61
- 0
src/geom/primitive/ray.hpp View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_RAY_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_RAY_HPP
#include "math/vector.hpp"
namespace geom {
namespace primitive {
/**
* Half of a line proceeding from an initial point.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
struct ray
{
typedef math::vector<T, N> vector_type;
/// Ray origin position.
vector_type origin;
/// Ray direction vector.
vector_type direction;
/**
* Extrapolates from the ray origin along the ray direction vector.
*
* @param distance Signed extrapolation distance.
*
* @return Extrapolated coordinates.
*/
constexpr vector_type extrapolate(T distance) const noexcept
{
return origin + direction * distance;
}
};
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_RAY_HPP

+ 35
- 0
src/geom/primitive/rectangle.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_RECTANGLE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_RECTANGLE_HPP
#include "geom/primitive/hyperrectangle.hpp"
namespace geom {
namespace primitive {
/// 2-dimensional hyperrectangle.
template <class T>
using rectangle = hyperrectangle<T, 2>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_RECTANGLE_HPP

+ 35
- 0
src/geom/primitive/sphere.hpp View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GEOM_PRIMITIVE_SPHERE_HPP
#define ANTKEEPER_GEOM_PRIMITIVE_SPHERE_HPP
#include "geom/primitive/hypersphere.hpp"
namespace geom {
namespace primitive {
/// 3-dimensional hypersphere.
template <class T>
using sphere = hypersphere<T, 3>;
} // namespace primitive
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVE_SPHERE_HPP

+ 1
- 1
src/scene/camera.cpp View File

@ -77,7 +77,7 @@ camera::camera():
exposure(0.0f, math::lerp<float, float>) exposure(0.0f, math::lerp<float, float>)
{} {}
geom::ray<float> camera::pick(const float2& ndc) const
geom::primitive::ray<float, 3> camera::pick(const float2& ndc) const
{ {
const float4x4 inverse_view_projection = math::inverse(view_projection[1]); const float4x4 inverse_view_projection = math::inverse(view_projection[1]);

+ 2
- 2
src/scene/camera.hpp View File

@ -22,7 +22,7 @@
#include "scene/object.hpp" #include "scene/object.hpp"
#include "geom/view-frustum.hpp" #include "geom/view-frustum.hpp"
#include "geom/ray.hpp"
#include "geom/primitive/ray.hpp"
#include "utility/fundamental-types.hpp" #include "utility/fundamental-types.hpp"
#include "render/compositor.hpp" #include "render/compositor.hpp"
@ -45,7 +45,7 @@ public:
* *
* @return Picking ray. * @return Picking ray.
*/ */
geom::ray<float> pick(const float2& ndc) const;
geom::primitive::ray<float, 3> pick(const float2& ndc) const;
/** /**
* Maps object coordinates to window coordinates. * Maps object coordinates to window coordinates.

Loading…
Cancel
Save