When realtime renderers (such as 3d games) have motion blur, how is it usually implemented?
I think I've heard something about needing to have motion vectors for each pixel but I'm not sure about that and not sure how it would be used.
There are several techniques used.
A simple, but limited, post-process approach that is not really used any more consists in reconstructing the world space position of a pixel using both the view projection matrix from current and previous frame. Using these two values you can compute the velocity at a pixel and blur accordingly, sampling along the velocity vector with how many samples you want ( the more sample the blurrier, but the more expensive as well).
This method unfortunately takes into account just the camera movement and therefore is not accurate enough if you have a dynamic scene with fast moving objects.
As you mentioned, other more modern techniques use a velocity buffer.
This velocity buffer can be created during the base pass in the deferred pipeline transforming each vertex using the world-view-projection matrix of the previous frame and then computing in the pixel shader the velocity vector using the screen space position of both frames.
With this velocity buffer you can, in a post-process step, sample across the per-pixel velocity direction like in the approach I described above. The motion blur that you will get is obviously not camera-only; however you get an overhead in terms of memory (you need to keep an extra buffer) and time (you need to render additional info per pixel).
One technique based on velocity buffer that I particularly like is McGuire et al. that IIRC, is used with some variations in Unreal Engine 4 and many other games.
From [McGuire et al. 2012]
They divide the scene in tiles, assuming that each of these have a dominant velocity. Then, starting from the full res velocity buffer, they locate the velocity vector with higher magnitude for each tile, producing a downsampled version of the velocity buffer where 1 pixel = 1 tile.
Using this buffer, in another pass, they can generate a buffer that stores for each pixel/tile the dominant velocity among the neighbourhood pixels.
Note that the tile size is based on the max blur radius.
Using these buffers they then proceed with the gathering step sampling in the neighbourhood dominant velocity direction as this is the most plausible direction of the blur for each sample (as I said, the tile size is the max-blur radius). The weighting used for the blur takes into account the full res velocity and depth informations. Note that the paper propose three different weighting for three different scenarios (blurry over sharp, sharp over blurry and blurry over blurry).
Another important advantage of the method is that you can early-out if the dominant velocity in the neighbourhood is smaller than a certain threshold.