I think you'll do fine with simple collisions. You can implement something like this:
Sphere to sphere:
Let sphere1 have coordinates p0 = (p0x, p0y, p0z), a movement vector (basically by what vector you want to translate the sphere in this frame) v = (vx, vy, vz) and radius r1. Let sphere2 have coordinates p1 = (p1x,p1y,p1z), movement vector m = (mx, my, mz) and radius r2. We want to find at what point exactly they will collide. The linear functions p(t) = p0 + v*t and q(t) = q0 + m*t can be defined. What we want to actually find is a point where the distance between the centers of the two spheres = r1+r2. Here's what we get:
||p(t)-q(t)|| = r1+r2
((p0-q0) + (v-m)*t)^2 = (r1+r2)^2
(v-m)^2*t^2 + 2*(p0-q0)*(v-m)*t + (p0-q0)^2 - (r1+r2)^2 = 0
//Thus:
A = (v-m)^2, B = (p0-q0)*(v-m), C = (p0-q0)^2 - (r1+r2)^2, D = B^2 - A*C
//If D<0 => No collision
//If D>=0 =>
t1 = (-B-sqrt(D))/A
t2 = (-B+sqrt(D))/A
If 0<= t1 <= 1 then there is a collision (else there is no collision, at least in this frame) and when it happens sphere1 and sphere2 will have coordinates:
p(t1) = p0 + v*t1
q(t1) = q0 + m*t1
Note that t2 should not be considered unless your sphere is inside the other one.
(If there's no collision you just move the spheres normally)
After you have calculated the collisions you need to resolve them, you have many options, but the most popular ones are:
1) Stop response: they just stop at the point of collision, in this case you just move the spheres to coordinates p(t1) and q(t1) respectively.
2) Slide response: the spheres slide depending on their velocity vectors - you basically alter the velocity vector to remove the contribution in the opposite direction of the normal of the geometry you collided against: v' = v + (-n*v)*n, you alter the velocity vector like so only after you've applied the stop response(so your spheres would be at the correct coordinates) - there are some minor details that have to do with time, but I'll explain them later. ( n is the normal vector at the point of collision - can be calculated by n = (p0-q0)/||p0-q0|| - that would be the n used in the calculations of v', the n used for m' is n' = -n )
3) Bounce response: the spheres bounce off one another - once again you alter the velocity vector after the stop response - you just reflect the vector(and you can optionally divide it's magnitude - basically diminish the speed because for example you lost some energy in the bounce). You alter the velocity vector like so: v' = 2*(-v*n)*n + v - you basically reflect it. If you want to have some control over the "elasticity" of the sphere you can do: v' = elasticity*(2*(-v*n)*n + v), where elasticity is a scalar such that: 0<= elasticity <= 1.0; 0 makes it so the object doesn't bounce, 1 makes it so it bounces without losing any magnitude off its velocity vector, 0.5 for example will make the speed of the sphere halved after the bounce. You can of course pick more than 1 for elasticity - but that will make the sphere gain speed every time it bounces.
Another thing to note is that a moving sphere vs static geometry is a lot easier to evaluate (just put m = 0 ). While many moving spheres are harder to evaluate (not impossible). Here's a brief summary of what you will do for many moving spheres:
0) evaluate all spheres for collisions and keep track of the various results (you can store them in a std::map<double,std::pair<Sphere*, Sphere*>> collisions<-> collisions.insert(std::make_pair(t1, std::make_pair(sphere1, sphere2))) you get for t1 if there's a collision(such that 0<t1<remaining_time: remaining_time = 1 the first time you do 0) in a new frame - otherwise dismiss the result). (you don't need to evaluate 2 spheres twice for the same collision as collision(sphere1,sphere2) = collision(sphere2, sphere1) )
1) if the map where you store the collisions is empty() => just move all your objects by v*remaining_time
if the map is not empty => proceed to 2)
2) pick the first element of the map(it will be with smallest time) - let's call it t1
3) translate every moving sphere by v*t1, where v is the velocity vector of the sphere
4) You would get at least one collision, resolve it (by stop/slide/bounce) => proceed back to 0), but make remaining_time = remaining_time - t1
At some point (depending on the magnitude of the velocity vectors, and the spatial distribution density of the spheres in the scene) you'll get 0 collisions at 0), or you would get such a low remaining_time that all the t1 results would get dismissed(because then t1>remaining_time) so you would basically get no collisions.
The theory is basically you find out the collision that will happen after the smallest time period - you resolve the collision and movement up to that period then you do the same for the remaining time period - you'd get really accurate collisions and resolutions this way (you can of course optimize it by making it less accurate - but I wanted to first show the ideal case). It may seem that you could get a lot of iterations just for one frame, but note that if your velocity vector has a small magnitude for this frame and the objects distribution doesn't have a too high density you probably won't get more than a few iterations. And it's an ideal approach - there are ways to alter it and make it plausible still.
For a sphere to axis aligned box and axis aligned box to box collisions, it's pretty much the same approach as sphere to sphere collisions though easier(if you have issues with it, I could still write the basic algorithm). Note that another popular decision is cylinder(used to depict players usually) to sphere/box/cylinder. With a cylinder you basically act for x,z as if it were a circle to circle collision(same as sphere to sphere but with 2d vectors) and for y as if it was an axis aligned box (basically your code for it should look like a hybrid between sphere/box collisions).
Note that you can do a sphere/box/cylinder to triangle collision if you're lazy to model your physics around your model's geometry.
A really simple example(for windows): http://www.mediafire.com/download/oouhkxydcw91d2w/ss_coll.7z
P.S. If you've got any questions feel free to ask.