I want to be able to get the coordinates of an object (e.g. triangle) after it's been translated and rotated, the reason i want to do this is so that later i can do collision detection and calculate the distance between objects using the coordinates. I think I might have to use gluProject but not sure. Also what are the differences between the different coordinate spaces e.g. world, object etc.
I've got some code below it's a circle in the middle of a square, how would i detect when the circle touches one of the edges, i can move it round using the up,down,left, right keys it just changes the x or y coordinates, but i just want to be able to do some basic collision detection and I don't know how to do it.
glPushMatrix();
glColor3f(0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -5.0f);
glScalef(0.5f, 0.5f, 0.0f);
glBegin(GL_POLYGON);
glVertex3f(-5.0f, -5.0f, 0.0f);
glVertex3f(5.0f, -5.0f, 0.0f);
glVertex3f(5.0f, 5.0f, 0.0f);
glVertex3f(-5.0f, 5.0f, 0.0f);
glEnd();
glPopMatrix();
glPushMatrix();
glColor3f(1.0f, 0.0f, 0.0f);
glTranslatef(x, y, -20.0f);
glBegin(GL_POINTS);
glVertex3f(-5, -5, 10.0f);
glEnd();
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
gluSphere(qobj, 1.0f, 20, 20);
gluDeleteQuadric(qobj);
glPopMatrix();
Also what are the differences between the different coordinate spaces e.g. world, object etc.
This is mostly a matter of convention, but:
Model space (= local space) is the coordinate space of a specific model, relative to its "center". If you have a file with a model, the coordinates are centered around some point of it (e.g. it's geometrical center, its base, anything actually).
Scene space (= world space) is the coordinate space relative to an arbitrary point of your scene
Eye space (= view space) is the space where the camera is at point (0,0,0), x faces right, y faces up and z faces out of the screen (-z = deeper)
Clip space is where (-1,-1,*) is the bottom left corner of the viewport, (1,1,*) is the top right corner of the viewport, and the Z coordinate in (-1,1) indicates just the depth (again smaller Z = deeper). (Fragments
Screen space (= window coordinates) is the same as above, except that the coordinates are rescaled from -1..1 to pixel-based values matching the range of the current viewport and depth range.
You transform coordinates from model space to scene space by multiplying (in OpenGL conventions usually left-multiplying) by a model matrix (which contains the information on where the model is on the scene). If you have a scene hierarchy, there can be many "stacked" model matrices for an object (placement of the sword relative to an arm, arm relative to a knight, knight relative to the scene).
Then you transform the coordinates to eye space by multiplying by a view matrix (usually connected to a "camera" object).
After that, using a projection matrix you transform those coords to the screen space, so that OpenGL would map these coords to actual screen pixels (depending on the viewport setting).
Some facts:
Model and view matrices usually contain translation, rotation and/or scaling, while projection matrix usually contains a perspective transformation, which makes the objects further from the screen appear smaller.
Old OpenGL (2.x and earlier) required you to put the matrices on two "matrix stacks":
GL_MODELVIEW stack which should contain View*Model (or View*Model1*Model2...*ModelN),
GL_PROJECTION stack which sould contain only the Projection matrix.
These could just as well be single matrices, not stacks, but the stack (along with glPushMatrix and glPopMatrix) was introduced to let the programmer "save and load" them easily. Only the "topmost" matrix from each stack is used in calculations.
The projection matrix is usually created with gluPerspective or equivalent. The view matrix can be made with gluLookAt (or similarly to model matrices), and the model matrices can be easily assembled using glTranslate, glRotate and glScale.
(note: OpenGL 3.1+ removed these features, allowing you to use any matrices and any conventions you prefer)
Knowing that:
I want to be able to get the coordinates of an object (e.g. triangle) after it's been translated and rotated, the reason i want to do this is so that later i can do collision detection and calculate the distance between objects using the coordinates
A reasonable way to calculate all your physics is to do them in scene space.
Hence if you have a model (e.g. a triangle mesh), to obtain the position of any its vertex in scene space, you need to left-multiply it by only the model's model matrix (or in case of the hierarchy, by all its model matrices).
About gluProject, in case you wondered- it is a convenience method which allows you to multiply a set of coordinates by the current PROJECTION*MODELVIEW and performs viewport transformation to see where it would end up in screen space, and gluUnProject does the reverse.
Ref: http://www.opengl.org/resources/faq/technical/transformations.htm
In addition to Kos' answer, keep in mind that OpenGL is not a scene management library. It is just a drawing API that draws things onto the screen and then forgets about them. Likewise it doesn't have any understanding of what an "object" is, it only knows triangles and even these it can't remember after they have been drawn. Never wondered why you have to render the whole scene anew each frame?
So to know an object's absolute position in the scene, keep track of the transformations yourself and, well, compute its position from these.
mx, my are simply mause cursor coordinates
import numpy as np
i didnt know about glunproject and recalculate it (open version of glunproject)
def CalculateRealCoordinates(mx, my):
Inverseofmodelviewmatrix = np.linalg.inv(glGetDoublev(GL_MODELVIEW_MATRIX))
Inverseofprojectionmatrix = np.linalg.inv(glGetDoublev(GL_PROJECTION_MATRIX))
WindowCoordinates_x = mx
WindowCoordinates_y = my
# glViewport(x, y, w, h)
glViewports = glGetIntegerv(GL_VIEWPORT)
NormalizedDeviceCoordinates_x = (WindowCoordinates_x - (
glViewports[0] + (glViewports[2] / 2))) * (2 / glViewports[2])
NormalizedDeviceCoordinates_y = (WindowCoordinates_y - (
glViewports[1] + (glViewports[3] / 2))) * (2 / glViewports[3])
w = 1
ClipCoordinates_x = NormalizedDeviceCoordinates_x * w
ClipCoordinates_y = NormalizedDeviceCoordinates_y * w
ClipCoordinatesMatrix = [[ClipCoordinates_x],
[-ClipCoordinates_y],
[0],
[0]]
ClipCoordinatesMatrix = np.array(ClipCoordinatesMatrix)
EyeCoordinatesMatrix = np.matmul(Inverseofprojectionmatrix, ClipCoordinatesMatrix)
RealCoordinatesMatrix = np.matmul(Inverseofmodelviewmatrix, EyeCoordinatesMatrix)
RealCoordinates_x = RealCoordinatesMatrix[0, 0]
RealCoordinates_y = RealCoordinatesMatrix[1, 0]
return RealCoordinates_x, RealCoordinates_y
builtin gluUnProject version:
def CalculateRealCoordinates(mx, my):
WindowCoordinates_x = mx
WindowCoordinates_y = my
WindowCoordinates_z = 0
RealCoordinates = gluUnProject(WindowCoordinates_x, WindowCoordinates_y, WindowCoordinates_z, glGetDoublev(GL_MODELVIEW_MATRIX), glGetDoublev(GL_PROJECTION_MATRIX), glGetIntegerv(GL_VIEWPORT))
RealCoordinates_x = RealCoordinates[0]
RealCoordinates_y = RealCoordinates[1]
return RealCoordinates_x, RealCoordinates_y
and if you want to reverse only MODELVIEW_MATRIX
# your projection matrix must be like this -->
# [[1. 0. 0. 0.]
# [0. 1. 0. 0.]
# [0. 0. 1. 0.]
# [0. 0. 0. 1.]]
def CalculateRealCoordinates(mx, my):
Inverseofmodelviewmatrix = np.linalg.inv(glGetDoublev(GL_MODELVIEW_MATRIX))
WindowCoordinates_x = mx
WindowCoordinates_y = my
glViewports = glGetIntegerv(GL_VIEWPORT)
NormalizedDeviceCoordinates_x = (WindowCoordinates_x - (glViewports[0] + (glViewports[2] / 2))) * (
2 / glViewports[2])
NormalizedDeviceCoordinates_y = (WindowCoordinates_y - (glViewports[1] + (glViewports[3] / 2))) * (
2 / glViewports[3])
NormalizedDeviceMatrix = [[NormalizedDeviceCoordinates_x],
[NormalizedDeviceCoordinates_y],
[0],
[0]]
NormalizedDeviceMatrix = np.array(NormalizedDeviceMatrix)
RealCoordinates = np.matmul(Inverseofmodelviewmatrix, NormalizedDeviceMatrix)
print("RealCoordinates:", RealCoordinates)
RealCoordinates_x = RealCoordinates[0, 0]
RealCoordinates_y = RealCoordinates[1, 0]
return RealCoordinates_x, -RealCoordinates_y
Related
How to move camera in OpenGL to capture 6 cube face images and save into files (like image below)?
What does "plugin" means?
I'm confused that you need how to calculate camera position&direction vectors for capture each side of dice or how to implement lookat&perspective functions.
for lookat&perspective functions, there are many resources to refer :
Can't understand gluLookAt arguments
gluPerspective parameters- what do they mean?
these functions are usually provided on many libraries, but if you need, then I will post my implementation.
Camera position and direction/up vector is calculated for viewing each side of dice squarely. to do this, you have to care about perspective FOV(field of view) with respect to distance between camera and dice.
If you read above posts carefully, you can determine arguments for these functions.
If once you see each side on screen, I think you need the method combining the result scene of each dice into one screen(or FBO) and save it.
If once you obtain 6 sets of arguments for lookat and perspective, you can use glViewPort.
// if pixel per each side : 10
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//back side draw
glViewPort(0, 10, 10, 10);
//call glulookat & gluperspective or equivalent functions with arguments so that back side of dice drew on your Viewport fully
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//up side draw
glViewPort(10, 0, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//left side draw
glViewPort(10, 10, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
...
The above code draw 6 times in each selected viewport of your result FBO.
An example using PyQt5 for making an image of a plane with size X, Y in the z=0 plane.
Xt = X/2 #center of your camera in X
Yt = Y/2 #center of your camera in Y
dist = math.tan(math.radians(60))*Y/2 #Compute the distance of the campera from plane
#assuming a 60 degree projection
aspect = float(self.width)/float(self.height) #aspect ratio of display
center = QtGui.QVector3D(Xt, Yt, 0) #look at this point
eye = QtGui.QVector3D(Xt, Yt, dist) #Point of Camera in space
up = QtGui.QVector3D(0, 1, 0)
self.modelview = QtGui.QMatrix4x4()
self.modelview.lookAt(eye,center,up) #build modelview matrix with given parameters
self.projection = QtGui.QMatrix4x4()
self.projection.perspective(60.0, aspect, dist*0.0001, dist*10000.0) #build projection matrix
repeating this process for each side + adjusting the z distance to your cube should yield the desired result. The you can just write your results to a framebuffer and read that buffer into an array.
I'm trying to teach myself the ways for 3D programming with OpenGL, however I am struggling with some things, especially projection matrices.
I defined some vertices for a cube and successfully handed them to my graphics processor. The cube goes from xyz -0.5 to xyz 0.5 respectively, which gets rendered fine.
To move it into my world coordinate system, I am using this model matrix:
auto model = glm::mat4(
glm::vec4(1, 0, 0, 0),
glm::vec4(0, 1, 0, 0),
glm::vec4(0, 0, 1, 0),
glm::vec4(0, 0, 0, 1)
);
model = glm::translate(model, glm::vec3(0.f, 0.f, 495.f));
model = glm::scale(model, glm::vec3(100.f, 100.f, 100.f));
This successfully moves my cube to (-50, -50, 445) -> (50, 50, 545) so its now centered in the 200x200x1000 world coordinates I defined for myself.
My camera / view matrix is
auto view = glm::lookAt(
glm::vec3(0.f, 0.f, 5.f),
glm::vec3(0.f, 0.f, 0.f),
glm::vec3(0.f, 1.f, 0.f)
);
which moves the cube slightly closer, changing the z coordinate to 440 and 540 respectively. I don't understand why this is happening but I guess it has something to do with glm expecting a right hand coordinate system while I am working with a left handed one? While this is not why I am posting this question, I would be happy if someone would clear it up for me.
Now to my actual problem: I am trying to make use of glm::perspective. I call it like this:
auto perspective = glm::perspective(glm::radians(55.f), 1.f, 0.f, 1000.f);
If I'm not mistaken, at a z value of 440 I can expect the clipping area to go from roughly -229 to 229, so I would expect that bottom right cube vertex at (-50,-50) is visible. I calculated this by drawing the frustum in 2D, when I noticed that I should be able to calculate the height of any distance to the camera using tan(alpha / 2) * distToCamera = maxVisibleCoordinate (working with a 1:1 aspect ratio). Is this a correct assumption? Here is my terrible drawing, maybe you can tell that I have a wrong understanding of something with it:
In the final step I am trying to get all this together in my vertex shader using
gl_Position = projection * view * model * vec4(pos.x, pos.y, pos.z, 1.0);
which yields a perfectly reasonable result for the x and y value but the z value is always -1 which is, as far as I know, just right for not being displayed.
For my front-bottom-left vertex of the cube (-0.5, -0.5, -0.5) the result is (-96.04, -96.04, -440, -440), normalized to (-0.218, -0.218, -1).
For my back-top-right vertex of the cube (0.5, 0.5, 0.5) the result is (96.04, 96.04, -550, -550), normalized to (0.218, 0.218, -1).
What am I getting wrong, that my z value is lost and just set to -1 instead? When playing around with the camera position, the best I can get is getting it to 1, which also results in an empty window and is definitely not what I would expect.
A projection matrix is like this:
In the picture, f is for zfar and n is for znear.
As you can see, if you put znear = 0, the term at the 4th column become zero, which is incorrect. Also, -(f+n)/(f-n) = -1, which is incorrect too.
So, the conclusion is, znear cannot be zero. It is usually a small value, for example, 0.1
Since Amadeus already answered the question correctly, I'm going to just use this space to add some clarifying information about why it's correct.
We can refer back to the diagram you provided to explain what the problem is: You have two planes, the near plane and the far plane, representing the range at which you may view objects. What the Perspective Matrix does is it takes everything in between those two planes, within the Frustrum that you've defined (mathematically a cone, but our monitors are rectangular, so...) and maps them onto the flat Near-plane to create the final image. In a sense, you can think of the Near Plane as representing the monitor.
So given this context, if you were to set the Near Plane's distance to 0, meaning it was identical to the camera, what would happen? Well, in a cone it would set the plane to a single point, and in a frustrum, it's the same. You cannot view objects drawn onto a single point. You need a surface with actual surface area to draw onto.
That is why it is inappropriate to set the near value to 0. It would turn the drawing surface into a single point, and you cannot mathematically render any objects on a single point. Hence why the essential mathematical formulas backing the matrix will break down and result in bad outcomes if you try to do so anyways.
I have found that tilting an object (by 23.4 degrees) changes the local or object space by the same angle. The following code comes before the rendering loop.
model[1] = glm::mat4(1.0f);
...
spheres[1].m_currentPosition = glm::vec3(65.0f, 0.0f, -60.0f);
...
model[1] = glm::translate(model[1], spheres[1].m_currentPosition);
model[1] = glm::rotate(model[1], glm::radians(-23.4f), glm::normalize(glm::vec3(0.0f, 0.0f, 1.0f)));
In the rendering loop I have very little code other than a regular rotation about what I specified before the rendering loop as,
rotationAxis[1] = glm::normalize(glm::vec3(0.0f, 1.0f, 0.0f));
This will cause a rotation about an axis tilted by 23.4 degrees, the following image being a static screen shot:
Where the lines meet at world coordinates (0, 0, 0).
===
If I reverse the first two lines, viz.,
model[1] = glm::rotate(model[1], glm::radians(-23.4f), glm::normalize(glm::vec3(0.0f, 0.0f, 1.0f)));
model[1] = glm::translate(model[1], spheres[1].m_currentPosition);
The result is,
===
In the rendering loop I can rotate the sphere in place about the specified rotationAxis[1], though the rotation is about a tilted 23.4 degree axis running through the blue top and bottom of the sphere in both cases.
Every other change to the (x, y, z) position of the sphere is about this now tilted frame of reference, again in both cases.
What I want is for the sphere to "orbit" in the plane of the horizontal line by calculating new (x, y, z) coordinates and then translating by the difference from the previous (x, y, z) coordinates. This tilt would cause me to have to adjust those coordinates for the tilt. While this is hardly impossible, I am looking for a more straightforward solution, and a better understanding of what is happening.
I have read about the order of translating and rotating in OpenGL, though changing the order does not solve my problem.
I am working on an opengl program. The viewing parameters are :
eye 0 -4 6
viewup 0 1 0
lookat 0 0 0
I want to draw a background rectangle (with texture) such that I will be able to see it from the current eye location. Right now, the eye is looking from the -ve Y direction. I want to be able to draw a rectangle that covers the entire screen. I am not understanding what coordinates to give to the rectangle and how to get the texture mapping.
Currently I have this in my method:
What would be the code for the same. I have this in function:
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(-1.0, -1.0);
glVertex2f(-1.0, 1.0);
glVertex2f(1.0, 1.0);
glVertex2f(1.0, -1.0);
glEnd();
glPopMatrix();
The easiest option for drawing a background image that is independent of the camera is to draw it in normalized device coordinates (NDC) and do not perform any transformations/projections on it.
To cover the whole screen, you have to draw a quad going from p = [-1, -1] to [1,1]. The texture coordinates can then be found by tex = (p + 1)/2
Normalized device coordinates are the coordinates one would normally get after applying projection and the perspective divide. They span a cube from [-1,-1,-1] to [1,1,1] where the near plane is mapped to z = -1 (at least in OpenGL, in DirectX the near plane is mapped to z=0). In your special case, the depth should not matter, as long as you draw the background plane as the first element in each frame and disable the depth-test.
I've just started playing with OpenGl to render a number of structure each comprising a number of polygon.
Basically I want to perform the equivalent of setting a camera at (0,0,z) in the world (structure) coordinates and rotate it about the x,y and z-axes of the world axes (in that order!) to render a view of each structure (as I understand it it common practice to do use the inverse camera matrix). Thus as I understand it I need to translate (to world origin i.e. (0,0,-z)) * rotateZrotateYrotateX * translate (re-define world origin see below)
So I think I need something like:
//Called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(9.148, (double)w / (double)h, 800.0, 1500.0);
}
float _Zangle = 10.0f;
float _cameraAngle = 90.0f;
//Draws the 3D scene
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
glLoadIdentity(); //Reset the drawing perspective
glTranslatef(0.0f, 0.0f, -z); //Move forward Z (mm) units
glRotatef(-_Zangle, 0.0f, 0.0f, 1.0f); //Rotate "camera" about the z-axis
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f); //Rotate the "camera" by camera_angle about y-axis
glRotatef (90.0f,1.0f,0.0f,0.0f); // rotate "camera" by 90 degrees about x-axis
glTranslatef(-11.0f,189.0f,51.0f); //re-define origin of world coordinates to be (11,-189,-51) - applied to all polygon vertices
glPushMatrix(); //Save the transformations performed thus far
glBegin(GL_POLYGON);
glVertex3f(4.91892,-225.978,-50.0009);
glVertex3f(5.73534,-225.978,-50.0009);
glVertex3f(6.55174,-225.978,-50.0009);
glVertex3f(7.36816,-225.978,-50.0009);
.......// etc
glEnd();
glPopMatrix();
However when I compile and run this the _angle and _cameraAngle seem to be reversed i.e. _angle seems to rotate about y-axis (Vertical) of Viewport and _cameraAngle about z-axis (into plane of Viewport)? What am I doing wrong?
Thanks for taking the time to read this
The short answer is: Use gluLookAt(). This utility function creates the proper viewing matrix.
The longer answer is that each OpenGL transformation call takes the current matrix and multiplies it by a matrix built to accomplish the transformation. By calling a series of OpenGL transformation function you build one transformation matrix that will apply the combination of transformations. Effectively, the matrix will be M = M1 * M2 * M3 . . . Mathematically, the transformations are applied from right to left in the above equation.
Your code doesn't move the camera. It stays at the origin, and looks down the negative z-axis. Your transformations move everything in model space to (11,-189,-51), rotates everything 90 degrees about the x-axis, rotates everything 90 degrees about the y-axis, rotates everything 10 degrees about the z-axis, then translates everything -z along the z-axis.
EDIT: More information
I'm a little confused about what you want to accomplish, but I think you want to have elements at the origin, and have the camera look at those elements. The eye coordinates would be where you want the camera, and the center coordinates would be where you want the objects to be. I'd use a little trigonometry to calculate the position of the camera, and point it at the origin.
In this type of situation I usually keep track of camera position using longitude, latitude, and elevation centered on the origin. Calculating x,y,z for the eye coordinates is simplyx = elv * cos(lat) * sin(lon), y = elv * sin(lat), z = elv * cos(lat) * cos(lat).
My gluLookAt call would be gluLookAt(x, y, z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
You could rotate the up on the camera by changing the last three coordinates for gluLookAt.
The z axis is coming from the center of the monitor into you. So, rotating around the z-axis should make the camera spin in place (like a 2D rotation on just the xy plane). I can't tell, but is that what's happening here?
It's possible that you are encountering Gimbal Lock. Try removing one of the rotations and see if things work the way they should.
While it's true that you can't actually move the camera in OpenGL, you can simulate camera motion by moving everything else. This is why you hear about the inverse camera matrix. Instead of moving the camera by (0, 0, 10), we can move everything in the world by (0, 0, -10). If you expand those out into matrices, you will find that they are inverses of each other.
I also noticed that, given the code presented, you don't need the glPushMatrix()/glPopMatrix() calls. Perhaps there is code that you haven't shown that requires them.
Finally, can you provide an idea of what it is you are trying to render? Debugging rotations can be hard without some context.
Short answer :Good tip
Longer answer: Yes the order of matrix multiplication is clear... that's what I meant by inverse camera matrix to indicate moving all the world coordinates of structures into the camera coordinates (hence the use of "camera" in my comments ;-)) instead of actually translating and rotating camera into the world coordinates.
So if I read between the lines correctly you suggest something like:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
glLoadIdentity(); //Reset the drawing perspective
gluLookAt(0.0,0.0,z,11.0,-189.0,-51.0,0.0,1.0,0.0); //eye(0,0,z) look at re-defined world origin(11,-189,-51) and up(0.0,1.0,0.0)
glRotatef(-_Zangle, 0.0f, 0.0f, 1.0f); //Rotate "camera" (actually structures) about the z-axis
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f); //Rotate the "camera" (actually structures!) by camera_angle about y-axis
glRotatef (90.0f,1.0f,0.0f,0.0f); // rotate "camera" (actually structures) by 90 degrees about x-axis
glPushMatrix();
Or am I still missing something?
I think you are mixing axes of your world with axes of the camera,
GLRotatef only uses axes of the camera, they are not the same as your the world axes once the camera is rotated.