3D - Rotation Matrix from direction vector (Forward, Up, Right) - c++

I need to get rotation matrix from direction vector (vForward) I also have vRight and vUp vectors. All those vectors are unit vectors.
I just need to get rotation matrix.
To get rotation matrix for rotation in only one plane (xy) parallel to ground, I do this:
XMMATRIX xmResult;
Vec3f vFwd = pPlayer->VForward;
vFwd.z = 0;
vFwd.Normalize();
xmResult = XMMatrixSet( vFwd.y, -vFwd.x, 0, 0,
vFwd.x, vFwd.y, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
Above code only get rotation matrix to rotate around Z axis:
I would like to get the code to rotate around all axis.
This is coordinate system I'm forced to use. I know it is strange:
This is how I'm using my matrix later in code:
XMStoreFloat3((XMFLOAT3*)&vStart, XMVector3Transform(XMLoadFloat3((XMFLOAT3*)&vStart), xmTransformation));
XMStoreFloat3((XMFLOAT3*)&vEnd, XMVector3Transform(XMLoadFloat3((XMFLOAT3*)&vEnd), xmTransformation));

Depending on how you use your matrices, Right, Up and Forward should correspond to the rows or columns of your matrix.
xmResult = XMMatrixSet( vRight.x, vRight.y, vRight.z, 0, vFwd.x, vFwd.y, vFwd.z, 0, vUp.x, vUp.y, vUp.z, 0, 0, 0, 0, 1);

Related

opengl - camera cannot see object when glOrtho is used

I'm new to OpenGL and I'm trying to understand how the projection matrix works in it.
To create a simple case, I define a triangle in the world space and its coordinates are:
(0,1,0), (1,0,0), (-1,0,0)
I set the modelview matrix and projection matrix as below:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, 2,
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // does not work
// glOrtho(-2, 2, -2, 2, 0.1, 2.0); // works
From my understanding, gluLookAt() is used to set the viewing matrix. Since OpenGL does not have a concept of "camera", and thus it transforms the entire world to reach the effect of a camera. In the above code, I assume the "camera" is at (0,0,2), looking at (0,0,0). So OpenGL internally moves the triangle backwards along z axis to z=-2.
To define a view frustum, glOrtho() get 6 parameters. To make the triangle visible in the frustum, I set the near and far value to -0.1 and -2.0 respectively and this should indicate that the frustum include [-0.1, -2.0] on z axis.
I searched for similar questions and found out someone states that the last two parameters of glOrtho() is in fact -near and -far. But if this is correct, the following code should work(but it doesn't):
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, -2, // changed 2 to -2, thus the triangle should be transformed to z=2?
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // -near=-0.1, -far=-2.0, thus the frustum should include [0.1, 2.0], thus include the triangle
If I'm correct, the triangle should be drawn on the screen, so there must be something wrong with my code. Can anyone help?
First of all note, that the fixed function pipeline matrix stack and drawing by glBegin/glEnd sequences is deprecated since more than 10 years.
Read about Fixed Function Pipeline and see Vertex Specification for a state of the art way of rendering.
If you use a view matrix like this:
gluLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);
Then the values for the near and the far plane have to be positive when you set up the the projection matrix,
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
because, gluLookAt transforms the vertices to view space (in view space the z axis points out of the viewport), but the projection matrix inverts the z-axis.
But be careful, since the triangle is at z=0
(0,1,0), (1,0,0), (-1,0,0)
and the distance from the camera to the triangle is 2, because of the view matrix, the triangle is placed exactly on the far plane (which is 2.0 too). I recommend to increase the distance to the far plane from 2.0 to (e.g.) 3.0:
glOrtho(-2, 2, -2, 2, 0.1, 3.0);
If you change the view matrix,
gluLookAt(0, 0, -2, 0, 0, 0, 0, 1, 0);
then still the (view space) z-axis points out of the viewport, but you look at the "back" side of the triangle. The triangle is still in the center of the view (0, 0, 0), but the camera position has changed. The triangle is still in front of the camera.
If you would do
gluLookAt(0, 0, 2, 0, 0, 4, 0, 1, 0);
then you would look away from the triangle. You would have to project the backside of the view to the viewport to "see" the triangle (glOrtho(-2, 2, -2, 2, -0.1, -3.0);).
Further note, that glOrtho multiplies the current matrix by the orthographic projection matrix. This means you should set the identity matrix, before you use glOrtho, as you do it with the model view matrix:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
Explanation
The projection, view and model matrix interact together to present the objects (meshes) of a scene on the viewport.
The model matrix defines the position orientation and scale of a single object (mesh) in the worldspace of the scene.
The view matrix defines the position and viewing direction of the observer (viewer) within the scene.
The projection matrix defines the area (volume) with respect to the observer (viewer) projected onto the viewport.
At orthographic projection, this area (volume) is defined by 6 distances (left, right, bottom, top, near and far) to the viewer's position.
View matrix
The view coordinates system describes the direction and position from which the scene is looked at. The view matrix transforms from the wolrd space to the view (eye) space.
If the coordiante system of the view space is a Right-handed system, then the X-axis points to the left, the Y-axis up and the Z-axis out of the view (Note in a right hand system the Z-Axis is the cross product of the X-Axis and the Y-Axis).
Projection matrix
The projection matrix describes the mapping from 3D points of the view on a scene, to 2D points on the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1). Every geometry which is out of the clippspace is clipped.
At Orthographic Projection the coordinates in the view space are linearly mapped to clip space coordinates and the clip space coordinates are equal to the normalized device coordinates, because the w component is 1 (for a cartesian input coordinate).
The values for left, right, bottom, top, near and far define a box. All the geometry which is inside the volume of the box is "visible" on the viewport.
The Orthographic Projection Matrix looks like this:
r = right, l = left, b = bottom, t = top, n = near, f = far
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 -2/(f-n) 0
-(r+l)/(r-l) -(t+b)/(t-b) -(f+n)/(f-n) 1
The z-axis is inverted by the projection matrix.

How to rotate an object using glm::lookAt()?

I'm working on a scenario that involves some cone meshes that are to be used as spot lights in a deferred renderer. I need to scale, rotate and translate these cone meshes so that they point in the correct direction. According to one of my lecturers I can rotate the cones to align with a direction vector and move them to the correct position by multiplying its model matrix with the matrix returned by this,
glm::inverse(glm::lookAt(spot_light_direction, spot_light_position, up));
however this doesn't seem to work, doing this causes all of the cones to be placed on the world origin. If I then translate the cones manually using another matrix it seems that the cones aren't even facing the right direction.
Is there a better way to rotate objects so that they face a specific direction?
Here is my current code that gets executed for each cone,
//Move the cone to the correct place
glm::mat4 model = glm::mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
spot_light_position.x, spot_light_position.y, spot_light_position.z, 1);
// Calculate rotation matrix
model *= glm::inverse(glm::lookAt(spot_light_direction, spot_light_position, up));
float missing_angle = 180 - (spot_light_angle / 2 + 90);
float scale = (spot_light_range * sin(missing_angle)) / sin(spot_light_angle / 2);
// Scale the cone to the correct dimensions
model *= glm::mat4(scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, spot_light_range, 0,
0, 0, 0, 1);
// The origin of the cones is at the flat end, offset their position so that they rotate around the point.
model *= glm::mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, -1, 1);
I've noted this in the comments but I'll mention again that the cones origin is at center of the flat end of the cone, I don't know if this makes a difference or not, I just thought I'd bring it up.
Your order of the matrices seems correct, but the lookAt function expects:
glm::mat4 lookAt ( glm::vec3 eye, glm::vec3 center, glm::vec3 up )
Here eye is the location of the camera, center is the location of the object you are looking at (in your case if you dont have that location, you can use
spot_light_direction + spot_light_position ).
so just change
glm::lookAt(spot_light_direction, spot_light_position, up)
to
glm::lookAt(spot_light_position, spot_light_direction + spot_light_position, up)

Reflect camera in a plane

I have a camera, which is defined through an up vector, a position and a reference point (camera looks at this point). Furthermore I can calculate the view direction, of course.
Now I tried to reflect this camera in a plane (e.g. z = 0). My first attempt was to reflect every single vector in the plane with the belonging reflection matrix and looked like this:
mat4 mReflection = mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1);
up = mReflection * up;
position = mReflection * position;
lookAt = mReflection * lookAt;
But this didn't work very well and I don't know why. What is wrong with this method?

Rotate object to "look at" another object in 3 dimensions?

I want to create a formula that rotates my object (o1) to always point into the direction of another object (o2), regardless of o1's position.
Kind of like the camera in the following image:
http://puu.sh/bLUWw/aaa653accf.png
I got the following code so far, but the yaw-axis seems to be inverted:
Vector3 lookat = { lookAtPosition.x, lookAtPosition.y, lookAtPosition.z };
Vector3 pos = { position.x, position.y, position.z };
Vector3 objectUpVector = { 0.0f, 1.0f, 0.0f };
Vector3 zaxis = Vector3::normalize(lookat - pos);
Vector3 xaxis = Vector3::normalize(Vector3::cross(objectUpVector, zaxis));
Vector3 yaxis = Vector3::cross(zaxis, xaxis);
Matrix16 pm = {
xaxis.x, yaxis.x, zaxis.x, 0,
xaxis.y, yaxis.y, zaxis.y, 0,
xaxis.z, yaxis.z, zaxis.z, 0,
0, 0, 0, 1
};
See the following image:
http://puu.sh/bLUSG/5228bb2176.jpg
I'm sure it's just a few variables that have to be swapped, but I couldn't find them...
PS: The position of the object matrix is multiplied at a later stage, for testing purposes...
I found the answer to my issue, it turns out that I just had to change the order of the values inside the matrix like so:
Matrix16 pm = {
xaxis.x, xaxis.y, xaxis.z, 0,
yaxis.x, yaxis.y, yaxis.z, 0,
zaxis.x, zaxis.y, zaxis.z, 0,
0, 0, 0, 1
};
camera matrix is inverse of transform matrix representing its coordinate system
look here: Transform matrix anatomy
origin = o1.position
Z axis = o1.position-o2.position
and make it unit length of coarse
mine frustrum/Zbuffer are configured to view in -Z axis direction
now just compute X,Y axises as perpendicular to eachother and Z also via crossproduct
and make them unit length of coarse
so take some vector (non parallel to Z)
ideally something best to align to like Up vector (0,1,0);
multiply it by Z axis and store result to X(or Y)
and then multiply it again by Z axis and store to Y(or X).
Now you have the transform matrix M1 representing O1 coordinate system
if you want just to render the object then thi is it
if you want to have camera on object o1
then just compute:
ViewMatrix=inverse(M1)*ProjectionMatrix;
here inverse matrix computation for mine OpenGL matrices

Opengl 2.0 Matrix.rotateM xAngle yAngle

I draw cube and want to rotate it using finger movement under the screen. I use this code
Matrix.rotateM(mMVPMatrix, 0, yAngle, 0, 1, 0);
Matrix.rotateM(mMVPMatrix, 0, xAngle, 1, 0, 0);
and I expect the yAngle will rotate cube on y axis of the screen and it's ok
and the xAngle will rotate cube on x axis of the screen, BUT it rotated in the coordinate system of the cube not of the coordinate system of screen.
I can't post images because i have only 1 reputation point :( so I upload images and the links :
NOW
Rotation as it is now
And I want
rotation as I want
You are using Intrinsic Euler angles, which by default rotate the points around local axis. In order to rotate around the global axis you just need to convert them to extrinsic angles. which is as simple as reversing the order so it becomes:
Matrix.rotateM(mMVPMatrix, 0, xAngle, 1, 0, 0);
Matrix.rotateM(mMVPMatrix, 0, yAngle, 0, 1, 0);
You also need to make sure that you post-multiply row vectors, instead of pre-multiplying ccolumn vectors.