mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
7.7 KiB
224 lines
7.7 KiB
|
8 years ago
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
||
|
|
Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
copy of this software and associated documentation files (the "Software"),
|
||
|
|
to deal in the Software without restriction, including without limitation
|
||
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
Software is furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included
|
||
|
|
in all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
|
DEALINGS IN THE SOFTWARE.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <random>
|
||
|
|
#include <tuple>
|
||
|
|
#include <utility>
|
||
|
8 years ago
|
#include <Corrade/TestSuite/Tester.h>
|
||
|
8 years ago
|
|
||
|
|
#include "Magnum/Math/Angle.h"
|
||
|
8 years ago
|
#include "Magnum/Math/Intersection.h"
|
||
|
8 years ago
|
|
||
|
8 years ago
|
namespace Magnum { namespace Math { namespace Test {
|
||
|
8 years ago
|
|
||
|
|
template<class T> bool rangeFrustumNaive(const Math::Range3D<T>& box, const Math::Frustum<T>& frustum) {
|
||
|
|
for(const Math::Vector4<T>& plane: frustum.planes()) {
|
||
|
|
bool cornerHit = 0;
|
||
|
|
|
||
|
|
for(UnsignedByte c = 0; c != 8; ++c) {
|
||
|
|
const Math::Vector3<T> corner = Math::lerp(box.min(), box.max(), Math::BoolVector<3>{c});
|
||
|
|
|
||
|
|
if(Distance::pointPlaneScaled<T>(corner, plane) >= T(0)) {
|
||
|
|
cornerHit = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* All corners are outside this plane */
|
||
|
|
if(!cornerHit) return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
/*
|
||
|
|
Ground truth, slow sphere cone intersection - calculating exact distances,
|
||
|
|
no optimizations, no precomputations
|
||
|
|
|
||
|
|
sphereCenter Sphere center
|
||
|
|
radius Sphere radius
|
||
|
|
origin Origin of the cone
|
||
|
|
normal Cone normal
|
||
|
|
angle Cone opening angle (0 < angle < pi)
|
||
|
|
|
||
|
|
Returns true if the sphere intersects with the cone.
|
||
|
|
*/
|
||
|
8 years ago
|
template<class T> bool sphereConeGT(
|
||
|
|
const Math::Vector3<T>& sphereCenter, const T radius,
|
||
|
|
const Math::Vector3<T>& origin, const Math::Vector3<T>& normal, const Math::Rad<T> angle) {
|
||
|
|
const Math::Vector3<T> diff = sphereCenter - origin;
|
||
|
|
const Math::Vector3<T> dir = diff.normalized();
|
||
|
|
const Math::Rad<T> halfAngle = angle/T(2);
|
||
|
|
|
||
|
|
/* Compute angle between normal and point */
|
||
|
|
const Math::Rad<T> actual = Math::acos(dot(normal, dir));
|
||
|
|
|
||
|
|
/* Distance from cone surface */
|
||
|
|
const T distanceFromCone = Math::sin(actual - halfAngle)*diff.length();
|
||
|
|
|
||
|
8 years ago
|
/* Either the sphere center lies in cone, or cone is max radius away from
|
||
|
|
the cone */
|
||
|
8 years ago
|
return actual <= halfAngle || distanceFromCone <= radius;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T>
|
||
|
|
Math::Matrix4<T> coneViewFromCone(const Math::Vector3<T>& origin, const Math::Vector3<T>& normal) {
|
||
|
|
return Math::Matrix4<T>::lookAt(origin, origin + normal, Math::Vector3<T>::yAxis()).inverted();
|
||
|
|
}
|
||
|
|
|
||
|
|
typedef Math::Vector2<Float> Vector2;
|
||
|
|
typedef Math::Vector3<Float> Vector3;
|
||
|
|
typedef Math::Vector4<Float> Vector4;
|
||
|
|
typedef Math::Matrix4<Float> Matrix4;
|
||
|
|
typedef Math::Frustum<Float> Frustum;
|
||
|
|
typedef Math::Range3D<Float> Range3D;
|
||
|
|
typedef Math::Deg<Float> Deg;
|
||
|
|
typedef Math::Rad<Float> Rad;
|
||
|
|
|
||
|
|
struct IntersectionBenchmark: Corrade::TestSuite::Tester {
|
||
|
|
explicit IntersectionBenchmark();
|
||
|
|
|
||
|
|
void rangeFrustumNaive();
|
||
|
|
void rangeFrustum();
|
||
|
|
|
||
|
|
void rangeCone();
|
||
|
|
|
||
|
|
void sphereFrustum();
|
||
|
|
|
||
|
|
void sphereConeNaive();
|
||
|
|
void sphereCone();
|
||
|
|
void sphereConeView();
|
||
|
|
|
||
|
|
Frustum _frustum;
|
||
|
|
std::tuple<Vector3, Vector3, Rad> _cone;
|
||
|
|
Matrix4 _coneView;
|
||
|
|
|
||
|
|
std::vector<Range3D> _boxes;
|
||
|
|
std::vector<Vector4> _spheres;
|
||
|
|
};
|
||
|
|
|
||
|
|
IntersectionBenchmark::IntersectionBenchmark() {
|
||
|
|
addBenchmarks({&IntersectionBenchmark::rangeFrustumNaive,
|
||
|
|
&IntersectionBenchmark::rangeFrustum,
|
||
|
|
|
||
|
|
&IntersectionBenchmark::rangeCone,
|
||
|
|
|
||
|
|
&IntersectionBenchmark::sphereFrustum,
|
||
|
|
|
||
|
|
&IntersectionBenchmark::sphereConeNaive,
|
||
|
|
&IntersectionBenchmark::sphereCone,
|
||
|
8 years ago
|
&IntersectionBenchmark::sphereConeView}, 10);
|
||
|
8 years ago
|
|
||
|
|
/* Generate random data for the benchmarks */
|
||
|
|
std::random_device rnd;
|
||
|
|
std::mt19937 g(rnd());
|
||
|
|
/* Position distribution */
|
||
|
|
std::uniform_real_distribution<float> pd(-10.0f, 10.0f);
|
||
|
|
/* Cone angle distribution */
|
||
|
|
std::uniform_real_distribution<float> ad(1.0f, 179.0f);
|
||
|
|
|
||
|
|
_cone = std::make_tuple(Vector3{pd(g), pd(g), pd(g)},
|
||
|
|
Vector3{pd(g), pd(g), pd(g)}.normalized(),
|
||
|
|
Rad(Deg(ad(g))));
|
||
|
|
_coneView = coneViewFromCone(std::get<0>(_cone), std::get<1>(_cone));
|
||
|
|
_frustum = Frustum::fromMatrix(_coneView*Matrix4::perspectiveProjection(std::get<2>(_cone), 1.0f, 0.001f, 100.0f));
|
||
|
|
|
||
|
|
_boxes.reserve(512);
|
||
|
|
_spheres.reserve(512);
|
||
|
|
for(int i = 0; i < 512; ++i) {
|
||
|
|
Vector3 center{pd(g), pd(g), pd(g)};
|
||
|
|
Vector3 extents{pd(g), pd(g), pd(g)};
|
||
|
|
_boxes.emplace_back(center - extents, center + extents);
|
||
|
|
_spheres.emplace_back(center, extents.length());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::rangeFrustumNaive() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) for(auto& box: _boxes) {
|
||
|
|
b = b ^ Test::rangeFrustumNaive<Float>(box, _frustum);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::rangeFrustum() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) for(auto& box: _boxes) {
|
||
|
|
b = b ^ Intersection::rangeFrustum(box, _frustum);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::rangeCone() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) {
|
||
|
|
const Float tanAngle = Math::tan(std::get<2>(_cone));
|
||
|
|
const Float tanAngleSqPlusOne = tanAngle*tanAngle + 1.0f;
|
||
|
|
for(auto& box: _boxes) {
|
||
|
|
b = b ^ Intersection::rangeCone(box, std::get<0>(_cone), std::get<1>(_cone), tanAngleSqPlusOne);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::sphereFrustum() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) for(auto& sphere: _spheres) {
|
||
|
|
b = b ^ Intersection::sphereFrustum(sphere.xyz(), sphere.w(), _frustum);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::sphereConeNaive() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) for(auto& sphere: _spheres) {
|
||
|
|
b = b ^ sphereConeGT<Float>(sphere.xyz(), sphere.w(), std::get<0>(_cone), std::get<1>(_cone), std::get<2>(_cone));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::sphereCone() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) {
|
||
|
|
const Float sinAngle = Math::sin(std::get<2>(_cone));
|
||
|
|
const Float tanAngle = Math::tan(std::get<2>(_cone));
|
||
|
|
const Float tanAngleSqPlusOne = tanAngle*tanAngle + 1.0f;
|
||
|
|
for(auto& sphere: _spheres) {
|
||
|
|
b = b ^ Intersection::sphereCone(sphere.xyz(), sphere.w(), std::get<0>(_cone), std::get<1>(_cone), sinAngle, tanAngleSqPlusOne);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void IntersectionBenchmark::sphereConeView() {
|
||
|
|
volatile bool b = false;
|
||
|
|
CORRADE_BENCHMARK(50) {
|
||
|
|
const Float sinAngle = Math::sin(std::get<2>(_cone));
|
||
|
|
const Float tanAngle = Math::tan(std::get<2>(_cone));
|
||
|
|
for(auto& sphere: _spheres) {
|
||
|
8 years ago
|
b = b ^ Intersection::sphereConeView(sphere.xyz(), sphere.w(), _coneView, sinAngle, tanAngle);
|
||
|
8 years ago
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
8 years ago
|
}}}
|
||
|
8 years ago
|
|
||
|
8 years ago
|
CORRADE_TEST_MAIN(Magnum::Math::Test::IntersectionBenchmark)
|