I have an object which I first want to rotate (about its own center) then translate it to some point. I have a glm::quat that holds the rotation and a glm::vec3 that holds the point to which it needs to be translated.
glm::vec3 position;
glm::quat orientation;
glm::mat4 modelmatrix; <-- want to combine them both in here
modelmatrix = glm::translate(glm::toMat4(orientation),position);
Then at my render function, I do.
pvm = projectionMatrix*viewMatrix*modelmatrix;
glUniformMatrix4fv(pvmMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr(pvm));
..and render...
Unfortunately, the object just orbits around the origin when I apply a rotation (the farther the "position" from the origin, the larger the orbit).
When I apply for only the position it translates fine. When I apply only the rotation it stays at the origin and rotates about its center (as expected). So why does it go weird when I apply them both? Am I missing something basic?
Because you're applying them in the wrong order. By doing glm::translate(glm::toMat4(orientation),position), you are doing the equivalent of this:
glm::mat4 rot = glm::toMat4(orientation);
glm::mat4 trans = glm::translate(glm::mat4(1.0f), position);
glm::mat4 final = rot * trans;
Note that the translation is on the right side of the matrix, not the left. This means that the translation happens first, then the rotation happens relative to the translation. So rotation happens in the space after translation.
You want the rotation to happen first. So reverse the order of the matrix multiplication.
Related
I'm trying to get an object to always face the camera. I looked up a way to do this, but the problem is when I put this part into the view matrix nothing is affected by the model matrix. How can I get it to translate it using the model matrix? code:
GLuint transformLocation=glGetUniformLocation(textureShaders,"transform");
glm::mat4 transform;
glm::mat4 model;
glm::vec3 playerPosition=user.getPosition();
model=glm::translate(model,glm::vec3(xpos,0.0f,zpos));
glm::mat4 view;
view=glm::lookAt(cam.getPositionVector(),cam.getPositionVector()+cam.getFrontVector(),cam.getUpVector());
glm::mat4 rotationMatrix=glm::transpose(glm::lookAt(glm::vec3(xpos,0.0f,zpos),playerPosition,glm::vec3(0.0f,1.0f,0.0f)));
view*=rotationMatrix;
glm::mat4 projection;
projection=glm::perspective(45.0f,(float)900/(float)600,0.1f,100.0f);
transform=projection*view*model;
Your "rotation" matrix doesn't really make sense:
rotationMatrix=glm::transpose(glm::lookAt(glm::vec3(xpos,0.0f,zpos),playerPosition,glm::vec3(0.0f,1.0f,0.0f)));
This will not result in a rotation matrix (except when both xpos and zpos happen to be zero). lookAt will create a transform matrix which can be decomposed to r * t(-pos) (for whatever pos you call it with). Building the transpose of this matrix will result in the translation column beeing transposed to the fourth row, which completely will screw the final w coordinate.
I am trying to render a 3D model using OpenGL. And for the projection and transformation matrices, I am using glm. I've got my model on the screen and it works just like I intended it to; except one small problem.
I am setting the model's translation matrix as
glm::translate(glm::vec3(0, 0, 4)
to move the model a little bit forward so that I can see it. Since in OpenGL, by default, negative z is out towards the 'camera' and positive z is forward, I expected this to work but it doesn't. It only works if I set it to
glm::translate(glm::vec3(0, 0, -4)
But this seems weird to me, as I am setting my zNear to 0.01 and zFar to 1000. Is glm's z values flipped or am I doing something wrong here?
Here is my code:
glm::mat4 rotation = glm::mat4(1.0f);
glm::mat4 translation = glm::translate(glm::vec3(0, 0, -4));
glm::mat4 scale = glm::mat4(1.0f);
glm::mat4 modelMatrix = translation * rotation * scale;
glm::mat4 projectionMatrix = glm::perspective(70.0f, aspectRatio, 0.01f, 1000.0f);
glm::mat4 transformationMatrix = projectionMatrix * modelMatrix;
When you call perspective() with near = 0.01 and far = 1000.0 planes, its actual meaning is that you are cutting it as -0.01 to -1000.0 so you should put the object's z-value into the range [-0.01, -1000.0].
Imagine the right handed Coordinate and assume your eye's z-value is 0.0 in default.
After reading through this article (http://3dgep.com/?p=1700) it seems to imply I got my view matrix wrong. Here's how I compute the view matrix;
Mat4 Camera::Orientation() const
{
Quaternion rotation;
rotation = glm::angleAxis(mVerticalAngle, Vec3(1.0f, 0.0f, 0.0f));
rotation = rotation * glm::angleAxis(mHorizontalAngle, Vec3(0.0f, 1.0f, 0.0f));
return glm::toMat4(rotation);
}
Mat4 Camera::GetViewMatrix() const
{
return Orientation() * glm::translate(Mat4(1.0f), -mTranslation);
}
Supposedly, I am to invert this resulting matrix, but I have not so far and it has work excellently thus far, and I'm not doing any inverting down the pipeline either. Is there something I am missing here?
You already did the inversion. The view matrix is the inverse of the model transformation that positions the camera. This is:
ModelCamera = Translation(position) * Rotation
So the inverse is:
ViewMatrix = (Translation(position) * Rotation)^-1
= Rotation^-1 * Translation(position)^-1
The translation is inverted by negating the offset:
= Rotation^-1 * Translation(-position)
This leaves us with inverting the rotation. We can assume that the rotation is inverted. Thus, the original rotation of the camera model is
Rotation^-1 = RotationX(verticalAngle) * RotationY(horizontalAngle)
Rotation = (RotationX(verticalAngle) * RotationY(horizontalAngle))^-1
= RotationY(horizontalAngle)^-1 * RotationX(verticalAngle)^-1
= RotationY(-horizontalAngle) * RotationX(-verticalAngle)
So the angles you specify are actually the inverted angles that would rotate the camera. If you increase horizontalAngle, the camera should turn to the right (assuming a right-handed coordinate system). That's just a matter of definitions.
I have been attempting to rotate an object around its local coordinates and then move it based off based of the rotated coordinates but i have not been able to achieve the desired results,
to explain the problem in a more in depth way i have an object at a certain point in space and i need to rotate it around its own origin(not the global origin) and then translate the object based off of the newly rotated axis's, after much experimenting i have discovered that i can either rotate the object around is origin but the coordinates will not be rotated with it or i can have the objects local coordinates be transformed with it but it will then rotate around the global origin.
currently my rotation/translation/scaling code looks like this
glm::mat4 myMatrix = glm::translate(glm::mat4(1.0f),trans);
glm::mat4 Model = glm::mat4(1.f);
glm::mat4 myScalingMatrix = glm::scale(sx, sy ,sz);
glm::vec3 myRotationAxis( 0, 1, 0);
glm::mat4 myRotationMatrix =glm::rotate(glm::mat4(1.0f),rot, myRotationAxis);
Model= myScalingMatrix* myRotationMatrix*myMatrix;
glm::mat4 MVP = Projection* View * Model;
I believe this is the problem code specifically the second line from the bottom but i could be wrong and will be post more code if its needed.
i have also attempted to create an inverse matrix and use that at the start of the calculation but that appears to do nothing(i can add the code that i attempted to do this with if needed)
If any kind of elaboration is needed regarding this issue feel free to ask and i will expand on the question
Thanks.
EDIT 1:
Slightly modified code that was suggested in the answers section, still giving the same bug though.
glm::mat4 Model = glm::mat4(1.f);
glm::mat4 myScalingMatrix = glm::scale(sx, sy ,sz);
glm::vec3 myRotationAxis( 0, 1, 0);
glm::mat4 myRotationMatrix =glm::rotate(glm::mat4(1.0f),rot, myRotationAxis);
glm::vec4 trans(x,y,z,1);
glm::vec4 vTrans = myRotationMatrix* trans ;
glm::mat4 myMatrix = glm::translate(glm::mat4(1.0f),vTrans.x,vTrans.y,vTrans.z);
Model= myScalingMatrix* myRotationMatrix*myMatrix;
You need to apply your rotation matrix to the translation vector (trans).
So, assuming trans is a vec4, your code will be:
glm::mat4 Model = glm::mat4(1.f);
glm::mat4 myScalingMatrix = glm::scale(sx, sy ,sz);
glm::vec3 myRotationAxis( 0, 1, 0);
glm::mat4 myRotationMatrix =glm::rotate(glm::mat4(1.0f),rot, myRotationAxis);
glm::vec4 vTrans = myRotationMatrix * trans;
glm::mat4 myMatrix = glm::translate(glm::mat4(1.0f), vTrans.xyz);
Model= myScalingMatrix* myRotationMatrix*myMatrix;
glm::mat4 MVP = Projection* View * Model;
convert vec4 to vec3
So to complete the answer, if the model center is not (0,0,0) , you will have to compute
bounds of your model and translate it by half of it less model bottom left vertex.
It's well explicated here:
model local origin
According to supplied code, the answer is the best available... if you wants more details, supply some screenshots and details on your Projection and view matrix calculations
Im a bit stuck when it comes to rotation and translation in OpenGL.
I got 3 Matrices, projection, view and model.
My VertexShader:
gl_Position = projection * model * view * vec4(vertexData, 1);
What is the best way to translate and rotate objects?
Either multiply my model matrix with a translation and or rotation matrix,
or pass data (rotation and translation) to the shader and to the math there?
Also I need to know "the final object position" for my mousepicking implementation.
What I did so far was something like this:
object.Transformation = Matrix.CreateTransLation(x,y,z) * Matrix.CreateRotation(x,y,z);
...
ForEach object to Draw
{
modelMatrix.Push();
modelMatrix.Mult(object.Transformation); // this also updates the matrix for the shader
object.Draw();
modelMatrix.Pop();
}
This works, but it doesnt feel right. What the best way to do this?
This
gl_Position = projection * model * view * vec4(vertexData, 1);
is wrong. Matrix multiplication is not commutative, i.e. the order of operations matters. The transformations on a vertex' position, in order are:
model
view
projection
Matrix multiplication for column vectors as used by OpenGL is left associative, i.e. goes from right to left. Hence the expression in the R side of the statement should be
gl_Position = projection * view * model * vec4(vertexPosition, 1);
However you can contract view and model transform into a compound modelview (first model, then view) transform. This saves a full matrix multiplication
gl_Position = projection * modelview * vec4(vertexPosition, 1);
The projection should be kept separate as other shading steps may require the eye space position of the vertex which is the result of modelview * position without projection applied.
BTW: You're transforming the vertex position, not the data. A vertex consists a larger number of attributes (not just the position) hence calling it "Data" is semantically wrong.
What is the best way to translate and rotate objects?
Those are part of the modelview transform. You should create a transformation matrix exactly one time on the CPU and pass it to the GPU. Doing this in the shader would force the GPU to redo the whole calculation for each and every vertex. You don't want to do this.
Update due to comment
Let's say you're using my →linmath.h. Then in your drawing function you'd have set up the scaffolding for your scene, i.e. set the viewport, built projection and view matrices
#include <linmath.h>
/* ... */
void display(void)
{
mat4x4 projection;
mat4x4 view;
glClear(…),
glViewport(…);
mat4x4_frustum(projection, …);
// linmath.h doesn't have a look_at function... yet
// I'll add it soon
mat4x4_look_at(view, …);
Then for each object you have a position and a orientation (translation and rotation). Orientations are stored most conveniently in a quaternion, but for processing vectors a matrix representation works better. So we iterate over the objects in the scene
for(int i_object = 0; i_object < scene->n_objects; i++) {
Object * const obj = scene->objects + i;
mat4x4 translation, orientation, model_view;
mat4x4_translate(translation, obj->pos.x, obj->pos.y, obj->pos.z);
mat4x4_from_quat(orientation, obj->orientation);
mat4x4_mul(model_view, translation, orientation);
model_view now contains the model matrix. Next we multiply the view matrix on it. Remember, matrix multiplication is right to left (mat4x4_mul can output onto one of its input operands).
mat4x4_mul(model_view, view, model_view);
Now model_view contains the full compount model orientation and translation and view matrix. All we need to do now is binding the shader program used for the object
glUseProgram(obj->shader->program);
Set the uniforms
glUniformMatrix4f(obj->shader->location.projection, 1, GL_FALSE, projection);
glUniformMatrix4f(obj->shader->location.modelview, 1, GL_FALSE, model_view);
// and a few others...
And draw the object
object_draw(obj);
}
/* ... */
}