-
Notifications
You must be signed in to change notification settings - Fork 18
Collision Testing
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.
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:
- You can specify a slice of multiple INodes to test against.
- You can define or pass a collision callback function that takes a collision and handles it. The callback function returns a boolean indicating whether to continue stepping through all other collisions detected or not, sorted in order of distance to the calling object.
You can also perform quick collision tests using the tetra3d.CollisionTest
functions, rather than creating BoundingObjects.
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 in the Object panel of an object. The appropriate BoundingObject will then be instantiated as a child underneath the object when loading the scene. See the Blender Add-on page for more information.
In terms of performance, in descending order of efficiency, bounding collision types can be ranked as follows:
BoundingSphere > BoundingAABB > BoundingCapsule > BoundingTriangles
Being that BoundingSpheres are the most efficient collision shape, if you can use BoundingSpheres for collision testing, do so.
Broadphase collision has been added for AABB + Triangles, Capsule + Triangles, and Sphere + Triangles 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 BoundingObject. Internally, 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()
.
Tetra v0.12 adds the ability to cast rays to check for collisions. Rays are cast from one point to another, against IBoundingObjects.
Similarly to the Bounds.CollisionTest function, ray testing happens using a ray test options struct that can provide a callback to be executed for each successful raytest, which results in a RayHit.
A RayHit contains relevant information for a successful ray test, like the object hit, the position hit, the collided normal, and the triangle, if it was a BoundingTriangles object. The callback function receives RayHits in order of distance.
NOTE: Capsules are internally handled as two sphere raycast checks, and a triangle mesh check for the cylindrical middle section. This is because I am just not that smart, and opted for the simplest solution (e.g. construct a cylinder in code and stick it in the middle for a BoundingCylinder check, haha) rather than the mathematically correct solution. This being the case, the cylindrical center section is composed of 32 faces around. If this isn't satisfactory and is too coarse for your purposes, let me know so I can create a function to recompose the cylinder with a higher fidelity (or just properly do the math).