Commit 6dd433f3 authored by Philip Trettner's avatar Philip Trettner
Browse files

reworked frustum class

parent 368e572f
......@@ -65,22 +65,4 @@ constexpr line<D, ScalarT> line<D, ScalarT>::from_points(pos_t a, pos_t b)
{
return line(a, normalize(b - a));
}
template <class ScalarT>
constexpr frustum<ScalarT>::frustum(mat<4, 4, ScalarT> const& m)
{
// computing planes in order: left, right, bottom, top, near, far
for (auto i = 0u; i < 3; ++i)
for (auto j = 0u; j < 2; ++j)
{
// plane parameters from matrix (see http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf)
vec4 abcd;
for (auto k = 0; k < 4; ++k)
abcd[k] = j == 0 ? m[k][3] + m[k][i] : m[k][3] - m[k][i];
auto n = vec3(abcd);
auto l = length(n);
planes[2 * i + j] = plane3(dir3(n / l), -abcd.w / l);
}
}
}
......@@ -6,11 +6,11 @@ namespace tg
{
namespace literals
{
constexpr angle32 operator""_deg(u64 v) { return angle32::from_degree(f32(v)); }
constexpr angle32 operator""_deg(unsigned long long v) { return angle32::from_degree(f32(v)); }
constexpr angle64 operator""_deg(long double v) { return angle64::from_degree(f64(v)); }
constexpr angle32 operator""_degf(long double v) { return angle32::from_degree(f32(v)); }
constexpr angle32 operator""_rad(u64 v) { return angle32::from_radians(f32(v)); }
constexpr angle32 operator""_rad(unsigned long long v) { return angle32::from_radians(f32(v)); }
constexpr angle64 operator""_rad(long double v) { return angle64::from_radians(f64(v)); }
constexpr angle32 operator""_radf(long double v) { return angle32::from_radians(f32(v)); }
} // namespace literals
......
......@@ -16,6 +16,7 @@
#include <typed-geometry/functions/objects/distance.hh>
#include <typed-geometry/functions/objects/edges.hh>
#include <typed-geometry/functions/objects/faces.hh>
#include <typed-geometry/functions/objects/frustum.hh>
#include <typed-geometry/functions/objects/intersection.hh>
#include <typed-geometry/functions/objects/normal.hh>
#include <typed-geometry/functions/objects/perimeter.hh>
......
......@@ -8,6 +8,7 @@
#include <typed-geometry/types/objects/cone.hh>
#include <typed-geometry/types/objects/cylinder.hh>
#include <typed-geometry/types/objects/ellipse.hh>
#include <typed-geometry/types/objects/frustum.hh>
#include <typed-geometry/types/objects/halfspace.hh>
#include <typed-geometry/types/objects/hemisphere.hh>
#include <typed-geometry/types/objects/inf_cone.hh>
......@@ -475,4 +476,14 @@ template <int D, class ScalarT>
return angle_between(dir<D, ScalarT>(apexOuterToP), c.opening_dir) <= ScalarT(0.5) * c.opening_angle
&& angle_between(dir<D, ScalarT>(apexInnerToP), c.opening_dir) >= ScalarT(0.5) * c.opening_angle;
}
template <class ScalarT>
[[nodiscard]] constexpr bool contains(frustum<3, ScalarT> const& f, pos<3, ScalarT> const& p, dont_deduce<ScalarT> eps = ScalarT(0))
{
for (auto const& pl : f.planes)
if (signed_distance(p, pl) > eps)
return false;
return true;
}
} // namespace tg
#pragma once
#include <typed-geometry/feature/matrix.hh>
#include <typed-geometry/feature/vector.hh>
#include <typed-geometry/types/objects/aabb.hh>
#include <typed-geometry/types/objects/frustum.hh>
namespace tg
{
template <class ScalarT, class TraitsT>
constexpr frustum<3, ScalarT, TraitsT> frustum<3, ScalarT, TraitsT>::from_view_proj(mat<4, 4, ScalarT> const& m, aabb<3, ScalarT> const& ndc)
{
// TODO: see if insight from http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf can be used
using frustum_t = frustum<3, ScalarT, TraitsT>;
using comp_t = tg::comp<3, ScalarT>;
using plane_t = tg::plane<3, ScalarT>;
auto const invM = inverse(m);
frustum_t f;
f.vertices[frustum_t::vertex_idx_000] = invM * ndc[comp_t(0, 0, 0)];
f.vertices[frustum_t::vertex_idx_001] = invM * ndc[comp_t(0, 0, 1)];
f.vertices[frustum_t::vertex_idx_010] = invM * ndc[comp_t(0, 1, 0)];
f.vertices[frustum_t::vertex_idx_011] = invM * ndc[comp_t(0, 1, 1)];
f.vertices[frustum_t::vertex_idx_100] = invM * ndc[comp_t(1, 0, 0)];
f.vertices[frustum_t::vertex_idx_101] = invM * ndc[comp_t(1, 0, 1)];
f.vertices[frustum_t::vertex_idx_110] = invM * ndc[comp_t(1, 1, 0)];
f.vertices[frustum_t::vertex_idx_111] = invM * ndc[comp_t(1, 1, 1)];
auto const build_plane = [&](int i0, int i1, int i2) {
auto const p0 = f.vertices[i0];
auto const p1 = f.vertices[i1];
auto const p2 = f.vertices[i2];
return plane_t(normalize(cross(p1 - p0, p2 - p0)), p0);
};
f.planes[frustum_t::plane_idx_neg_x] = build_plane(frustum_t::vertex_idx_000, frustum_t::vertex_idx_010, frustum_t::vertex_idx_001);
f.planes[frustum_t::plane_idx_neg_y] = build_plane(frustum_t::vertex_idx_000, frustum_t::vertex_idx_001, frustum_t::vertex_idx_100);
f.planes[frustum_t::plane_idx_neg_z] = build_plane(frustum_t::vertex_idx_000, frustum_t::vertex_idx_100, frustum_t::vertex_idx_010);
f.planes[frustum_t::plane_idx_pos_x] = build_plane(frustum_t::vertex_idx_100, frustum_t::vertex_idx_101, frustum_t::vertex_idx_110);
f.planes[frustum_t::plane_idx_pos_y] = build_plane(frustum_t::vertex_idx_010, frustum_t::vertex_idx_110, frustum_t::vertex_idx_011);
f.planes[frustum_t::plane_idx_pos_z] = build_plane(frustum_t::vertex_idx_001, frustum_t::vertex_idx_011, frustum_t::vertex_idx_101);
// proper sign
auto const center = invM * ndc[comp_t(0.5f, 0.5f, 0.5f)];
if (signed_distance(center, f.planes[0]) > ScalarT(0))
{
f.planes[frustum_t::plane_idx_neg_x] = -f.planes[frustum_t::plane_idx_neg_x];
f.planes[frustum_t::plane_idx_neg_y] = -f.planes[frustum_t::plane_idx_neg_y];
f.planes[frustum_t::plane_idx_neg_z] = -f.planes[frustum_t::plane_idx_neg_z];
f.planes[frustum_t::plane_idx_pos_x] = -f.planes[frustum_t::plane_idx_pos_x];
f.planes[frustum_t::plane_idx_pos_y] = -f.planes[frustum_t::plane_idx_pos_y];
f.planes[frustum_t::plane_idx_pos_z] = -f.planes[frustum_t::plane_idx_pos_z];
}
return f;
}
}
......@@ -13,6 +13,12 @@
namespace tg
{
template <int D, class ScalarT>
[[nodiscard]] constexpr plane<D, ScalarT> operator-(plane<D, ScalarT> const& p)
{
return {-p.normal, -p.dis};
}
template <int D, class ScalarT>
[[nodiscard]] constexpr plane<D, ScalarT> plane_of(plane<D, ScalarT> const& p)
{
......
......@@ -3,6 +3,7 @@
#include <typed-geometry/feature/assert.hh>
#include <typed-geometry/types/scalars/default.hh>
#include <typed-geometry/types/span.hh>
namespace tg
{
......@@ -33,5 +34,25 @@ struct array
TG_CONTRACT(i < N);
return _values[i];
}
constexpr bool operator==(span<T const> rhs) const noexcept
{
if (N != rhs.size())
return false;
for (size_t i = 0; i < N; ++i)
if (!(_values[i] == rhs[i]))
return false;
return true;
}
constexpr bool operator!=(span<T const> rhs) const noexcept
{
if (N != rhs.size())
return true;
for (size_t i = 0; i < N; ++i)
if (_values[i] != rhs[i])
return true;
return false;
}
};
}
......@@ -5,49 +5,73 @@
#include <typed-geometry/types/scalars/default.hh>
#include "../pos.hh"
#include "../vec.hh"
#include "aabb.hh"
#include "plane.hh"
// A representation of a view frustum
// NOTE: the storage is not minimal. halfspaces AND endpoints are stored
namespace tg
{
template <class ScalarT>
template <int D, class ScalarT, class TraitsT = default_object_tag>
struct frustum;
// Common frustum types
using ffrustum = frustum<f32>;
using dfrustum = frustum<f64>;
using frustum3 = frustum<3, f32>;
using ffrustum3 = frustum<3, f32>;
using dfrustum3 = frustum<3, f64>;
// ======== IMPLEMENTATION ========
template <class ScalarT>
struct frustum
template <class ScalarT, class TraitsT>
struct frustum<3, ScalarT, TraitsT>
{
// frustum represented by 6 planes
array<tg::plane<3, ScalarT>, 6> planes;
enum
{
plane_idx_neg_x = 0,
plane_idx_neg_y,
plane_idx_neg_z,
plane_idx_pos_x,
plane_idx_pos_y,
plane_idx_pos_z,
plane_count
};
constexpr frustum() = default;
explicit constexpr frustum(array<tg::plane<3, ScalarT>, 6> const& planes) : planes(planes)
{ /* TG_CONTRACT(..); */
}
enum
{
vertex_idx_000 = 0,
vertex_idx_001,
vertex_idx_010,
vertex_idx_011,
vertex_idx_100,
vertex_idx_101,
vertex_idx_110,
vertex_idx_111,
vertex_count,
};
// extract frustum from a view-projection-matrix (proj * view)
constexpr frustum(mat<4, 4, ScalarT> const& m); // requires tg.hh
/// frustum represented by 6 planes
/// NOTE: planes point outwards, i.e. positive signed distance is OUTSIDE
array<plane<3, ScalarT>, plane_count> planes;
[[nodiscard]] bool operator==(frustum const& rhs) const
{
for (auto i = 0u; i < planes.size(); ++i)
{
if (planes[i] != rhs.planes[i])
return false;
}
return true;
}
[[nodiscard]] bool operator!=(frustum const& rhs) const { return !operator==(rhs); }
/// frustum represented by 8 corner vertices
array<pos<3, ScalarT>, vertex_count> vertices;
/// extract frustum from a view-projection-matrix (proj * view)
/// uses -1..1 NDC coordinates by default (but is configurable)
/// does not assume handedness of matrix
/// needs functions/objects/frustum.hh
/// or feature/objects.hh
/// or tg.hh
constexpr static frustum from_view_proj(mat<4, 4, ScalarT> const& m, aabb<3, ScalarT> const& ndc = aabb<3, ScalarT>(ScalarT(-1), ScalarT(1)));
constexpr bool operator==(frustum const& rhs) const { return planes == rhs.planes; }
constexpr bool operator!=(frustum const& rhs) const { return planes != rhs.planes; }
};
template <class I, int D, class ScalarT, class TraitsT>
constexpr void introspect(I&& i, frustum<ScalarT>& v)
constexpr void introspect(I&& i, frustum<D, ScalarT, TraitsT>& v)
{
i(v.planes, "planes");
}
......
......@@ -57,7 +57,7 @@ struct plane
// <x, normal> = dis
dir_t normal;
scalar_t dis; // NOTE: this is not the "d" from the plane equation, but -d
scalar_t dis = scalar_t(0); // NOTE: this is not the "d" from the plane equation, but -d
constexpr plane() = default;
constexpr plane(dir_t n, scalar_t d) : normal(n), dis(d) {}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment