Collision detection
Collection of simple shapes for high performance collision detection.
Contents
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 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.
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.
One-dimensional shapes
- Shapes::
Point*D — Point. - Shapes::
Line*D — Infinite line, defined by two points. - Shapes::
LineSegment*D — Line segment, defined by starting and ending point.
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.
Two-dimensional shapes
- Shapes::
Plane — Infinite plane, defined by position and normal (3D only)
Three-dimensional shapes
- Shapes::
Sphere*D — Sphere defined by position and radius. - Shapes::
InvertedSphere*D — Inverted sphere defined by position and radius. - Shapes::
Cylinder*D — Infinite cylinder defined by line and radius. - Shapes::
Capsule*D — Capsule defined by cylinder start and end point and radius. - Shapes::
AxisAlignedBox*D — Axis-aligned box. - Shapes::
Box*D — Unit-size box with assigned transformation matrix.
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.
Creating shape compositions
Shapes can be composed together using one of three available logical operations: AND, OR and NOT. These operations are mapped to &&
, ||
and !
operators, so for example creating negation of logical OR of line segment and point is simple as this:
Shapes::LineSegment3D segment; Shapes::Point3D point; Shapes::Composition3D composition = !(segment || point);
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 &&
operator — the collision is initially detected on first (simplified) shape and then on the other:
Shapes::Sphere3D sphere; Shapes::Box3D box; Shapes::AxisAlignedBox3D simplified; Shapes::Composition3D composition = simplified && (sphere || box);
Detecting shape collisions
Shape pairs which have collision occurence detection implemented can be tested for collision using the %
operator. The operator returns boolean describing whether the collision happened or not. Example:
Shapes::Point3D point; Shapes::Sphere3D sphere; bool collide = point % sphere;
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 Shapes::%
operator mentioned above, this operation is not commutative. See Shapes::
const Shapes::Collision3D c = point/sphere; if(c) { Vector3 translation = c.separationNormal()*c.separationDistance(); // translate point by translation... }
Integration with scene graph
Shape can be attached to object in the scene using Shapes::%
and /
operators above. Please note that the shape group caches the absolute transformations of all shapes and thus you need to explicitly call Shapes::
Scenegraph-flavored equivalent to the above code:
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()); }
There is also Shapes::nullptr
, if there isn't any collision).
You can also use DebugTools::