Q:

XNA - 3D Rotation about local (changing) ship axes - What am I missing?

I'm developing a 3D spaceshooter in XNA  as a school project (basically Asteroids in 3D with power-ups), and have been working to implement roll, pitch, and yaw with respect to the ship's local axes. (I should emphasize: the rotation is not with respect to the absolute/world x, y, and z axes.) Sadly, I've been struggling with this for the last few weeks. Google and my neolithic monkey brain have failed me; maybe you folks can help!
Here's my setup:
Via keyboard input, I have the following variables ready to go:

yawRadians, which stores the desired yaw away from the ship's initial
position
pitchRadians, which stores the desired pitch away from the
ship's initial position
rollRadians, which stores the desired roll
away from the ship's initial position

The ship also maintains its own Front, Back, Right, Left, Top and Bottom unit vectors, which are used both for the rotations and also for propulsion. (Different keys will propel the ship toward the Front, Back, etc. This part is working great.)
Ultimately, I generate the rotation matrix mShipRotation, representing all of the ship's rotations, which is passed to the ship's draw method.
The problem I have is with the rotations themselves. Different solutions I've tried have had differing results. Here's what I've gone with so far:
Method 1 – Yaw, Pitch, and Roll relative to the absolute/world x, y, and z axes
At first, I naively tried using the following in my ship's Update method:
qYawPitchRoll = Quaternion.CreateFromYawPitchRoll(yawRadians, pitchRadians, rollRadians);     

vFront = Vector3.Transform(vOriginalFront, qYawPitchRoll); 
vBack = -1 * vFront;

vRight = Vector3.Transform(vOriginalRight, qYawPitchRoll);
vLeft = -1 * vRight;

vTop = Vector3.Transform(vOriginalTop, qYawPitchRoll);
vBottom = -1 * vTop;

mShipRotation = Matrix.CreateFromQuaternion(qYawPitchRoll);

(vOriginalFront, vOriginalRight, and vOriginalTop just store the ship's initial orientation.)
The above actually works without any errors, except that the rotations are always with respect to the x, y, and z axes, and not with respect to the ship's Front/Back/Right/Left/Top/Bottom vectors. This results in the ship not always yawing and pitching as expected. (Specifically, yawing degenerates to rolling if you have pitched up so the ship is pointing to the top. This makes sense, as yawing in this solution is just rotating about the world up axis.)
I heard about the Quarternion.CreateFromAxisAngle method, which sounded perfect. I could just combine three Quaternion rotations, one around each of the ship's local axis. What could go wrong?
Method 2 – Quaternion.CreateFromAxisAngle
Here's the second code snippet I used in my ship's Update method:
qPitch = Quaternion.CreateFromAxisAngle(vRight, pitchRadians);
qYaw = Quaternion.CreateFromAxisAngle(vTop, yawRadians);
qRoll = Quaternion.CreateFromAxisAngle(vFront, rollRadians);
qPitchYawAndRoll = Quaternion.Concatenate(Quaternion.Concatenate(qPitch, qYaw), qRoll);

vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, qPitchYawAndRoll));
vBack = -1 * vFront;
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, qPitchYawAndRoll));
vLeft = -1 * vRight;

vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, qPitchYawAndRoll));
vBottom = -1 * vTop;

mShipRotation = Matrix.CreateFromQuaternion(qPitchYawAndRoll);

The above works perfectly if I only do one rotation at a time (yaw, pitch, or roll), but if I combine more than one rotation simultaneously, the ship begins to wildly spin and point in many different directions, getting more and more warped until it disappears entirely.
I've tried variants of the above where I first apply the Pitch to all the vectors, then the Yaw, then the Roll, but no luck.
I also tried it using Matrices directly, despite concerns of Gimbal Lock:
Method 3: Matrices
mShipRotation = Matrix.Identity;

mShipRotation *= Matrix.CreateFromAxisAngle(vRight, pitchRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vFront, rollRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vTop, yawRadians);

vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, mShipRotation));
vBack = -1 * vFront;

vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, mShipRotation));
vLeft = -1 * vRight;

vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, mShipRotation));
vBottom = -1 * vTop;

No luck; I got the same behavior. One rotation at a time is okay, but rotating about multiple axes resulted in the same bizarre spinning behavior.
After some brilliant debugging (read as: blindly outputting variables to the console), I noticed that the Front/Right/Top vectors were slowly, over time, becoming less orthogonal to one another. I added Normalization to vectors basically every step of the way, and also tried computing new vectors based on cross products, to try to ensure that they always remained perpendicular to one another, but even then they were not perfectly orthogonal. I'm guessing this is due to floating point math not being perfectly precise.
Note that I regenerate the mShipRotation matrix every Update method, so it cannot be accumulating drift or inaccuracies directly. I think that applying multiple Quarternion rotations may be accumulating error (as I can do one rotation just fine), but my attempts to fix it have not worked.
In short:

I can pitch/roll/yaw relative to the world axes x, y, and z just
fine. It's just not what the player would expect to happen as the
rolling/pitching/yawing is not relative to the ship, but to the
world.
I can roll, pitch, or yaw around the ship's local axes (Front/Back/Top/Bottom/Left/Right) just fine, but only one at a time. Any combination of them will cause the ship to spiral and deform rapidly.

I've tried Quaternions and Matrices. I've tried suggestions I've found in various forums, but ultimately do not wind up with a working solution. Often people recommend using  Quaternion.CreateFromYawPitchRoll, not really realizing that the intent is to have a ship rotate about its own (constantly changing) axes, and not the (fixed) world axes.
Any ideas? Given a situation where you are given the roll, pitch, and yaw about a ship's front, right, and top vectors, how would you go about creating the rotation matrix?

A:

You seem to be applying your overall angles (yawRadians, pitchRadians, rollRadians) to your local axis in your methods 2 & 3. These values are married to the world axis and have no meaning in local space. The root of your problem is wanting to hang onto the 3 angles.
In local space, use an angular amount that is the amount you want to rotate between frames. If you only pitched up 0.002f radians since the last frame, that would be what you would use when you rotate around the vRight axis.
This will screw with your overall angle values (yawRadians, pitchRadians, & rollRadians) and render them useless but most folks who stick with 3d programming quickly drop the angle approach to storing the orientation anyway.
Simply rotate your matrix or quaternion little by little each frame around your local axis and store the orientation in that structure (the quat or matrix) instead of the 3 angles.
There is no worries about gimbal lock when you are rotating a matrix about local axis like this. You would have to have 90 degree rotations between frames to bring that into the picture.
If you want to avoid error accumulation use a quat to store the orientation and normalize it each frame. Then the matrix you send to the effect will be made each frame from the quat and will be ortho-normal. Even if you didn't use a quat and stored your orientation in a matrix it would take hours or days to accumulate enough error to be visually noticeable.
This blog might help: http://stevehazen.wordpress.com/2010/02/15/matrix-basics-how-to-step-away-from-storing-an-orientation-as-3-angles/

