by Preach » Tue Aug 14, 2007 10:46 pm
Inspecting the darkplaces source for feasibility of writing this stuff myself (outlook not good, I'm afraid), I think it turns out bones only have keys for translation and rotation. In more mathematical terms, the bones have a 4 by 3 matrix, the first 3x3 matrix is applied to a vertex in the normal way, and constitutes a rotation matrix, and the 4th component is a constant vector added on as an offset. Of course, you could easily make the rotation matrix a rotation and scaling matrix, by simply multiplying all the values in that matrix by the scale factor. I don't know whether normalisation is expected or constrained somewhere else in the code, all I can say is that the comments only describe it as a rotation.
For those of you unfamiliar with a rotation matrix, I'll explain it in terms you should be familiar with - QC . Think of it as three column vectors side by side, those three column vectors being v_forward, v_right and v_up for a given direction(corresponding to the rotation you are trying to achieve). So they are unit vectors at right angles to one another. When a vector a is multiplied by this matrix, using the , you end up with
a_x * v_forward +
a_y * v_right +
a_z * v_up
So for a stupidly simple example, a = '1 0 0' will get rotated to v_forward, which is what you'd expect, I guess.
Enough of the maths talk, back to the theoretical coding side of things. Having just introduced the QuakeC notions of v_forward, v_right and v_up into the discussion, you might expect I'm about to suggest a GetBoneRotation function that puts the three rotation values straight into the v_forward, v_right and v_up vector, like makevectors does. Well, I'm not!
What? Well, my reasoning is, while that might sound like useful information, and very easy for the engine to do, it's actually not gonna be great if you want to change the bone's rotation. The problem is that you'd want to pair this with a SetBoneRotation function that takes the same input, and it'd be a hard task to make correct v_forward, v_right and v_up values in qc.
The obvious route would be convert v_forward with vectoangles, rotate the angle you get back, and then convert it back to vectors with makevectors(). However, if you do that, you'll lose information! The problem is that vectoangles will supply you with an angle of 'pitch yaw 0'. From this you'll only reconstruct v_forward correctly, v_right/v_up will be set to something arbitrary. Even if SetBoneRotation took a 'pitch yaw roll' vector as input, you'd still run afoul of this problem.
So you need the GetBoneRotation function to return a full rotation vector of the form 'pitch yaw roll' to stand a chance of setting this properly in my opinion. It could possibly return the values in v_forward, v_right and v_up as well, as a kind of bonus piece of information that might be useful.
One final detail that should be mentioned. I said above that by multiplying the whole matrix by a scale factor you can get the scaling effect. You can also scale the individual vectors v_forward, v_right and v_up within the matrix, and it does what you'd expect, scales in those directions. So if scaling is supported, it should return and be set by a vector quantity, not a scalar!