diff --git a/CMakeLists.txt b/CMakeLists.txt index 7faddc1..74f34e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,15 +77,11 @@ else() target_compile_definitions(${EXECUTABLE_TARGET} PRIVATE NDEBUG) endif() -# Set C++17 standard +# Set C++20 standard set_target_properties(${EXECUTABLE_TARGET} PROPERTIES - CXX_STANDARD 17 + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON 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 if(MSVC) diff --git a/src/color/cat.hpp b/src/color/cat.hpp index 3b56d03..8f4fcb2 100644 --- a/src/color/cat.hpp +++ b/src/color/cat.hpp @@ -49,8 +49,8 @@ constexpr math::matrix bradford = template constexpr math::matrix 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 }; @@ -62,9 +62,9 @@ constexpr math::matrix von_kries = template constexpr math::matrix 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} }; /** diff --git a/src/game/ant/swarm.cpp b/src/game/ant/swarm.cpp index aa1d718..d87828a 100644 --- a/src/game/ant/swarm.cpp +++ b/src/game/ant/swarm.cpp @@ -40,15 +40,11 @@ static math::vector3 sphere_random(Generator& rng) { const std::uniform_real_distribution distribution(T{-1}, T{1}); - const T x = distribution(rng); - const T y = distribution(rng); - const T z = distribution(rng); + math::vector3 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) diff --git a/src/game/component/picking.hpp b/src/game/component/picking.hpp index 347eddb..e1bdecf 100644 --- a/src/game/component/picking.hpp +++ b/src/game/component/picking.hpp @@ -20,7 +20,7 @@ #ifndef ANTKEEPER_GAME_COMPONENT_PICKING_HPP #define ANTKEEPER_GAME_COMPONENT_PICKING_HPP -#include "geom/sphere.hpp" +#include "geom/primitive/sphere.hpp" #include namespace game { @@ -29,7 +29,7 @@ namespace component { struct picking { /// Picking sphere. - geom::sphere sphere; + geom::primitive::sphere sphere; /// Picking flags. std::uint32_t flags; diff --git a/src/game/load.cpp b/src/game/load.cpp index de801b1..164babe 100644 --- a/src/game/load.cpp +++ b/src/game/load.cpp @@ -195,6 +195,7 @@ void biome(game::context& ctx, const std::filesystem::path& path) ( [](float x, float z) -> float { + /* float frequency = 0.01f; std::size_t octaves = 4; 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 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; } diff --git a/src/game/state/boot.cpp b/src/game/state/boot.cpp index 4810b7f..4ecbc97 100644 --- a/src/game/state/boot.cpp +++ b/src/game/state/boot.cpp @@ -837,7 +837,7 @@ void boot::setup_systems() // Setup terrain system ctx.terrain_system = new game::system::terrain(*ctx.entity_registry); 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); // Setup vegetation system diff --git a/src/game/state/nuptial-flight.cpp b/src/game/state/nuptial-flight.cpp index 2336c1a..c6d73dd 100644 --- a/src/game/state/nuptial-flight.cpp +++ b/src/game/state/nuptial-flight.cpp @@ -56,6 +56,9 @@ #include "color/color.hpp" #include "application.hpp" #include "input/mouse.hpp" +#include "geom/primitive/sphere.hpp" +#include "geom/primitive/rectangle.hpp" +#include "geom/primitive/hyperplane.hpp" #include using namespace game::ant; @@ -66,6 +69,11 @@ namespace state { nuptial_flight::nuptial_flight(game::context& ctx): game::state::base(ctx) { + geom::primitive::rectangle rect; + rect.intersects(rect); + geom::primitive::hyperplane plane; + plane.distance({0, 0, 0, 0}); + ctx.logger->push_task("Entering nuptial flight state"); // Init selected picking flag @@ -637,7 +645,7 @@ void nuptial_flight::enable_controls() }; // Get picking ray from camera - const geom::ray ray = ctx.surface_camera->pick(mouse_ndc); + const geom::primitive::ray ray = ctx.surface_camera->pick(mouse_ndc); // Pick entity entity::id picked_eid = ctx.collision_system->pick_nearest(ray, ~selected_picking_flag); diff --git a/src/game/system/collision.cpp b/src/game/system/collision.cpp index 7618f25..a79a63c 100644 --- a/src/game/system/collision.cpp +++ b/src/game/system/collision.cpp @@ -20,8 +20,8 @@ #include "collision.hpp" #include "game/component/transform.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 namespace game { @@ -42,7 +42,7 @@ void collision::update(double t, double dt) registry.on_destroy().disconnect<&collision::on_collision_destroy>(this); } -entity::id collision::pick_nearest(const geom::ray& ray, std::uint32_t flags) const +entity::id collision::pick_nearest(const geom::primitive::ray& ray, std::uint32_t flags) const { entity::id nearest_eid = entt::null; float nearest_distance = std::numeric_limits::infinity(); @@ -57,21 +57,18 @@ entity::id collision::pick_nearest(const geom::ray& ray, std::uint32_t fl return; // Transform picking sphere - const geom::sphere sphere = + const geom::primitive::sphere sphere = { transform.world * picking.sphere.center, 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 - 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::infinity(); // Construct picking plane - const geom::plane picking_plane = geom::plane(normal, origin); + const geom::primitive::plane picking_plane = geom::primitive::plane(origin, normal); // For each entity with picking and transform components registry.view().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; // 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; // Measure distance from picking plane origin to picking sphere center diff --git a/src/game/system/collision.hpp b/src/game/system/collision.hpp index 5ec8487..35e5ca0 100644 --- a/src/game/system/collision.hpp +++ b/src/game/system/collision.hpp @@ -23,7 +23,7 @@ #include "game/system/updatable.hpp" #include "entity/id.hpp" #include "game/component/collision.hpp" -#include "geom/ray.hpp" +#include "geom/primitive/ray.hpp" namespace game { namespace system { @@ -45,7 +45,7 @@ public: * * @return ID of the picked entity, or `entt::null` if no entity was picked. */ - entity::id pick_nearest(const geom::ray& ray, std::uint32_t flags) const; + entity::id pick_nearest(const geom::primitive::ray& ray, std::uint32_t flags) const; /** * Picks the nearest entity with the specified picking flags that has a non-negative distance from a plane. diff --git a/src/game/system/terrain.cpp b/src/game/system/terrain.cpp index cfdc20b..878c05d 100644 --- a/src/game/system/terrain.cpp +++ b/src/game/system/terrain.cpp @@ -24,6 +24,7 @@ #include "geom/mesh-functions.hpp" #include "geom/morton.hpp" #include "geom/quadtree.hpp" +#include "geom/primitive/ray.hpp" #include "gl/vertex-attribute.hpp" #include "math/quaternion-operators.hpp" #include "render/vertex-attribute.hpp" @@ -89,7 +90,7 @@ void terrain::update(double t, double dt) // for (int i = 0; i < 8; ++i) // std::cout << "corner " << i << ": " << cam.get_view_frustum().get_corners()[i] << std::endl; - geom::ray rays[8]; + geom::primitive::ray rays[8]; rays[0] = cam.pick({-1, -1}); rays[1] = 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 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 delete[] patch_vertex_data; @@ -169,7 +170,7 @@ void terrain::set_patch_subdivisions(std::size_t n) // Resize patch buffers 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); 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::infinity(); 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 = { 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 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()); // 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()); + // Update patch 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; } @@ -399,51 +410,69 @@ geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const 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 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: +---+---+---+---+---+ - | 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 @@ -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 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 - // | x | + // | | // 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& 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_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[1]; *(v++) = vertex.tangent[2]; - *(v++) = vertex.tangent[3]; + *(v++) = vertex.bitangent_sign; // Barycentric *(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_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); + } } } diff --git a/src/game/system/terrain.hpp b/src/game/system/terrain.hpp index f420c6a..c65b930 100644 --- a/src/game/system/terrain.hpp +++ b/src/game/system/terrain.hpp @@ -132,7 +132,9 @@ private: float3 position; float2 uv; float3 normal; - float4 tangent; + float3 tangent; + float3 bitangent; + float bitangent_sign; }; mutable std::vector> patch_vertex_buffer; diff --git a/src/geom/primitive/box.hpp b/src/geom/primitive/box.hpp new file mode 100644 index 0000000..e3f503e --- /dev/null +++ b/src/geom/primitive/box.hpp @@ -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 . + */ + +#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 +using box = hyperrectangle; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_BOX_HPP diff --git a/src/geom/primitive/circle.hpp b/src/geom/primitive/circle.hpp new file mode 100644 index 0000000..f065eb1 --- /dev/null +++ b/src/geom/primitive/circle.hpp @@ -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 . + */ + +#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 +using circle = hypersphere; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_CIRCLE_HPP diff --git a/src/geom/primitive/hyperplane.hpp b/src/geom/primitive/hyperplane.hpp new file mode 100644 index 0000000..02328fc --- /dev/null +++ b/src/geom/primitive/hyperplane.hpp @@ -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 . + */ + +#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 +struct hyperplane +{ + typedef math::vector 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 diff --git a/src/geom/primitive/hyperrectangle.hpp b/src/geom/primitive/hyperrectangle.hpp new file mode 100644 index 0000000..fd9ec10 --- /dev/null +++ b/src/geom/primitive/hyperrectangle.hpp @@ -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 . + */ + +#ifndef ANTKEEPER_GEOM_PRIMITIVE_HYPERRECTANGLE_HPP +#define ANTKEEPER_GEOM_PRIMITIVE_HYPERRECTANGLE_HPP + +#include "math/vector.hpp" +#include + +namespace geom { +namespace primitive { + +/** + * *n*-dimensional axis-aligned rectangle. + * + * @tparam T Real type. + * @tparam N Number of dimensions. + */ +template +struct hyperrectangle +{ + typedef math::vector 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{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 diff --git a/src/geom/primitive/hypersphere.hpp b/src/geom/primitive/hypersphere.hpp new file mode 100644 index 0000000..d991e31 --- /dev/null +++ b/src/geom/primitive/hypersphere.hpp @@ -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 . + */ + +#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 +struct hypersphere +{ + typedef math::vector 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 + static constexpr T volume(T r) noexcept + { + return (math::two_pi / static_cast(M)) * r * r * volume(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(radius); + } +}; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_HYPERSPHERE_HPP diff --git a/src/geom/primitive/intersection.hpp b/src/geom/primitive/intersection.hpp new file mode 100644 index 0000000..1c8e8dd --- /dev/null +++ b/src/geom/primitive/intersection.hpp @@ -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 . + */ + +#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 +#include + +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 +constexpr std::optional intersection(const ray& ray, const hyperplane& 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 +constexpr inline std::optional intersection(const hyperplane& hyperplane, const ray& ray) noexcept +{ + return intersection(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 +constexpr std::optional> intersection(const ray& ray, const hyperrectangle& hyperrectangle) noexcept +{ + T t0 = -std::numeric_limits::infinity(); + T t1 = std::numeric_limits::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 +constexpr inline std::optional> intersection(const hyperrectangle& hyperrectangle, const ray& ray) noexcept +{ + return intersection(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 +std::optional> intersection(const ray& ray, const hypersphere& hypersphere) noexcept +{ + const math::vector 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{-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 +constexpr inline bool intersection(const hyperrectangle& a, const hyperrectangle& 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 +constexpr bool intersection(const hyperrectangle& hyperrectangle, const hypersphere& 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 +constexpr inline bool intersection(const hypersphere& hypersphere, const hyperrectangle& hyperrectangle) noexcept +{ + return intersection(hyperrectangle, hypersphere); +} +/// @} + +/** + * Hypersphere-hypersphere intersection test. + * + * @param a First hypersphere. + * @param b Second hypersphere. + * + * @return `true` if an intersection occurred, `false` otherwise. + */ +template +constexpr inline bool intersection(const hypersphere& a, const hypersphere& b) noexcept +{ + return a.intersects(b); +} + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_INTERSECTION_HPP diff --git a/src/geom/primitive/line-segment.hpp b/src/geom/primitive/line-segment.hpp new file mode 100644 index 0000000..e923581 --- /dev/null +++ b/src/geom/primitive/line-segment.hpp @@ -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 . + */ + +#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 +struct line_segment +{ + typedef math::vector 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 diff --git a/src/geom/primitive/line.hpp b/src/geom/primitive/line.hpp new file mode 100644 index 0000000..4748a14 --- /dev/null +++ b/src/geom/primitive/line.hpp @@ -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 . + */ + +#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 +using line = hyperplane; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_LINE_HPP diff --git a/src/geom/primitive/plane.hpp b/src/geom/primitive/plane.hpp new file mode 100644 index 0000000..b1c5d3c --- /dev/null +++ b/src/geom/primitive/plane.hpp @@ -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 . + */ + +#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 +using plane = hyperplane; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_PLANE_HPP diff --git a/src/geom/primitive/ray.hpp b/src/geom/primitive/ray.hpp new file mode 100644 index 0000000..47c6595 --- /dev/null +++ b/src/geom/primitive/ray.hpp @@ -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 . + */ + +#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 +struct ray +{ + typedef math::vector 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 diff --git a/src/geom/primitive/rectangle.hpp b/src/geom/primitive/rectangle.hpp new file mode 100644 index 0000000..bb86412 --- /dev/null +++ b/src/geom/primitive/rectangle.hpp @@ -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 . + */ + +#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 +using rectangle = hyperrectangle; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_RECTANGLE_HPP diff --git a/src/geom/primitive/sphere.hpp b/src/geom/primitive/sphere.hpp new file mode 100644 index 0000000..9e80adb --- /dev/null +++ b/src/geom/primitive/sphere.hpp @@ -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 . + */ + +#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 +using sphere = hypersphere; + +} // namespace primitive +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVE_SPHERE_HPP diff --git a/src/scene/camera.cpp b/src/scene/camera.cpp index 5595c73..26194a5 100644 --- a/src/scene/camera.cpp +++ b/src/scene/camera.cpp @@ -77,7 +77,7 @@ camera::camera(): exposure(0.0f, math::lerp) {} -geom::ray camera::pick(const float2& ndc) const +geom::primitive::ray camera::pick(const float2& ndc) const { const float4x4 inverse_view_projection = math::inverse(view_projection[1]); diff --git a/src/scene/camera.hpp b/src/scene/camera.hpp index 2afb008..f26c1a0 100644 --- a/src/scene/camera.hpp +++ b/src/scene/camera.hpp @@ -22,7 +22,7 @@ #include "scene/object.hpp" #include "geom/view-frustum.hpp" -#include "geom/ray.hpp" +#include "geom/primitive/ray.hpp" #include "utility/fundamental-types.hpp" #include "render/compositor.hpp" @@ -45,7 +45,7 @@ public: * * @return Picking ray. */ - geom::ray pick(const float2& ndc) const; + geom::primitive::ray pick(const float2& ndc) const; /** * Maps object coordinates to window coordinates.