@haegarr
Is it enough to normalize the quaternion each time, or should the entire rotation matrix need to be re-orthonormalized? The latter seems a slightly more involved process, at least for a 4x4 matrix.
edit* I'm going to guess the latter, as a test of normalizing the quaternion didn't seem to fix it The drift is much, much smaller now (it slowly changes by .001 now), but it still definitely drifting as I rotate. Just to reiterate, this is a drift in the distance between ModelMatrix[3][0], ModelMatrix[3][1], ModelMatrix[3][2](minus the object's starting position), and the camera at 0,0,0. and distance is calculated by the typical pythagorean method.
2.) You need to think about spatial spaces, and what transformation should happen in which space. If you define a computation like
Mn+1 := Tn+1 * Rn+1 * Mn
you perform a rotation R onto an formerly translated and rotated model, since Mn contains both the current position and orientation. This means that a rotation R, which ever has (0,0,0) in its axis of rotation, will cause the model to rotate around an axis which is distant to the model's own local origin.
This is actually what I'm going for(i think), as I'd like the objects to rotate around the "camera". The rotation Matrix is recalculated every time by a new quaternion, so just rotates in small pieces, same with the translation vector. Basically, take it's stored location and rotation, and then rotate and translate that by another small rotation and translation.Everything works right as the code stands now,visually, at least, just the problem with the values drifting a little lingers. It really isn't much, just enough to cause problems. It's possible I'm misunderstanding you here, though. Is the fact that it's rotating around an axis distant to the model's local origin causing the drifting to occur?
To really clarify my problem(as I'm experiencing it), lets say I calculate the distance between the object as represented by ModelMatrix[3][0],ModelMatrix[3][1], ModelMatrix[3][2] and the "camera" at 0,0,0. and, let's say that distance is 10. if I rotate around (without translating at all) a whole bunch, eventually that distance will increase to 10.001 and then 10.002, etc. is calculating the matrix as "Mn+1 := Tn+1 * Rn+1 * Mn" causing that drift?
Instead, if you undo the current position first, so that
Mn+1 := Tn+1 * Tn * Rn+1 * Tn-1 * Mn = ( Tn+1 * Tn * … * T0 ) * ( Rn+1 * Rn * … * R0 )
I'm going to admit my mathematical skills are a little too poor to parse this(simple as it may be). If I'm reading it correctly, for each iteration, I undo the translation, then rotate, then apply the translation again with whatever added translation for that pass. Doesn't this result in the rotation always rotating about the original point, making it so regardless of where the player-camera is, the world will seem to rotate around the original starting position(like, imagine a space-ship(the camera) starts near the sun, but no matter where the ship goes in the solar system, when it rotates it looks like the whole solar system is rotating around the sun still, rather than everything around the ship)?
Back, to the normalization thing, a quick search online has recommended Gramm-Schmidt orthogonalization. I'm using the glm library. Would it just be easier to use the glm/gtx orthogonalization function that's in the library and fanagle it into the rotation matrix(the library is for 3x3 matrices, but perhaps I can write a function to adapt it),or, do you recommend a specific way to go about doing this? I'm happy to do my own research into this, but thought I may as well ask while I have your attention.
@Sean
I think I may have inadvertently led us off on an irrelevant tangent. In hindsight, this does appear to be a problem more along the lines of what haegarr is referring to. Nothing is way off, everything appears to be mostly correct, just over time everything "drifts" just a little. Fractions of a value, even (about .001 every other second, if I'm holding the rotate key down). But, when implementing collision, those fractions start adding up and become noticeable. I'm finding if I try to store the translation and rotation separately, and not multiply the matrix against itself, the rotations tend to be wrong. They'll either do what was reported above, where they rotate around a central point, instead of the camera, or weirder, they'll rotate with the camera view. I'll spend some time tomorrow working with your idea as well, to see if I can suss out what I'm doing wrong there.
Edit* @Sean
the issue I'm having with implementing your method, wherein I save the rotation and translation is that the translation has no direction in it. It's merely forward. Multiplying the matrix as you have it results in odd translation as it's translating before rotating.
void UpdateTransformation(const Transform& transform, mat44& out_matrix)
{
out_matrix = scale_mat44(transform.scale) * transform.rotation * translate_mat44(transform.position);//translates before rotating, but translation has no direction. always moves along world z-axis, not camera z-axis
}
but, if I change that to:
void UpdateTransformation(const Transform& transform, mat44& out_matrix)
{
out_matrix = scale_mat44(transform.scale)* translate_mat44(transform.position) * transform.rotation;//rotates then translates, but origin is always the starting point, not the current position of the player camera
}
This is a little better, but results in the objects rotating around the starting position of the camera, not its current one.
Perhaps there is an easy solution to this I'm overlooking. Normally, I would translate to the current position before rotating, then translate the new movement however, since the translation has no direction, it results in odd behavior(like always translating along the world z-axis, and not the camera z-axis). Again, when I say the translation has no direction, I mean it's just a forward position, say vec3(0,0,1). It only makes sense when coupled with the rotation to end up moving in the desired direction. This makes it so I'm unable to translate to the current position before rotating, as I only know what it is after multiplying the rotation by the translation. Perhaps I'm totally going about this the wrong way and there is a simple solution, but I thought I would lay out what I'm struggling with (even if it makes me look a little dense). Your method definitely gets rid of the drifting matrix points however, so if I can figure out how to make this work, it would solve my problem
bleh. Is there just a way to get to the object's position coordinates after translating it in a rotated direction? That alone would just really solve most of the problems here. After multiplying the model matrix by a quaternion based matrix, i just lose any sort of knowledge of the actual world coordinates of the object. Trying to calculate it by:
positionVector += quaternion * movement * conjugateOfQuaternion;
is giving me funny results.
Alright, last edit, hopefully.
Got everything working, kinda.
Taking Sean's advice. Though, I had to find a way to translate with a rotated quaternion as simply translating and rotating would move along worldspace z-axis instead of camera space. So:
combinedQuaternion = quaternion * combinedQuaternion;//cached quaternion
position += vec3Move * sumQuaternion;//position to be translated. current movement + total rotation.
RotationMatrix = mat4_cast(combinedQuaternion);
ModelMatrix = RotationMatrix * glm::translate(position);//translate with the direction, then rotate.
Seems to work. I get the correct movement and don't have to multiply the ModelMatrix by itself. I can retrieve the position of the object by the "position" vector, and use that for collision without dealing with parsing the ModelMatrix (which wasn't really working out anyhow).
My problem was I didn't realize you could translate a vector by a quaternion. I was mistakenly under the impression you could only multiply a quaternion once it was converted to a matrix. So, once that was resolved, the rest worked out pretty well.
My old problem of the translation coming to a halt while rotating has reared its ugly head again, but I'l spend some time trying to figure that out on my own.
Thank you all for your help I learned a lot, and got this sorted out (I think, there's always something else, isn't there? )
Cheers,