I'm working in the revitalization of an old 3d game (built using Direct3D) and I'm struggling with the game objects animations.
The game has its objects animations stored in binary files that contains transformation matrices for each bone of its meshes at each frame of the animation (in the form of an array of D3DMATRIX).
I've tried using the D3DXMatrixDecompose function to get the position, rotation and scale but it seems that something is wrong with the animation. Some animations almost matches the originals, but there are some strange rotations in the middle of the animations (the scale vector goes from negative to positive values and that causes the whole bone to rotate in an strange way - it is definitely wrong) and for other animations the whole thing is wrong.
I read somewhere that the function D3DXMatrixDecompose assumes the matrix was composed as a SRT matrix and apparently the order in which each component was combined in the matrix matters. So, as the animations are clearly wrong I'm assuming maybe the matrices were not composed in the SRT order and the output of D3DXMatrixDecompose is wrong.
I didn't find much material to read about this without going very deep on math. As I don't have a strong background on math, hopefully someone can point me in the right direction.
So, how can I decompose position, rotation and scale of an unknown transformation matrix? I'm not asking for a unique algorithm that can do that, I'm asking what I can do in this scenario to find the original (or equivalents) values for the position, rotation and scale of each matrix.
Thanks in advance!
Related
Background:
I am currently implementing a skeletal animation shader in GLSL, and to save space and complexity I am using Quaternions for the bone rotations, using weighted quaternion multiplication (of each bone) to accumulate a "final rotation" for each vertex.
Something like: (pseudo-code, just assume the quaternion math works as expected)
float weights[5];
int bones[5];
vec4 position;
uniform quaternion allBoneRotations[100];
uniform vec3 allBonePositions[100];
main(){
quaternion finalQuaternion;
for(i=0;i<5;i++){finalQuaternion *= allBoneRotations[bones[i]]*weights[i];}
gl_position = position.rotateByQuaternion(finalQuaternion);
}
The real code is complicated, sloppy, and working as expected, but this should give the general idea, since this is mostly a math question anyway, the code isn't of much consequence, it's just provided for clarity.
Problem:
I was in the process of adding "pivot points"/"joint locations" to each bone (negative translate, rotate by "final quaternion", translate back) when I realized that the "final quaternion" will not have taken the different pivot points into account when combining the quaternions themselves. In this case each bone rotation will have been treated as if it was around point (0,0,0).
Given that quaternions represent only a rotation, it seems I'll either need to "add" a position to the quaternions (if possible), or simply convert all of the quaternions into matrices, then do matrix multiplication to combine the series of translations and rotations. I am really hoping the latter is not necessary, since it seems like it would be really inefficient, comparatively.
I've searched through mathoverflow, math.stackexchange, and whatever else Google provided and read the following resources so far in hopes of figuring out an answer myself:
http://shankel.best.vwh.net/QuatRot.html
http://mathworld.wolfram.com/Quaternion.html
plus various other small discussions found through Googling (I can only post 2 links)
The consensus is that Quaternions do not encode "translation" or "position" in any sense, and don't seem to provide an intuitive way to simulate it, so pure quaternion math seems unlikely to be a viable solution.
However it might be nice to have a definitive answer to this here. Does anyone know any way to "fake" a position component of a quaternion, that in some way that would keep the quaternion math efficiency, or some other method to "accumulate" rotations around different origin points that is more efficient than just computing the matrix of the quaternions, and doing matrix translation and rotation multiplications for each and every quaternion? Or perhaps some mathematical assurance that differing pivot points don't actually make any difference, and can, in fact be applied later (but I doubt it).
Or is using quaternions in this situation just a bad idea on the face of it?
Indeed, there is no such thing as a position component of a quaternion, so you'll need to track it separately. Suppose individual transformations end up being like
x' = R(q)*(x-pivot)+pivot = R(q)*x + (pivot-R(q)*pivot) = R(q)*x+p,
where q is your quaternion, R(q) is the rotation matrix built from it, and p=pivot-R(q)*pivot is the position/translation component. If you want to combine two such transformations, you can do it without going full-matrix multiplication:
x'' = R(q2)*x'+p2 = R(q2)*R(q)*x + (R(q2)*p+p2) = R(q2*q)*x + (R(q2)*p+p2).
This way the combined quaternion will be q2*q, and the combined position, R(q2)*p+p2. Note that you can even apply quaternions to vectors (R(q2)*p and so on) without explicitly building rotation matrices, if you want to absolutely avoid them.
That said, there is also a notion of "dual quaternions" which, in fact, do contain a translation component, and are presumably better for representing screw motions. Check them out on Wiki, and here (the last link also points to a paper).
After extensive additional searching, and reading more about quaternions than any sane person should, I finally discovered my answer here:
http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/other/dualQuaternion/index.htm
It turns out Dual Quaternions operate similarly to actual quaternions, with many of the mathematical operations based off of regular quaternion math, but they provide both orientation, and displacement both, and can be combined for any rotation-translation sequence needed, much like Transformation Matrix multiplication, but without the shear/scale ability.
The page also has a section that derives exactly the "rotating around an arbitrary point" functionality that I was requiring by using dual quaternion multiplication. Perhaps I should have researched a bit more before asking, but at least the answer is here now in case anyone else comes looking.
I am currently teaching myself linear algebra in games and I almost feel ready to use my new-found knowledge in a simple 2D space. I plan on using a math library, with vectors/matrices etc. to represent positions and direction unlike my last game, which was simple enough not to need it.
I just want some clarification on this issue. First, is it valid to express a position in 2D space in 4x4 homogeneous coordinates, like this:
[400, 300, 0, 1]
Here, I am assuming, for simplicity that we are working in a fixed resolution (and in screen space) of 800 x 600, so this should be a point in the middle of the screen.
Is this valid?
Suppose that this position represents the position of the player, if I used a vector, I could represent the direction the player is facing:
[400, 400, 0, 0]
So this vector would represent that the player is facing the bottom of the screen (if we are working in screen space.
Is this valid?
Lastly, if I wanted to rotate the player by 90 degrees, I know I would multiply the vector by a matrix/quarternion, but this is where I get confused. I know that quarternions are more efficient, but I'm not exactly sure how I would go about rotating the direction my player is facing.
Could someone explain the math behind constructing a quarternion and multiplying it by my face vector?
I also heard that OpenGL and D3D represent vectors in a different manner, how does that work? I don't exactly understand it.
I am trying to start getting a handle on basic linear algebra in games before I step into a 3D space in several months.
You can represent your position as a 4D coordinate, however, I would recommend using only the dimensions that are needed (i.e. a 2D vector).
The direction is mostly expressed as a vector that starts at the player's position and points in the according direction. So a direction vector of (0,1) would be much easier to handle.
Given that vector you can use a rotation matrix. Quaternions are not really necessary in that case because you don't want to rotate about arbitrary axes. You just want to rotate about the z-axis. You helper library should provide methods to create such matrix and transform the vector with it (transform as a normal).
I am not sure about the difference between the OpenGL's and D3D's representation of the vectors. But I think, it is all about memory usage which should be a thing you don't want to worry about.
I can not answer all of your questions, but in terms of what is 'valid' or not it all completely depends on if it contains all of the information that you need and it makes sense to you.
Furthermore it is a little strange to have the direction that an object is facing be a non-unit vector. Basically you do not need the information of how long the vector is to figure out the direction they are facing, You simply need to be able to figure out the radians or degrees that they have rotated from 0 degrees or radians. Therefore people usually simply encode the radians or degrees directly as many linear algebra libraries will allow you to do vector math using them.
I am quite new to this, and iv'e heard that i need to get my inversed projection matrix and so on to create a ray from a 2D point to a 3D world point, however since im using OpenglES and there are not as many methods as there would be regulary to help me with this. (And i simply don't know how to do it) im using a trigenomeric formula for this insted.
For each time i iterate one step down the negative Z-axis i multiply the Y-position on the screen (-1 to 1) with
(-z / (cot(myAngle / 2))
And the X position likewise but with a koefficent equally to the aspect ratio.
myAngle is the frustum perspective angle.
This works really good for me and i get very accurate values, so what i wonder is: Why should i use the inverse of the projection matrix and multiply it with some stuff instead of using this?
Most of the time you have a matrix lying around for your OpenGl camera. Using an inverse matrix is simple when you already have a camera matrix on hand. It is also (oh so very slightly at computer speeds) faster to do a matrix multiply. And in cases where you are doing a bajillion of these calculations per frame, it can matter.
Here is some good info on getting started on a camera class if you are interested:
Camera Class
And some matrix resources
Depending on what you are working on, I wouldn't worry too much about the 'best way to do it.' You just want to make sure you understand what your code is doing then keep improving it.
I use slerp to interpolate between two quaternions representing rotations. The resulting rotation is then extracted as Euler angles to be fed into a graphics lib. This kind of works, but I have the following problem; when rotating around two (one works just fine) axes in the direction of the green arrow as shown in the left frame
here
the rotation soon jumps around to rotate from the opposite site to the opposite visual direction, as indicated by the red arrow in the right frame.
This may be logical from a mathematical perspective (although not to me), but it is undesired. How could I achieve an interpolation with no visual flipping and changing of directions when rotating around more than one axis, following the green arrow at all times until the interpolation is complete?
Thanks in advance.
Your description of the problem is a little hard to follow, quite frankly. But it sounds like you need to negate one of your quaternions.
Remember, each rotation can actually be represented by two quaternions, q and -q. But the Slerp path from q to w will be different from the path from (-q) to w: one will go the long away around, the other the short away around. It sounds like you're getting the long way when you want the short way.
Try taking the dot product of your two quaternions (i.e., the 4-D dot product), and if the dot product is negative, replace your quaterions q1 and q2 with -q1 and q2 before performing Slerp.
How far is the total rotation? You may be asking for an interpolation for two orientation too far apart in angle. The math, quaternions or not, has trouble deciding which way to go, in a sense. Like not having enough keyframes in animation.
Determine a good intermediate orientation about halfway along, and make separate interpolations from the initial orientation to that intermediate one, and from the intermediate to the final.
I am using a 3D engine called Electro which is programmed using Lua. It's not a very good 3D engine, but I don't have any choice in the matter.
Anyway, I'm trying to take a flat quadrilateral and transform it to be in a specific location and orientation. I know exactly where it is supposed to go (i.e. I know the exact vertices where the corners should end up), but I'm hitting a snag in getting it rotated to the right place.
Electro does not allow you to apply transformation matrices. Instead, you must transform models by using built-in scale, position (that is, translate), and rotation functions. The rotation function takes an object and 3 angles (in degrees):
E.set_entity_rotation(entity, xangle, yangle, zangle)
The documentation does not speficy this, but after looking through Electro's source, I'm reasonably certain that the rotation is applied in order of X rotation -> Y rotation -> Z rotation.
My question is this: If my starting object is a flat quadrilateral lying on the X-Z plane centered at the origin, and the destination position is in a different location and orientation where the destination vertices are known, how could I use Electro's rotation function to rotate it into the correct orientation before I move it to the correct place?
I've been racking my brain for two days trying to figure this out, looking at math that I don't understand dealing with Euler angles and such, but I'm still lost. Can anyone help me out?
Can you tell us more about the problem? It sounds odd phrased in this way. What else do you know about the final orientation you have to hit? Is it completely arbitrary or user-specified or can you use more knowledge to help solve the problem? Is there any other Electro API you could use to help?
If you really must solve this general problem, then too bad, it's hard, and underspecified. Here's some guy's code that may work, from euclideanspace.com.
First do the translation to bring one corner of the quadrilateral to the point you'd like it to be, then apply the three rotational transformations in succession:
If you know where the quad is, and you know exactly where it needs to go, and you're certain that there are no distortions of the quad to fit it into the place where it needs to go, then you should be able to figure out the angles using the vector scalar product.
If you have two vectors, the angle between them can be calculated by taking the dot product.