openGL rotation with respect to x axis in view coordinator - opengl

Suppose I have a starting view like this
With code
gluLookAt(eye.x, eye.y, eye.z, ref.x, ref.y, ref.z,
viewup.x,viewup.y,viewup.z);
here
(eye.x, eye.y, eye.z) = (5.0, 5.0, 10.0);
(ref.x, ref.y, ref.z) = (0,0, 0) ;
(viewup.x, viewup.y, viewup.z) = (0, 1, 0);
May I know how do I change eye.x, eye.y and eye.z's value so the view coordinate will have a rotation respect to x axis like the following two screenshots.
Is there a rotation matrix operation in view coordinate just like model coordinate's rotation?
Thanks

You should change eye.x and eye.y position, i mean you should change your camera position in gluLookAt function and mantain your lookAt reference in (0,0,0) or in the center of the cube. For the first screenshot you could try:
eye.x=0.0;
eye.y=5.0;
eye.z=10.0;

Related

About view matrix and frustum culling

I was trying to determine if an object (sphere) is inside a view frustum. My strategy was first to get the view matrix:
glm::lookAt(cameraPosition, lookAtPosition, cameraUp);
Where cameraPosition is the position of the camera, lookAtPosition is calculate by cameraPosition + cameraDirection and cameraUp is pretty much self-explanatory.
After obtaining the view matrix, I calculate the 8 vertices of the frustum in the camera view, then multiply the inverse of the view matrix by each point to get the coordinate of them in the world space.
Using these 8 points in the world space, I can construct the 6 planes by using cross products (so their normals will point inward). Then I take the dot product of the object vector (I get the vector by subtracting the object position with an arbitrary point on that plane) with the normal vector of each plane, if it is positive for all 6, I know it's inside the frustum.
So my questions are:
Is the camera view is always set at (0,0,0) and looking at the positive z direction?
The view matrix transform the world view into the camera view, if I use the inverse of it to transform the camera view to the world view, is it correct?
My frustum is opposite with my cameraDirection which causes nothing to be seen on the screen (but it still drawing stuff in the back of my camera).
Is the camera view is always set at (0,0,0) and looking at the positive z direction?
The view space is the space which defines the look at the scene.
Which part is "seen" (is projected onto the viewport) is depends on the projection matrix. Generally (in OpenGL) the origin is (0,0,0) and the view space z axis points out of the viewport. However, the projection matrix inverts the z axis. It turns from a the Right-handed system of the view space to the left handed system of the normalized device space.
the inverse of it to transform the camera view to the world view
Yes.
The view matrix transforms from world space to view space. The projection matrix transform the Cartesian coordinates of the view space to the Homogeneous coordinates of the clipspace. Clipspace coordinates are transformed to normalized device space by dividing the xyz components by the w component (Perspective divide).
The normalized device space is a cube with a minimum of (-1, -1, -1) and a maximum of (1, 1, 1). So the 8 corner points of the cube are the corner of the viewing volume in normalized device space.
(-1, -1, -1) ( 1, -1, -1) ( 1, 1, -1) (-1, 1, -1) // near plane
(-1, -1, 1) ( 1, -1, 1) ( 1, 1, 1) (-1, 1, 1) // far plane
If you want to transform a point from normalized device space to view space, you've to:
transform by the inverse projection matrix
transform by the inverse view matrix
divide the xyz component of the result by its w component
glm::mat4 view; // view matrix
glm::mat4 projetion; // projection matrix
glm::vec3 p_ndc; // a point in normalized device space
glm::mat4 inv_projetion = glm::inverse( projetion );
glm::mat4 inv_view = glm::inverse( view );
glm::vec4 pth = inv_view * inv_projetion * glm::vec4( p_ndc, 1.0f );
glm::vec3 pt_world = glm::vec3( pth ) / pth.w;

OpenGL 3.0 Window Collision Detection

Can someone tell me how to make triangle vertices collide with edges of the screen?
For math library I am using GLM and for window creation and keyboard/mouse input I am using GLFW.
I created perspective matrix and simple array of triangle vertices.
Then I multiplied all this in vertex shader like:
gl_Position = projection * view * model * vec4(pos, 1.0);
Projection matrix is defined as:
glm::mat4 projection = glm::perspective(
45.0f, (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 100.0f);
I have fully working camera and projection. I can move around my "world" and see triangle standing there. The problem I have is I want to make sure that triangle collide with edges of the screen.
What I did was disable camera and only enable keyboard movement. Then I initialized translation matrix as glm::translate(model, glm::vec3(xMove, yMove, -2.5f)); and scale matrix to scale by 0.4.
Now all of that is working fine. When I press RIGHT triangle moves to the right when I press UP triangle moves up etc... The problem is I have no idea how to make it stop moving then it hits edges.
This is what I have tried:
triangleRightVertex.x is glm::vec3 object.
0.4 is scaling value that I used in scaling matrix.
if(((xMove + triangleRightVertex.x) * 0.4f) >= 1.0f)
{
cout << "Right side collision detected!" << endl;
}
When I move triangle to the right it does detect collision when x of the third vertex(bottom right corner of triangle) collides with right side but it goes little bit beyond before it detects. But when I tried moving up it detected collision when half of the triangle was up.
I have no idea what to do here can someone explain me this please?
Each of the vertex coordinates of the triangle is transformed by the model matrix form model space to world space, by the view matrix from world space to view space and by the projection matrix from view space to clip space. gl_Position is the Homogeneous coordinate in clip space and further transformed by a Perspective divide from clip space to normalized device space. The normalized device space is a cube, with right, bottom, front of (-1, -1, -1) and a left, top, back of (1, 1, 1).
All the geometry which is in this (volume) cube is "visible" on the viewport.
In clip space the clipping of the scene is performed.
A point is in clip space if the x, y and z components are in the range defined by the inverted w component and the w component of the homogeneous coordinates of the point:
-w <= x, y, z <= w
What you want to do is to check if a vertex x coordinate of the triangle is clipped. SO you have to check if the x component of the clip space coordinate is in the view volume.
Calculate the clip space position of the vertices on the CPU, as it does the vertex shader.
The glm library is very suitable for things like that:
glm::vec3 triangleVertex = ... ; // new model coordinate of the triangle
glm::vec4 h_pos = projection * view * model * vec4(triangleVertex, 1.0);
bool x_is_clipped = h_pos.x < -h_pos.w || h_pos.x > h_pos.w;
If you don't know how the orientation of the triangle is transformed by the model matrix and view matrix, then you have to do this for all the 3 vertex coordinates of the triangle-

glm::lookat, perspective clarification in OpenGL

All yalls,
I set up my camera eye on the positive z axis (0, 0, 10), up pointing towards positive y (0, 1, 0), and center towards positive x (2, 0, 0). If, y is up, and the camera is staring down the negative z axis, then x points left in screen coordinates, in right-handed OpenGL world coordinates.
I also have an object centered at the world origin. As the camera looks more to the left (positive x direction), I would expect my origin-centered object to move right in the resulting screen projection. But I see the opposite is the case.
Am I lacking a fundamental understanding? If so, what? If not, can anyone explain how to properly use glm to generate view and projection matrices, in the default OpenGL right-handed world model, which are sent to shaders?
glm::vec3 _eye(0, 0, 10), _center(2, 0, 0), _up(0, 1, 0);
viewMatrix = glm::lookAt(_eye, _center, _up);
projectionMatrix = glm::perspective(glm::radians(45), 6./8., 0.1, 200.);
Another thing I find interesting is the red line in the image points in the positive x-direction. It literally is the [eye -> (forward + eye)] vector of another camera in the scene, which I extract from the inverse of the viewMatrix. What melts my brain about this is, when I use that camera's VP matrices, it points in the direction opposite to the same forward direction that was extracted from the inverse of the viewMatrix. I'd really appreciate any insight into this discrepancy as well.
Also worth noting: I built glm 0.9.9 via cmake. And I verified it uses the right-hand, [-1, 1] variants of lookat and perspective.
resulting image:
I would expect my origin-centered object to move right in the resulting screen projection. But I see the opposite is the case.
glm::lookAt defines a view matrix. The parameters of glm::lookAt are in world space and the center parameter of glm::lookAt defines the position where you look at.
The view space is the local system which is defined by the point of view onto the scene.
The position of the view, the line of sight and the upwards direction of the view, define a coordinate system relative to the world coordinate system. 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).
The line of sight is the vector form the eye position to the center positon:
eye = (0, 0, 10)
center = (2, 0, 0)
up = (0, 1, 0)
los = center - eye = (2, 0, -10)
In this case, if the center of the object is at (0, 0, 0) and you look at (0, 0, 2), the you look at a position at the right of the object, this means that the object is shifted to the left.
This will change, if you change the point of view e.g. (0, 0, -10) or flip the up vector e.g. (0, -1, 0).

Creating a view matrix with glm

I am trying to create a view matrix with glm. I know of glm::lookAt and understand how it works. I want to know if there are similar functions that will acheive the same outcome that take different parameters. For example, is there a function that takes an up-vector, a directional bearing on the plane perpendicular(?) to the vector, and an angle? (i.e. The sky is that way, I turn N degrees/radians to my left and tilt my head M degrees/radians upward).
You can just build the matrix by composing a set of operations:
// define your up vector
glm::vec3 upVector = glm::vec3(0, 1, 0);
// rotate around to a given bearing: yaw
glm::mat4 camera = glm::rotate(glm::mat4(), bearing, upVector);
// Define the 'look up' axis, should be orthogonal to the up axis
glm::vec3 pitchVector = glm::vec3(1, 0, 0);
// rotate around to the required head tilt: pitch
camera = glm::rotate(camera, tilt, pitchVector);
// now get the view matrix by taking the camera inverse
glm::mat4 view = glm::inverse(camera);

OpenGL simultaneous translate and rotate around local axis

I am working on an application that has similar functionality to MotionBuilder in its viewport interactions. It has three buttons:
Button 1 rotates the viewport around X and Y depending on X/Y mouse drags.
Button 2 translates the viewport around X and Y depending on X/Y mouse drags.
Button 3 "zooms" the viewport by translating along Z.
The code is simple:
glTranslatef(posX,posY,posZ);
glRotatef(rotX, 1, 0, 0);
glRotatef(rotY, 0, 1, 0);
Now, the problem is that if I translate first, the translation will be correct but the rotation then follows the world axis. I've also tried rotating first:
glRotatef(rotX, 1, 0, 0);
glRotatef(rotY, 0, 1, 0);
glTranslatef(posX,posY,posZ);
^ the rotation works, but the translation works according to world axis.
My question is, how can I do both so I achieve the translation from code snippet one and the rotation from code snippet 2.
EDIT
I drew this rather crude image to illustrate what I mean by world and local rotations/translations. I need the camera to rotate and translate around its local axis.
http://i45.tinypic.com/2lnu3rs.jpg
Ok, the image makes things a bit clearer.
If you were just talking about an object, then your first code snippet would be fine, but for the camera it's quite different.
Since there's technically no object as a 'camera' in opengl, what you're doing when building a camera is just moving everything by the inverse of how you're moving the camera. I.e. you don't move the camera up by +1 on the Y axis, you just move the world by -1 on the y axis, which achieves the same visual effect of having a camera.
Imagine you have a camera at position (Cx, Cy, Cz), and it has x/y rotation angles (CRx, CRy). If this were just a regular object, and not the camera, you would transform this by:
glTranslate(Cx, Cy, Cz);
glRotate(CRx, 1, 0, 0);
glRotate(CRy, 0, 1, 0);
But because this is the camera, we need to do the inverse of this operation instead (we just want to move the world by (-Cx, -Cy, and -Cz) to emulate the moving of a 'camera'. To invert the matrix, you just have to do the opposite of each individual transform, and do them in reverse order.
glRotate(-CRy, 0, 1, 0);
glRotate(-CRx, 1, 0, 0);
glTranslate(-Cx, -Cy, -Cz);
I think this will give you the kind of camera you're mentioning in your image.
I suggest that you bite the apple and implement a camera class that stores the current state of the camera (position, view direction, up vector, right vector) and manipulate that state according to your control scheme. Then you can set up the projection matrix using gluLookAt(). Then, the order of operations becomes unimportant. Here is an example:
Let camPos be the current position of the camera, camView its view direction, camUp the up vector and camRight the right vector.
To translate the camera by moveDelta, simply add moveDelta to camPos. Rotation is a bit more difficult, but if you understand quaternions you'll be able to understand it quickly.
First you need to create a quaternion for each of your two rotations. I assume that your horizontal rotation is always about the positive Z axis (which points at the "ceiling" if you will). Let hQuat be the quaternion representing the horizontal rotation. I further assume that you want to rotate the camera about its right axis for your vertical rotation (creating a pitch effect). For this, you must apply the horizontal rotation to the camera's current angle. The result is the rotation axis for your vertical rotation hQuat. The total rotation quaternion is then rQuat = hQuat * vQuat. Then you apply rQuat to the camera's view direction, up, and right vectors.
Quat hRot(rotX, 0, 0, 1); // creates a quaternion that rotates by angle rotX about the positive Z axis
Vec3f vAxis = hRot * camRight; // applies hRot to the camera's right vector
Quat vRot(rotY, vAxis); // creates a quaternion that rotates by angle rotY about the rotated camera's right vector
Quat rQuat = hRot * vRot; // creates the total rotation
camUp = rQuat * camUp;
camRight = rQuat * camRight;
camView = rQuat * camView;
Hope this helps you solve your problem.
glRotate always works around the origin. If you do:
glPushMatrix();
glTranslated(x,y,z);
glRotated(theta,1,0,0);
glTranslated(-x,-y,-z);
drawObject();
glPopMatrix();
Then the 'object' is rotate around (x,y,z) instead of the origin, because you moved (x,y,z) to the origin, did the rotation, and then pushed (x,y,z) back where it started.
However, I don't think that's going to be enough to get the effect you're describing. If you always want transformations to be done with respect to the current frame of reference, then you need to keep track of the transformation matrix yourself. This why people use Quaternion based cameras.