When working with 3d graphics, sample shaders USUALLY use the following operation for vector position transformation:
result = mul(matrix, vector);
This obviously means the same as:
result = mul(vector, matrix_transposed);
Also, just to mention, most linear algebra libraries prefer to only leave the vector * matrix multiplication operation for simplicity.
Now: let's say I want to transform some vector (position, for example), using some concrete matrix (to be concrete, let's use D3DX matrix operations). So, I construct simple world-view-projection matrix and then pass it to my shader.
D3DXMatrixRotationX(&world, 0.05f);
D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(400.0f, 80.0f, 0.0f),
&D3DXVECTOR3(0.1f, 0.1f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
D3DXMatrixPerspectiveFovLH(&projection, 0.5f, 800.0f / 600.0f, 1.0f, 1500.0f);
D3DXMATRIX wvp = world * view * projection;
Set Shader Parameter (wvp); // Pseudocode here
Question:
And here comes the part I can't understand - if done this way, the shader code should be
result = mul(vector, wvp)
for this transformation to work(vector is multiplied from the left side of the matrix).
Why does this happen? How do most sample shaders have the result = mul(wvp, vector) transformation inside them (and they don't transpose the matrix before setting it as a parameter)?
Where am I wrong?
Thank you.
A bit more information - D3DX matrix has row-major alignment and I am using the corresponding function, which takes a row-major matrix as a parameter (cgSetMatrixParameterfr in my particular case).
Of course, I could "transpose" that matrix by calling the function cgSetMatrixParameterfc, which treats input data as column-major matrix (and "automatically" transposes it), but that would be ridiculous.
The convention in mathematics (and thus in programming) is that you multiply the vector by a linear transformation from the right: matrix * vector == transformed vector. So I don't understand you complain. The matrix is already set to the right one. If you want to multiply the vector from the left then you need to transpose the matrix: result = mul(vector, transpose(wvp))
EDIT: OK, Direct3D actually does the opposite. It multiplies vectors from the left (treats them as rows rather than columns). OpenGL, for example, multiplies from the right as normal people do. So you need to load the transposed matrix to the cg program.
If both matrices are diagonal, square and have same size, then the multiplication is commutative.
Related
I have been handling object rotations in my engine by storing object`s x,y and z rotation and then when I am about to render, I was creating the transformation matrix like this.
// entity.getRotation() returns a glm::vec3 where I use these
//values to rotate the object.
glm::mat4 model;
model = glm::translate(model, entity.getPosition());
model = glm::rotate(model, glm::radians(entity.getRotation().x), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(entity.getRotation().y), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(entity.getRotation().z), glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::scale(model, glm::vec3(entity.getScale(), entity.getScale(), entity.getScale()));
Now, I implemented an AntTweakBar GUI into my engine where there is an option to be able to rotate objects on the GUI. I am currently trying to make it possible to rotate the objects in GUI and see the resulting rotations in the engine. The problem is that GUI works with quaternions while in my engine object rotation is stored as 3 floats of x,y,z rotation amounts.
My question is, how can I take the quaternion and turn it into x, y, z rotations so that I can use my above mention method to create the transformation matrix?
I found this method in glm
glm::eulerAngles(glm::quat(q[0], q[1], q[2], q[3]));
but upon looking at returned vec3, it does not seem like what I am looking for. I believe eulerAngles returns pitch, yaw, and roll which behaves incorrectly when I try to use these values to create my Transformation matrix.
Edit:
I found my mistake. It turned out that my old solution was fine(Although as someone pointed out in comments using quats might be faster). The problem was in my conversion from float array representation of quat(float array representation for AntTweakBar) to angles. It seems like AntTweakBar stores the x,y,z,w components in quat in a different order in the float array. The correct order in the float array is y,z,w,x but I have no clue why this is.
With GLM there are a couple of options, one that you have already mentioned, however make sure that your measure of angles are consistent. If you are using and relying on radians most of GLM's library methods past a specific version now expects all angles that are being passed into their rotation functions in radians however according to their docs when working with quaternions and using glm::eulerAngles(); it returns the angles pitch as X, yaw as Y, and roll as Z in degrees unless GLM_FORCE_RADIANS is defined.
Another alternative would be to use these two methods:
glm::mat4_cast
GLM_FUNC_DECL tmat4x4<T, P> glm::mat4_cast ( tquat< T, P > const & x )
Converts a quaternion to a 4 * 4 matrix.
See also GLM_GTC_quaternion Referenced by glm::toMat4().
glm::quat_cast
GLM_FUNC_DECL tquat<T, P> glm::quat_cast ( tmat4x4< T, P > const & x )
Converts a 4 * 4 matrix to a quaternion.
See also GLM_GTC_quaternion
If your GUI is using Quaternions you can retrieve that information and save it to a glm::quaternion then from there you can use one of these functions to convert it over to a 4x4 matrix. There are also 3x3 matrix-quat & quat-3x3 matrix versions of these conversion functions.
Simply put, I'm learning OpenGL and am starting to learn about transform matrices. Below is my current code:
glm::vec4 myPosition(1.0f, 1.0f, 1.0f, 1.0f);
glm::vec3 rotationAxis(0.0f, 1.0f, 0.0f);
glm::mat4 scalar = glm::scale(glm::vec3(1.0f, 1.0f, 1.0f));
glm::mat4 rotator = glm::rotate(360.0f, rotationAxis);
glm::mat4 translator = glm::translate(glm::vec3(1.0f, 1.0f, 1.0f));
glm::mat4 transform = translator * rotator * scalar;
myPosition = transform * myPosition;
As far as I can tell, I'm doing this in the correct order: Scale -> Rotate -> Translate. So, I have the scale set to do nothing because I don't actually want it to scale anywhere (for simplicity sake).
Next, I set rotate to 360.0f on (correct me if I'm wrong) the Y axis. This should return to the original point, at least that's what I would think from a 360 degree rotation around a singular axis.
Then, I set it to translate 1 unit in every direction to make sure it moves.
After finishing this all, I have commented out the rotator line, and it works fantastic, even if I change the scale. However, whenever I add in the rotate line the final position is not a normal 360 degree rotation?
I have configured my program to output the position vector both before transforms and after.
The before position is (1, 1, 1)
The after position is (1.67522, 2, -0.242607).
I have been struggling to find my error, literally all day so if anyone can help me find what I'm doing wrong, it would be greatly appreciated!!
According to the documentation at http://glm.g-truc.net/0.9.7/api/a00236.html (for the latest released version right now), glm::rotate(..) takes in an angle expressed in degrees.
However, changing your rotation matrix line
glm::mat4 rotator = glm::rotate(360.0f, rotationAxis);
to
glm::mat4 rotator = glm::rotate(3.141592f * 2.0f, rotationAxis);
which is just 2*PI fixes this.
This means that the angle should be in radians rather than in degrees. Tested on my machine with GLM 0.9.7.1-1. This is either a mistake in the documentation or in the GLM code itself.
From my experience with GLM (some time ago, might've been an earlier version) these kinds of functions should take a degrees angle by default, and the #define GLM_FORCE_RADIANS macro is what makes them calculate in radians. It is possible that the author made this the default behaviour and forgot to update the docs.
On a side note, you should probably not be using scalar as the name for a glm::mat4 value, since a scalar in mathematics is just a single real number rather than a matrix: https://en.wikipedia.org/wiki/Scalar_%28mathematics%29
In most 3D platform games, only rotation around the Y axis is needed since the player is always positioned upright.
However, for a 3D space game where the player needs to be rotated on all axises, what is the best way to represent the rotation?
I first tried using Euler angles:
glRotatef(anglex, 1.0f, 0.0f, 0.0f);
glRotatef(angley, 0.0f, 1.0f, 0.0f);
glRotatef(anglez, 0.0f, 0.0f, 1.0f);
The problem I had with this approach is that after each rotation, the axises change. For example, when anglex and angley are 0, anglez rotates the ship around its wings, however if anglex or angley are non zero, this is no longer true. I want anglez to always rotate around the wings, irrelevant of anglex and angley.
I read that quaternions can be used to exhibit this desired behavior however was unable to achieve it in practice.
I assume my issue is due to the fact that I am basically still using Euler angles, but am converting the rotation to its quaternion representation before usage.
struct quaternion q = eulerToQuaternion(anglex, angley, anglez);
struct matrix m = quaternionToMatrix(q);
glMultMatrix(&m);
However, if storing each X, Y, and Z angle directly is incorrect, how do I say "Rotate the ship around the wings (or any consistent axis) by 1 degree" when my rotation is stored as a quaternion?
Additionally, I want to be able to translate the model at the angle that it is rotated by. Say I have just a quaternion with q.x, q.y, q.z, and q.w, how can I move it?
Quaternions are very good way to represent rotations, because they are efficient, but I prefer to represent the full state "position and orientation" by 4x4 matrices.
So, imagine you have a 4x4 matrix for every object in the scene. Initially, when the object is unrotated and untraslated, this matrix is the identity matrix, this is what I will call "original state". Suppose, for instance, the nose of your ship points towards -z in its original state, so a rotation matrix that spin the ship along the z axis is:
Matrix4 around_z(radian angle) {
c = cos(angle);
s = sin(angle);
return Matrix4(c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
now, if your ship is anywhere in space and rotated to any direction, and lets call this state t, if you want to spin the ship around z axis for an angle amount as if it was on its "original state", it would be:
t = t * around_z(angle);
And when drawing with OpenGL, t is what you multiply for every vertex of that ship. This assumes you are using column vectors (as OpenGL does), and be aware that matrices in OpenGL are stored columns first.
Basically, your problem seems to be with the order you are applying your rotations. See, quaternions and matrices multiplication are non-commutative. So, if instead, you write:
t = around_z(angle) * t;
You will have the around_z rotation applied not to the "original state" z, but to global coordinate z, with the ship already affected by the initial transformation (roatated and translated). This is the same thing when you call the glRotate and glTranslate functions. The order they are called matters.
Being a little more specific for your problem: you have the absolute translation trans, and the rotation around its center rot. You would update each object in your scene with something like:
void update(quaternion delta_rot, vector delta_trans) {
rot = rot * delta_rot;
trans = trans + rot.apply(delta_trans);
}
Where delta_rot and delta_trans are both expressed in coordinates relative to the original state, so, if you want to propel your ship forward 0.5 units, your delta_trans would be (0, 0, -0.5). To draw, it would be something like:
void draw() {
// Apply the absolute translation first
glLoadIdentity();
glTranslatevf(&trans);
// Apply the absolute rotation last
struct matrix m = quaternionToMatrix(q);
glMultMatrix(&m);
// This sequence is equivalent to:
// final_vertex_position = translation_matrix * rotation_matrix * vertex;
// ... draw stuff
}
The order of the calls I choose by reading the manual for glTranslate and glMultMatrix, to guarantee the order the transformations are applied.
About rot.apply()
As explained at Wikipedia article Quaternions and spatial rotation, to apply a rotation described by quaternion q on a vector p, it would be rp = q * p * q^(-1), where rp is the newly rotated vector. If you have a working quaternion library implemented on your game, you should either already have this operation implemented, or should implement it now, because this is the core of using quaternions as rotations.
For instance, if you have a quaternion that describes a rotation of 90° around (0,0,1), if you apply it to (1,0,0), you will have the vector (0,1,0), i.e. you have the original vector rotated by the quaternion. This is equivalent to converting your quaternion to matrix, and doing a matrix to colum-vector multiplication (by matrix multiplication rules, it yields another column-vector, the rotated vector).
I am trying to learn some OpenGL basics by reading OpenGL Superbible.
I am at the beginning of the 4th chapter and I have a question about the transformations.
Firstly, relevant link:http://www.songho.ca/opengl/gl_transform.html
If I understand this pipeline (so to speak) right, if in my code I would have something like this
const float vertexPositions[] = {
0.75f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
-0.75f, -0.75f, 0.0f, 1.0f,
};
those coordinates are in so called object space coordinates, and I can specify each value as something in [-1,1] range.
After applying viewmodel matrix, each vertex coordinates can be any number and those coordinates will be in so called eye coordinates.
After applying projection matrix (be it perspective projection) we are in clip space, and still the numbers can have any possible value.
Now here is the point I am wondering about. In this page it is said that for each vertex x,y,z coordinate we are diving it by fourth value w, which is present because we are using homogeneous coordinate system, and after the division, x,y,z are in range [-1,1].
My question is, how can be sure that after all those transformations the value of w will be sufficient enough, that after dividing x,y,z by it we will get something in range [-1,1]?
… object space coordinates, and I can specify each value as something in [-1,1] range.
You're not limited in the range for object coordinates.
My question is, how can be sure that after all those transformations the value of w will be sufficient enough, that after dividing x,y,z by it we will get something in range [-1,1]?
The range [-1, 1] is the range of what will be in the viewport after transformation. Everything outside that range is outside the viewport and hence clipped. There's nothing to ensure about this. If things are in range, they are visible, if not, they are outside the viewport window.
I just don't seem to be able to figure this out in my head. I'm trying to move an object in 3D space.
If I have a point at 5,15,5 and use opengl functions to change the model view....
glTranslatef( 10.0f, 4.0f, 4.0f );
glRotatef( 33.0f, 1.0f, 0.0f, 0.0f );
glTranslatef( 10.0f, 4.0f, 4.0f );
Is there a way I can find out where that point ends up (in world / global coordinates)?
Can I do some kind of matrix calculations that will give me back 20,26,23 (or what every the new coordinate position is)?
Please help, I've been stuck on this for so long!
Try the following:
1) Push the current matrix into stack;
2) Load identity and apply your transformations;
3) Get the resulting transformation matrix into some temp variable. glGet or something like that will help;
4) Pop the matrix from the stack;
Now you have your transformation matrix. Multiply your point by this matrix to predict the point's coordinates after the transformation.
Definitely: check out http://research.cs.queensu.ca/~jstewart/454/notes/pipeline/
In short, all of these calls reduce to a single matrix, which is multiplied onto the point.
SadSido's method will definitely get you the resultant matrix, but it may not hurt to actually understand what's going on behind the scenes. The calculations above will result in a linear algebra equation of the following:
pOut = [mTranslate] * [mRotate] * [mTranslate] * pIn
where mTranslate = the translation calls (matrix for translation), and mRotate = rotate call (matrix for rotation about an arbitrary axis). Calculate that, and you're good to go!