|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
/** @page shapes Collision detection
|
|
|
|
|
@brief Collection of simple shapes for high performance collision detection.
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
@m_footernavigation
|
|
|
|
|
|
|
|
|
|
@deprecated This library is a failed design experiment and is scheduled for
|
|
|
|
|
removal in a future release. Related geometry algorithms were moved to
|
|
|
|
|
@ref Magnum::Math::Distance "Math::Distance" and
|
|
|
|
|
@ref Magnum::Math::Intersection "Math::Intersection"; if you need a
|
|
|
|
|
full-fledged physics library, please have look at
|
|
|
|
|
[Bullet](https://bulletphysics.org), which has Magnum integration in
|
|
|
|
|
@ref Magnum::BulletIntegration "BulletIntegration" or at
|
|
|
|
|
[Box2D](https://box2d.org/), which has a @ref examples-box2d "Magnum example"
|
|
|
|
|
as well.
|
|
|
|
|
|
|
|
|
|
The essential thing in collision detection is to define a complex object with
|
|
|
|
|
collection of simple shapes, for which it is easy to detect collisions. The
|
|
|
|
|
library is contained in @ref Shapes namespace, see its documentation for more
|
|
|
|
|
information about building and usage with CMake.
|
|
|
|
|
|
|
|
|
|
These shapes can be either one-, two- or three-dimensional and they can be
|
|
|
|
|
grouped together using various operations.
|
|
|
|
|
|
|
|
|
|
@section shapes-collection Available shapes
|
|
|
|
|
|
|
|
|
|
Magnum provides a set of simple shapes for collision detection, similarly to
|
|
|
|
|
what is found in many other collision detection libraries. Additionally some
|
|
|
|
|
shapes are provided in inverted form --- e.g. inverted box detects collisions on
|
|
|
|
|
outside instead of inside, which might be useful for example to create bounds
|
|
|
|
|
around platformer game level.
|
|
|
|
|
|
|
|
|
|
@subsection shapes-1D One-dimensional shapes
|
|
|
|
|
|
|
|
|
|
- @ref Shapes::Point "Shapes::Point*D" --- @copybrief Shapes::Point
|
|
|
|
|
- @ref Shapes::Line "Shapes::Line*D" --- @copybrief Shapes::Line
|
|
|
|
|
- @ref Shapes::LineSegment "Shapes::LineSegment*D" --- @copybrief Shapes::LineSegment
|
|
|
|
|
|
|
|
|
|
Because of numerical instability it's not possible to detect collisions of
|
|
|
|
|
line and point. Collision of two lines can be detected only in 2D.
|
|
|
|
|
|
|
|
|
|
@subsection shapes-2D Two-dimensional shapes
|
|
|
|
|
|
|
|
|
|
- @ref Shapes::Plane --- @copybrief Shapes::Plane
|
|
|
|
|
|
|
|
|
|
@subsection shapes-3D Three-dimensional shapes
|
|
|
|
|
|
|
|
|
|
- @ref Shapes::Sphere "Shapes::Sphere*D" --- @copybrief Shapes::Sphere
|
|
|
|
|
- @ref Shapes::InvertedSphere "Shapes::InvertedSphere*D" --- @copybrief Shapes::InvertedSphere
|
|
|
|
|
- @ref Shapes::Cylinder "Shapes::Cylinder*D" --- @copybrief Shapes::Cylinder
|
|
|
|
|
- @ref Shapes::Capsule "Shapes::Capsule*D" --- @copybrief Shapes::Capsule
|
|
|
|
|
- @ref Shapes::AxisAlignedBox "Shapes::AxisAlignedBox*D" --- @copybrief Shapes::AxisAlignedBox
|
|
|
|
|
- @ref Shapes::Box "Shapes::Box*D" --- @copybrief Shapes::Box
|
|
|
|
|
|
|
|
|
|
The easiest (and most efficient) shape combination for detecting collisions
|
|
|
|
|
is point and sphere, followed by two spheres. Computing collision of two boxes
|
|
|
|
|
is least efficient.
|
|
|
|
|
|
|
|
|
|
@section shapes-composition Creating shape compositions
|
|
|
|
|
|
|
|
|
|
Shapes can be composed together using one of three available logical
|
|
|
|
|
operations: AND, OR and NOT. These operations are mapped to @cpp && @ce, @cpp || @ce
|
|
|
|
|
and @cpp ! @ce operators, so for example creating negation of logical OR of
|
|
|
|
|
line segment and point is simple as this:
|
|
|
|
|
|
|
|
|
|
@code{.cpp}
|
|
|
|
|
Shapes::LineSegment3D segment;
|
|
|
|
|
Shapes::Point3D point;
|
|
|
|
|
|
|
|
|
|
Shapes::Composition3D composition = !(segment || point);
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@note Logical operations are not the same as set operations --- intersection of
|
|
|
|
|
two spheres will not generate any collision if they are disjoint, but
|
|
|
|
|
logical AND will if the object collides with both of them.
|
|
|
|
|
|
|
|
|
|
@subsection shapes-simplification Providing simplified version of shape for better performance
|
|
|
|
|
|
|
|
|
|
If there are many shapes composed together, it might hurt performance of
|
|
|
|
|
collision detection, because it might be testing collision with more shapes
|
|
|
|
|
than necessary. It's then good to specify simplified version of such shape,
|
|
|
|
|
so the collision detection is done on the complex one if and only if collision
|
|
|
|
|
was detected with the simplified shape. It is in fact logical AND using the
|
|
|
|
|
@cpp && @ce operator --- the collision is initially detected on first
|
|
|
|
|
(simplified) shape and then on the other:
|
|
|
|
|
|
|
|
|
|
@code{.cpp}
|
|
|
|
|
Shapes::Sphere3D sphere;
|
|
|
|
|
Shapes::Box3D box;
|
|
|
|
|
Shapes::AxisAlignedBox3D simplified;
|
|
|
|
|
|
|
|
|
|
Shapes::Composition3D composition = simplified && (sphere || box);
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section shapes-collisions Detecting shape collisions
|
|
|
|
|
|
|
|
|
|
Shape pairs which have collision occurence detection implemented can be tested
|
|
|
|
|
for collision using the @cpp % @ce operator. The operator returns boolean
|
|
|
|
|
describing whether the collision happened or not. Example:
|
|
|
|
|
|
|
|
|
|
@code{.cpp}
|
|
|
|
|
Shapes::Point3D point;
|
|
|
|
|
Shapes::Sphere3D sphere;
|
|
|
|
|
|
|
|
|
|
bool collide = point % sphere;
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
As this is useful for e.g. menu handling and simple particle systems, for
|
|
|
|
|
serious physics you often need more information like contact point, separation
|
|
|
|
|
normal and penetration depth. For shape pairs which have implemented this
|
|
|
|
|
detailed collision detection you can use the `/` operator, which returns
|
|
|
|
|
@ref Shapes::Collision object. Note that unlike with the `%` operator mentioned
|
|
|
|
|
above, this operation is not commutative. See @ref Shapes::Collision class
|
|
|
|
|
documentation for more information about the returned data. Example:
|
|
|
|
|
|
|
|
|
|
@code{.cpp}
|
|
|
|
|
const Shapes::Collision3D c = point/sphere;
|
|
|
|
|
if(c) {
|
|
|
|
|
Vector3 translation = c.separationNormal()*c.separationDistance();
|
|
|
|
|
// translate point by translation...
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section shapes-scenegraph Integration with scene graph
|
|
|
|
|
|
|
|
|
|
Shape can be attached to object in the scene using @ref Shapes::Shape feature.
|
|
|
|
|
In conjunction with @ref Shapes::ShapeGroup you can use
|
|
|
|
|
@ref Shapes::Shape::collides() and @ref Shapes::Shape::collision() similarly to
|
|
|
|
|
the @cpp % @ce and @cpp / @ce operators above. Please note that the shape group
|
|
|
|
|
caches the absolute transformations of all shapes and thus you need to
|
|
|
|
|
explicitly call @ref Shapes::ShapeGroup::setClean() before computing the
|
|
|
|
|
collisions if you did any modifications to the objects in the scene.
|
|
|
|
|
|
|
|
|
|
Scenegraph-flavored equivalent to the above code:
|
|
|
|
|
|
|
|
|
|
@code{.cpp}
|
|
|
|
|
Shapes::ShapeGroup3D shapes;
|
|
|
|
|
Object3D& a;
|
|
|
|
|
auto aShape = new Shapes::Shape<Shapes::Sphere3D>(a, {{}, 23.0f}, &shapes);
|
|
|
|
|
|
|
|
|
|
Object3D& b;
|
|
|
|
|
auto bShape = new Shapes::Shape<Shapes::Point3D>(b, {{1.0f, 0.2f, 3.0f}}, &shapes);
|
|
|
|
|
|
|
|
|
|
// Translate point so the objects no longer collide
|
|
|
|
|
shapes.setClean();
|
|
|
|
|
if(aShape->collides(*bShape)) {
|
|
|
|
|
const Shapes::Collision3D c = aShape->collision(*bShape);
|
|
|
|
|
b.translate(c.separationNormal()*c.separationDistance());
|
|
|
|
|
}
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
There is also @ref Shapes::ShapeGroup::firstCollision() function which returns
|
|
|
|
|
arbitrary first collision for given shape in whole group (or @cpp nullptr @ce,
|
|
|
|
|
if there isn't any collision).
|
|
|
|
|
|
|
|
|
|
You can also use @ref DebugTools::ShapeRenderer to visualize the shapes for
|
|
|
|
|
debugging purposes. See also @ref scenegraph for introduction.
|
|
|
|
|
*/
|
|
|
|
|
}
|