Spherical Collisions
This section deals with spherical collisions, both reflective (bouncing) and sliding.
Bouncing collisions
For bouncing collision, you basically find a collision point between the sphere and any point, segment or surface you are colliding with, and reflect the sphere's movement on the normal of the collision (for surfaces, it's the surface normal; for points, it's the unit vector from the point to the sphere center; for segments, it's the unit vector from the contact point to the sphere center).
To detect a collision with a surface, move the sphere along its intended path until its center is distance radius from the surface. Then calculate the contact point as if the surface is infinite. If that point is inside the bounds of the defined surface's segments, there is a collision. It's best for surfaces to be defined convex for this purpose.
To detect a collision with a point, simply calculate the point along the sphere's path where it is distance radius from the point. If there is a solution, there is a collision. Actually, there are usually two solutions to this, because the sphere could move through the point and be distance radius away again. So you'll have to figure out the right one to use.
For segments, I transformed the world along the segment into a 2D space and then used the sphere-point collision method to figure out how far along the sphere's path it had to move to collide with it. Once I got a contact point, I checked that it was within the bounds of the start and end point of the segment.
When I calculate for a collision, I check surfaces first, then segments, then points.
For the collision loop, in each game tick I calculate where the sphere would arrive if it had no collisions, and use that offset as well as with the sphere's current position and radius for all the calculations. I evaluate all possible objects it could collide with (collision volumes that keep lists of potential colliders help speed up the program here), and take the earliest collision and apply that to the sphere's movement. If more movement remains, I repeat the process until all the movement is used up. If no collisions occur, I just assign the sphere's remaining movement and end the routine.
The only problem I see with this method comes when the sphere in some rare circumstance ends up in a place where it is completely surrounded by geometry that makes it "stuck" - that is, all collisions occur at time 0. This would cause an infinite loop as the routine attempts to consume the sphere's movement. One possible solution is to multiply the sphere's remaining movement by a constant slightly less than 1 to simulate friction of some sort. This will cause the sphere's movement to eventually reach zero. Another possibility is to somehow track all the surfaces the sphere is colliding with at time 0 and watch for a "stuck" condition (which I have not yet done).
Sliding collisions
Sliding is what happens when an object touches another and slides along its surface, such as what happens in a first person shooter when you move to a wall at an angle and you press against it, causing you to slide down its length. this can still happen against surfaces, points, or segments.
I still use the method of calculating the sphere's final position as above, and the collision routines to see what the sphere makes contact with. But there are some complications.
If you are colliding with a single object (surface, segment, sphere), you just use the normal of the collision and alter the sphere's movement. If no more collisions occur, you get a slide. Note that for segments and points, this would actually move the sphere farther away from them again, but it works for surfaces, and I have no problem myself with the inaccuracy, since it's barely noticable.
It's also not too difficult to handle a time 0 collision with two objects. If the new movement resulting from the collision with the second object would cause the intended movement to go against the first collision normal, then you use the cross product of both collision normals, and that is the unit vector along which the intended movement will proceed. This causes you to travel along wall intersections, or slide around segments and points while touching another surface, point or segment, etc.
The difficulty comes when there are time 0 collisions with more than two objects. Imagine a sphere moving inside a cylinder of the same radius. It's possible while pressing against the inside to come in contact with up to an infinite number of surfaces, and the end result has to be that the sphere slides down the cylinder's length. Now imagine that the cylinder tapers at the end, resulting in a "stuck" position, where pressing actually results in no movement at all. How do we evalute accurately for both of these conditions?
My initial detection of a "stuck" situation involved watching for three time 0 collisions. If this happens, then we are stuck. This worked fine for surface geometry that only only involved 90 degree angles, due to how all the normals were orthonal to each other. But simply watching for three time 0 collisions isn't enough. With other angles, you'll easily run into situations where this detection method is inaccurate - you'll be evaluated as stuck when you clearly should be moving.
Bascially, what I did was keep track of the number of time 0 collisions I have so far. If I only have 1, I apply a slide. If I then have another time 0 collision, I calculate the slide movement as a result of that collision and see if it goes against the first collision normal. If it does, then I'm pressing against two surfaces now and must slide along their normals' cross product. If the second collision actually takes me away from the first normal, then I'm back down to one time 0 collision and the first collision is cancelled. If I have two collisions and encounter a third, I calculate the new movement and see if it moves me away from either of the other two normals and cancel appropriately. If there is no cancellation, I'm pressing against three normals that are oppsing my movement and are against each other. This is a stuck condition.
Applying this method to the cylinder example, you would quickly cancel collisions as the evaluation works its way up the side of the cylinder, until you are pressing against the two top surfaces, which would be opposing each other, causing a slide down the cylinder's length. Collision with the end of the cylinder would provide the third opposing collision. It works.