Skip to content

Collision Testing

SolarLune edited this page Dec 12, 2022 · 10 revisions

Collision testing is done using BoundingObjects, a specific class of Node. There are currently four kinds of BoundingObjects.

  • BoundingAABB - An axis-aligned bounding box (or cube). An AABB cannot rotate (or rather, rotating it makes for a differently sized cube that is still axis-aligned).
  • BoundingCapsule - A capsule, which can rotate and has a customizeable radius and height.
  • BoundingSphere - A 3D sphere, with customizeable radius.
  • BoundingTriangles - A triangle mesh, primarily used for terrain or other static objects.

NOTE: Currently, AABB > Triangles and Triangles > Triangles collisions are buggy.

Checking for collisions

To check for collisions, you simply call BoundingObject.Colliding(otherBounds) to see if an object is intersecting with another. You can also get more detail with BoundingObject.Collision(otherBounds), which returns a Collision struct. A Collision is the result of at least one Intersection between two BoundingObjects. Each Intersection struct contains information regarding an intersection between the two Bounds objects, like the contact point, the collision normal, the slope, and the MTV (or minimum translation vector). You can use the MTV to easily move the intersecting object away from the other object. You can also get a few averaged values from the Collision struct itself. Two objects can collide in multiple locations (thereby making for multiple individual Intersections).

You can also check against multiple objects at the same time and handle collisions more smoothly using BoundingObject.CollisionTest() - this functions allow you to supply a CollisionTestSettings struct, which currently allows for two things:

  1. You can specify a slice of multiple INodes to test against. When you pass a Node to these functions, they will test both the Nodes themselves (if BoundingObjects), as well as all of their children / grandchildren, recursively. This means you can test, for example, a Model for collision (as Tetra3D will test its BoundingObject children in this case), or compose a complex shape out of smaller individual BoundingObjects. Of course, if you want to be more specific, then you can just test the BoundingObjects specifically.
  2. You can define or pass a HandleCollision() function, which can take a collision and handle it. The difference between using this callback function and manually stepping through collisions that hte CollisionTest() function returns, is that the HandleCollision() function gets called after each individual collision is found. This means that, say, if you found a collision between a player and the ground, and then moved the player to not be in collision with the ground anymore, any other potential collisions where the player was would not be detected.

While not currently implemented yet, ray testing would also be very useful to add and is on the todo list.

Creating Bounds

There are two ways to create bounding objects in Tetra3D - one way is to do so in code, by simply creating the desired Node and adding it to the node tree. The other way is to do so from Blender directly. If you install the Blender Add-on, you can specify the Bounds type of an object in Blender, which will then be instantiated as a child underneath the object when creating the scene. See the Blender Add-on page for more information.

Performance

In terms of performance, in descending order of efficiency, bounding collision types can be ranked as follows:

BoundingSphere > BoundingCapsule > BoundingAABB > BoundingTriangles

Being that BoundingSpheres are the most efficient collision shape, if you can use BoundingSpheres for collision testing, do so.

Broadphase Collision

Broadphase collision has been added for AABB+BoundingTriangles, Capsule+BoundingTriangles, and Sphere+BoundingTriangles collision checks. The basic idea behind this is to avoid checking for collision against triangles if they're simply too far away from the colliding object. This is done by checking the colliding object against a broadphase AABB at various grid positions surrounding the triangle mesh; if the colliding object collides with the broadphase AABB object at these positions, then we can check the triangles therein for collision. If not, then we can skip those triangles.

By default, the Broadphase grid is broken up into large squares, each of which are about 20 Blender Units large. Note that the grid divisions don't change in size depending on the triangle mesh's dimensions - the grid's overall size changes to cover the triangle mesh, but the cube's divisions would still be 20 Blender Units large (so if your triangle mesh is 19x10x13 Blender Units, you'll have exactly one 20x20x20 cube. Conversely, if your mesh is 50x10x100, you'll have 3 * 1 * 5 = 15 cubes).

You can customize this, though - if you have, for example, a rather large triangle mesh with relatively few triangles, you might desire a coarser broadphase grid, perhaps one where each cell covers 100 Blender Units, rather than just 20. This would limit the number of broadphase checks Tetra3d would need to perform.

To customize the broadphase settings, you can alter the broadphase grid's cell size, either in code with BoundingTriangles.Broadphase.Resize() (which takes the desired cell size), or in Blender, by checking the "Custom Broadphase Size" checkbox next to the bounds dropdown and then customizing the grid's cell size. You can turn off the broadphase checks by setting the broadphase size to 0, or calling BoundingTriangles.DisableBroadphase().

Custom broadphase setting

Clone this wiki locally