Sunday, 29 May 2011

Stable 2D Contact Points between Convex Objects

The purpose of this post is to describe a bit about how the 2D collision detection works in Juggernaut.  Some of it may be overly basic, and some bits may skip massively over other aspects, but it does cover a few points (particularly on convex object collision detection) that I didn't find directly anywhere else on the web, and should at least provide a good overview.

In order to integrate a shape into the physics engine, you need to be able to detection intersections between that shape and the others supported by the collision detection engine.

Simple Primitive Intersection

Up until now, Juggernaut has only properly supported circle/circle and circle/line interactions: the main world brush is defined by a series of straight lines (organised into a hierarchical tree structure for efficient collision), and the objects themselves are defined by a series of bounding circles.  These are the simplest types of collision, as there is only ever one possible contact point between the primitives (to clarify, circles can have two actual intersections with a line/other circle, but only a single contact point is required to resolve them).

A very rough image showing example contact points/normals for circle/line and circle/circle collision detection.  By convention, the normals are defined as pointing into object A.
A contact point is defined by the intersection point between the two objects, the collision normal, and the penetration depth.  The circle/circle case is the simplest, as you just take the vector between the two circle centres and compare the magnitude to the sum of the radii.

For the line/circle case you need to create the function closestPointOnLine( Point A, Line B ), which will determine the closest point on the line segment B to the point A, which may either be a point along B or one of the endpoints of B.  Intersection/non-intersection may then be determined by comparison of the distance of the circle centre to the closest point on B with the radius of the circle. 

For a more in-depth look (including the actual maths) this site is a very useful resource.

Convex Primitive Intersection

So, for the simple primitive case, the contact point information can be calculated directly.  However, what if we want to have a more complex shape, such as an arbitrary convex polygon?   Convex polygons are selected as dealing directly with non-convex polygons is much more difficult, and it is always possible to decompose non-convex polygons into multiple convex polygons.  In this case, working out whether the objects intersect is much more difficult, and a naive approach would probably involve comparing every edge in shape A with every edge in shape B.  Luckily, this is not necessary!

The key concepts and algorithms required in order to solve this problem are:
- The Minkowski difference (see here). 

- The Gilbert–Johnson–Keerthi distance algorithm (or just GJK algorithm)
- Alternatively to GJK, a Separating Axis Theorem-based approach such as the Lin-Canny algorithm.
- The Expanding Polytope Algorithm, which may be used in conjunction with GJK in order to improve performance on deep penetrations.


The Juggernaut convex shape handler is based around GJK, and I'll mention a couple of things that I've found about it.
  1. It works absolutely amazingly for determining whether objects intersect or not.
  2. If the objects *do* intersect, the raw GJK results can be unreliable, as the closest simplex edge won't necessarily correspond to an edge on the convex hull of the Minkowski difference.  To ensure that this always happens, you'll need to use the Expanding Polytope Algorithm in these cases for robust behaviour.
Now, the main problem I've had over the last few days is the calculation of robust edge/edge collisions between convex objects.  This is because, in the general case, what you'll get as a result from GJK is 2 simplex vertices (corresponding to the closest external edge on the Minkowski difference), and each of these is associated with a vertex in Shape A and a vertex in Shape B.  There are four main cases:
  1. Both Shape A vertices are identical and the Shape B vertices define an outside edge of B.
  2. Both Shape B vertices are identical and the Shape A vertices define an outside edge of A.
  3. Both the Shape A and Shape B vertices define outside edges of A and B, respectively.  This will only really occur when the edges are very close to parallel, and can also be associated with a triangular simplex of zero are.  Also, this may or may not occur in exactly the same situation depending on the initially selected simplex point.
  4. The vertices do something else and define non-external edges of A and/or B (may happen with raw GJK, but not GJK+EPA). 
When there is only a point/edge interaction, both cases 1 and 2 are simple to solve as the intersection point occurs on the point of whichever shape, and the normal is defined by the edge normal of the other shape. However, if an edge/edge interaction is going on, this will lead to only one contact point being found rather than 2, causing jittery behaviour.

So, the solution that I've come up with is as follows: for the shape where only one vertex is returned by GJK, check both edges that are connected to it for contact points.  This is almost certainly not the only solution to this problem, but it's the only one I've found that produces stable results thus far.  This is demonstrated in the diagram below: 

Dual-edge checking collision point calculation, showing the possible basic configurations for 1, 2 and 3 point contacts.  The red vertices show those that form the closest Minkowski difference edge, as returned by the GJK algorithm.  The grey outline show the outlines of the capsules produced by the edges, and the red arrows the intersections/normals.  Note that this figure skips the situations where the endpoints of the lower shape edge come further in than the outer ones of the upper one.

Monday, 23 May 2011

Sunday, 22 May 2011

More dynamic world environments.

As part of the upgraded environment there will be free-floating debris found in areas, which can either be destroyed or, coupled with the tractor beam, employed as a weapon.

This video shows the prototype implementation, where each piece of debris is circular and coloured a dreadful orange. However, they do properly collide with each other in a realistic way using the physics engine. Prior to this point, the complexity of the physics engine was a little unnecessary when only interacting a single object with a set of immovable objects.



The next step is to upgrade these large debris pieces such that they are an arbitrary polygon, rather than just circular. Also, improving their graphics wouldn't go amiss, either! I must confess to being tempted to texturemap a space hopper face onto them, though :)

Saturday, 21 May 2011

Moar better collision detection.

Up until now, the only collision detection between the player's ship and the environment had been with the main outline of the world generated by the initial brush carving, which is a relatively simple shape. However, for a properly completed environment there will also be a lot flair (decorative) objects adorning the environment, and it's also important to be able to collide with them.

In addition, the laser impact effects have also been updated, with the impact explosion orientation now being determined by the normal of the impacted surface. It also kicks up some debris particle effects, although these are currently the same regardless of the surface type being hit, and thus look odd for some of the alien flora.



Flair intersection

There were two parts to getting this to work, both of which drew heavily on my existing codebase for creating and merging vector brushes (which has held up surprisingly well, given that there are a few bits that could really do with improving).

The first part is, for a given 2D (or basic 3D) mesh, generating a 2D vector brush of the outline. This abridged version is as follows:
  1. Identify all edges within the mesh. This is something that needs calculating, as by default meshes are stored in terms of vertices/triangles.
  2. Identify the set of triangles that use each edge (the set must at least of size 1, else where the hell did the edge come from?) 
  3. Determine whether each edge is potentially part of the outline.  If an edge has only one triangle associated with it, then it's always an outline edge.  For multiple triangles, it is an outline edge if the third point of each triangle (i.e. that not part of the edge) all lie on the same side of the line.
  4. Throw out all the non-outline-edge edges. 
  5. Starting on any outline edge, following connected edges around until you come back to the original edge in a loop.  In normal situations (apart from some awkward 3D configurations) there will never be any branching to worry about that.  Add that as a vector path.
  6. Repeat 5. for any currently unused outline edges until all are accounted for.
  7. Merge the set of vector paths together to form the final outline (which is a whole different bunch of algorithms).
Then, once you've generated the vector brushes for all the flair objects, you can then merge them together, and then again with the main world outline brush in order to produce the final collision geometry. Finally, take that geometry and generate a binary tree from it in order to allow efficent intersections. 

Friday, 20 May 2011

Rapture Investment Opportunity!

So, if there's anyone out there who believes that the Rapture is going to occur tomorrow, I'd like to offer the last minute opportunity to divest yourself of some wealth and give it to a cheerful heathen.  Not only will it aid indie game development, but by reducing your level of wealth you may help avoid the camel/eye of a needle/Heaven problem*.

*Warning: money not returned in the unlikely event that Rapture does not occur.

Sunday, 15 May 2011

Progress Update

Oops, it's been over a week since the last update! Time really does fly when you're coding away.

OK, the main things I've been working on over the last week or so are as follows:

Player/World collision

This is now basically done, along with player ship damage and particle effects at collision points. The particle effects are a mixture of sparks and rock being disturbed from the walls, which looks quite nice when scraping along the side. It also need a good corresponding sound effect!

There's still some tidying up and improvement to do on this aspect, but it's sufficient for now.  Have a peek:



 

Scripting zones

In order to make a game with an interesting and interactive world, there need to be scriptable zones within the world that can do a variety of things, from bringing up a certain story conversation, spawning some enemies, changing world states (e.g. opening/closing doors) and a lot of other things. The basic scripting capability now exists, and is embedded within the main global asset management system.  At the moment its capabilities are pretty limited, but these will rapidly expand as I add more scripting interfaces.

Upgraded collision detection

For anyone unfamiliar with collision detection, the basic problem is one of testing your game object's bounding shape (a circle, in the simple case) against all the objects in the world. Now, if you have 10000 primitives (e.g. lines/triangles) in your world, the easiest way is just to test directly against each of the 10000 objects, leading to 10000 geometry tests per object. However, using a hierarchical (tree-based) model you can achieve this in around Log2(10000) = 13 tests, allowing much greater efficiency. Even better, if you increase the number of primitives by a factor of 2, you'll only need one more test. This scaling allows testing against very complex world geometry in an efficient fashion.

Anyway, something that's been niggling at me since I upgraded to using the physics engine is the old hierarchical collision detection, which used a binary tree in order to calculate collisions with each triangle in the world mesh.

However, in reality, using all the triangles was quite wasteful and pointless, as the only important bits are the lines that form the outline of the world itself, and the corresponding bounding circles/bounding boxes were much larger than they needed to be. Since the world is carved from an overall vector brush, though, this outline is directly available, and thus I've refactored the code to produce a collision tree from a set of lines rather than triangles, leading to an overall improvement in efficiency and niceness. This is one of those things that won't have any directly visible effect, but makes further development easier.

Tuesday, 3 May 2011

Collision Physics Mk. 1

OK, the basic version of the world collision physics is now up and running.  This takes the overall bounding circle of the player's ship and uses that as a collision object, as shown in the video below.

However, there's still work to do in order to:
- Perform physics collisions with each ship component.
- Apply damage to the components based upon the collision energy.
- Add visual effects, such as a spark stream if the ship is scraping along the side of a wall.


Basic Environment Collision Physics from Darren Myatt on Vimeo.