geom: add simple frustum class

This commit is contained in:
Danny Robson 2018-03-13 22:37:40 +11:00
parent 47efd293c9
commit b1276519ef
7 changed files with 220 additions and 7 deletions

View File

@ -205,6 +205,8 @@ list (
geom/cylinder.hpp
geom/ellipse.cpp
geom/ellipse.hpp
geom/frustum.cpp
geom/frustum.hpp
geom/iostream.cpp
geom/iostream.hpp
geom/ops.hpp
@ -450,6 +452,7 @@ if (TESTS)
format
geom/aabb
geom/ray
geom/frustum
hash/checksum
hash/crc
hash/fasthash

68
geom/frustum.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "frustum.hpp"
using util::geom::frustum;
///////////////////////////////////////////////////////////////////////////////
template <typename T>
frustum<T>::frustum (const matrix4<T> &transform)
{
// left
planes[0].coefficients[0] = transform[3][0] + transform[0][0];
planes[0].coefficients[1] = transform[3][1] + transform[0][1];
planes[0].coefficients[2] = transform[3][2] + transform[0][2];
planes[0].coefficients[3] = transform[3][3] + transform[0][3];
// Right clipping plane
planes[1].coefficients[0] = transform[3][0] - transform[0][0];
planes[1].coefficients[1] = transform[3][1] - transform[0][1];
planes[1].coefficients[2] = transform[3][2] - transform[0][2];
planes[1].coefficients[3] = transform[3][3] - transform[0][3];
// Top clipping plane
planes[2].coefficients[0] = transform[3][0] - transform[1][0];
planes[2].coefficients[1] = transform[3][1] - transform[1][1];
planes[2].coefficients[2] = transform[3][2] - transform[1][2];
planes[2].coefficients[3] = transform[3][3] - transform[1][3];
// Bottom clipping plane
planes[3].coefficients[0] = transform[3][0] + transform[1][0];
planes[3].coefficients[1] = transform[3][1] + transform[1][1];
planes[3].coefficients[2] = transform[3][2] + transform[1][2];
planes[3].coefficients[3] = transform[3][3] + transform[1][3];
// Near clipping plane
planes[4].coefficients[0] = transform[3][0] + transform[2][0];
planes[4].coefficients[1] = transform[3][1] + transform[2][1];
planes[4].coefficients[2] = transform[3][2] + transform[2][2];
planes[4].coefficients[3] = transform[3][3] + transform[2][3];
// Far clipping plane
planes[5].coefficients[0] = transform[3][0] - transform[2][0];
planes[5].coefficients[1] = transform[3][1] - transform[2][1];
planes[5].coefficients[2] = transform[3][2] - transform[2][2];
planes[5].coefficients[3] = transform[3][3] - transform[2][3];
for (auto &p: planes)
p = normalised (p);
}
///////////////////////////////////////////////////////////////////////////////
template struct util::geom::frustum<float>;

68
geom/frustum.hpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_GEOM_FRUSTUM_HPP
#define CRUFT_UTIL_GEOM_FRUSTUM_HPP
#include "../matrix.hpp"
#include "plane.hpp"
#include "aabb.hpp"
#include <array>
#include <cstddef>
namespace util::geom {
/// a viewing frustrum comprised of 4 axis planes, a near plane, and a far
/// plane. it may describe something other than a perspective projection
/// (eg, an orthographic projection)
template <typename ValueT>
struct frustum {
explicit frustum (const matrix<4,4,ValueT>&);
std::array<plane<3,ValueT>, 6> planes;
};
using frustum3f = frustum<float>;
/// tests whether a frustum and an aabb overlap
///
/// XXX: there may be occasional false positives.
template <size_t S, typename T>
bool
intersects (const frustum<T> &f, const aabb<S,T> &b)
{
for (const auto &p: f.planes) {
const auto n = normal (p);
const auto positive = n > 0;
const auto lo = select (positive, b.lo, b.hi);
const auto hi = select (positive, b.hi, b.lo);
if (dot (n, lo) + p.coefficients[S] > 0)
return false; // OUTSIDE
if (dot (n, hi) + p.coefficients[S] >= 0)
return true; //INTERSECT
}
// INSIDE
return true;
}
};
#endif

View File

@ -11,11 +11,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_FWD_HPP
#define __UTIL_GEOM_FWD_HPP
#ifndef CRUFT__UTIL_GEOM_FWD_HPP
#define CRUFT__UTIL_GEOM_FWD_HPP
#include <cstdlib>
@ -28,6 +28,8 @@ namespace util::geom {
template <size_t S, typename T> struct rect;
template <size_t S, typename T> struct cylinder;
template <size_t S, typename T> struct tri;
template <typename T> struct frustum;
}
#endif

View File

@ -11,12 +11,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2018 Danny Robson <danny@nerdcruft.net>
*/
#include "iostream.hpp"
#include "sphere.hpp"
#include "plane.hpp"
#include "frustum.hpp"
#include "../coord/iostream.hpp"
@ -32,3 +34,30 @@ util::geom::operator<< (std::ostream &os, util::geom::sphere<S,T> s)
//-----------------------------------------------------------------------------
template std::ostream& util::geom::operator<< (std::ostream&, util::geom::sphere<2,float>);
template std::ostream& util::geom::operator<< (std::ostream&, util::geom::sphere<3,float>);
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
std::ostream&
util::geom::operator<< (std::ostream &os, plane<S,T> val)
{
return os << val.coefficients;
}
//-----------------------------------------------------------------------------
template std::ostream& util::geom::operator<< (std::ostream&, plane<2,float>);
template std::ostream& util::geom::operator<< (std::ostream&, plane<3,float>);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
std::ostream&
util::geom::operator<< (std::ostream &os, frustum<T> val)
{
return os << "[ " << util::make_infix (val.planes) << " ]";
}
//-----------------------------------------------------------------------------
template std::ostream& util::geom::operator<< (std::ostream&, frustum<float>);

View File

@ -11,11 +11,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_IOSTREAM_HPP
#define __UTIL_GEOM_IOSTREAM_HPP
#ifndef CRUFT_UTIL_GEOM_IOSTREAM_HPP
#define CRUFT_UTIL_GEOM_IOSTREAM_HPP
#include "fwd.hpp"
@ -35,6 +35,14 @@ namespace util::geom {
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, sphere<S,T>);
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, plane<S,T>);
template <typename T>
std::ostream&
operator<< (std::ostream&, frustum<T>);
}
#endif

35
test/geom/frustum.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "tap.hpp"
#include "geom/frustum.hpp"
#include "geom/aabb.hpp"
#include "matrix.hpp"
#include "geom/iostream.hpp"
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
int
main ()
{
util::TAP::logger tap;
const util::geom::frustum3f origin90 (
util::perspective (90.f, 1.f, {0.01f, 1.f})
);
static const struct {
util::geom::aabb3f box;
bool intersects;
const char *message;
} TESTS[] = {
{ { { -1, -1, -1 }, { 1, 1, 1 } }, true, "covers origin with unit radius" },
{ { { -9, -9, -9 }, { -8, -8, -8 } }, false, "out of view negative" },
{ { { -1, -1, 2 }, { 1, 1, 3 } }, false, "past far plane" },
};
for (const auto &t: TESTS) {
tap.expect_eq (intersects (origin90, t.box), t.intersects, "origin frustrum, %s", t.message);
}
return tap.status ();
};