Opengl transformations - perspective division confusion - opengl

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.

Related

OpenGL - Object axes orientation; order of glm::translate and glm::rotate

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.

OpenGL weird vertex shader issue

Before I start my question, a little bit of background. I started learning OpenGL not so long ago, and I have learned most of what I know about it here. I have only really gotten past 2 tutorials, and yes, I know I will eventually have to learn about matrices, but for now, nothing fancy. So let's get on with it.
Okay, so, I simplified my program just a bit, but no worries, it still recreates the same problem. For my example, we are making a purple triangle. I do the usual, initializing GLFW and GLEW, and create a window with the following hints:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 8);
And then I create my window:
GLFWwindow* Window = glfwCreateWindow(640, 480, "Foo", NULL, NULL);
glfwMakeContextCurrent(Window);
glfwSwapInterval(0);
These are my vertices:
float Vertices[] = {
0.0f, 0.5f, 1.0f,
0.5f, -0.5f, 1.0f,
-0.5f, -0.5f, 1.0f
};
My shaders:
const char* vertex_shader =
"#version 330\n"
"in vec3 vp;"
"void main () {"
" gl_Position = vec4 (vp, 1.0);"
"}";
const char* fragment_shader =
"#version 330\n"
"out vec4 frag_colour;"
"void main () {"
" frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);"
"}";
All is good, I compile the whole program, and voila! Purple triangle!
The yellow counter on the top left is FRAPS, by the way.
So, anyways, my brain gets this awesome idea (not really), what if I do this: vec4(vp, vp.z) in the vertex shader? Then I could get some sort of depth just by changing my z's in my buffer, I thought. Note that I wasn't thinking of replacing a perspective matrix, it was just a sort of an experiment. Please don't hate me.
And it worked, by changing the values, I got something that looked like depth, as in it looked like it was getting farther into the distance. Take a look, I changed the top vertex from 1.0 to 6.0:
Now here's the problem: I change the value to 999999999 (9 nines), and I get this:
Seems to work. Little difference from z = 6 though. Change it to 999999999999999999999999 (24 nines)? No difference. Take a look for yourself:
So this is weird. Big difference in numbers, yet little difference visually. Accuracy issues maybe? Multiple 24 nines by 349 and I get the same result. The kicker: Multiply the 24 nines by 350 and the triangle disappears. This is a surprise to me because I thought that the change would be visible and gradual. It clearly wasn't. However, changing the w manually in the vertex shader instead of doing vp.z does seem to give a gradual result, instead of just suddenly disappearing. I hope someone could shed light on this. If you got this far, you're one awesome person for reading through all my crap, for that, I thank you.
Your model can be seen as a simple form of a pinhole camera where the vanishing point for the depth direction is the window center. So, lines that are parallel to the z-axis meet in the center if they are extended. The window center represents the point of infinite depth.
Changing a vertex's z (or w) component from 1 to 6 is a very large change in depth (the vertex is 6 times farther away from the camera than before). That's why the resulting vertex is closer to the screen center than before. If you double the z component again, it will move a bit closer to the screen center (the distance will be halved). But it is obviously already very close to the center, so this change is hardly recognizable. The same applies to the 999999... depth value.
You can observe this property on most natural images, especially with roads:
[Source: http://www.benetemps.com/road-warriors.htm ]
If you walk along the road for - let's say - 5 meters, you'll end up somewhere at the bottom of the image. If you walk five more meters, you continue to the image center. After another five meters you're even closer. But you can see that the distance on the screen gets shorter and shorter the farther away you are.
Nico gave you a great visual explanation of what happens. The same thing can also be explained by using simple math, using the definition of homogeneous coordinates.
Your input coordinates have the form:
(x, y, z)
By using vec4(vp, vp.z) in the vertex shader, you map these coordinates to:
(x, y, z, z)
After the division by w that happens when converting from clip coordinates to normalized device coordinates, this is mapped to:
(x / z, y / z, 1.0f)
As long as z has the value 1.0f, this is obviously still the same as (x, y, z), which explains why the 2nd and 3rd vertex don't change in your experiment.
Now, applying this to your first vertex as you vary the z value, it gets mapped as:
(0.0f, 0.5f, z) --> (0.0f, 0.5f / z, 1.0f)
As you approach infinity with the z value, the y coordinate converges towards 0.5f / infinity, which is 0.0f. Since the center of the screen is at (0.0f, 0.0f), the mapped vertex converges towards the center of the screen.
Also, the vertex moves less and less as the z value increases. Picking a few values:
z = 1.0f --> y = 0.5f
z = 10.0f --> y = 0.05f
z = 100.0f --> y = 0.005f
z = 1000.0f --> y = 0.0005f
For example, when you change z from 100.0f to 1000.0f, y changes by 0.0045, or only a little more than 0.2% of your window height. With a window height of 500 pixels, that would be just about 1 pixel.
Why the triangle disappears completely at a certain value is somewhat more mysterious. I suspect that it must be some kind of overflow/rounding issue during clipping.

OpenGL Directional Lighting + Positioning

I'm writing an engine and using Light 0 as the "sun" for the scene. The sun is a directional light.
I setup the scene's Ortho viewpoint, then setup the light to be on the "East" side of the screen (and to the character) (x/y are coordinates of the plane terrain, with a positive z facing the camera and indicating "height" on the terrain -- the scene is also rotated for an isometric view on the x axis).
The light seems to be shining fine "East" of 0,0,0, but as the character moves it does not shift (CenterCamera does a glTranslate3f on the negative of the values provided, such that they can be mapped specifying world coordinates). Meaning, the further I move to the west, it's ALWAYS dark, with no light.
Graphics.BeginRenderingLayer();
{
Video.MapRenderingMode();
Graphics.BeginLightingLayer( Graphics.AmbientR, Graphics.AmbientG, Graphics.AmbientB, Graphics.DiffuseR, Graphics.DiffuseG, Graphics.DiffuseB, pCenter.X, pCenter.Y, pCenter.Z );
{
Graphics.BeginRenderingLayer();
{
Graphics.CenterCamera( pCenter.X, pCenter.Y, pCenter.Z );
RenderMap( pWorld, pCenter, pCoordinate );
}
Graphics.EndRenderingLayer();
Graphics.BeginRenderingLayer();
{
Graphics.DrawMan( pCenter );
}
Graphics.EndRenderingLayer();
}
Graphics.EndLightingLayer();
}
Graphics.EndRenderingLayer();
Graphics.BeginRenderingLayer = PushMatrix, EndRenderingLayer = PopMatrix Video.MapRenderingMode = Ortho Projection and Scene Rotation/Zoom CenterCamera does a translate to the opposite of the X/Y/Z, such that the character is now centered at X/Y/Z in the middle of the screen.
Any thoughts? Maybe I've confused some of my code here a little?
The lighting code is as follows:
public static void BeginLightingLayer( float pAmbientRed, float pAmbientGreen, float pAmbientBlue, float pDiffuseRed, float pDiffuseGreen, float pDiffuseBlue, float pX, float pY, float pZ )
{
Gl.glEnable( Gl.GL_LIGHTING );
Gl.glEnable( Gl.GL_NORMALIZE );
Gl.glEnable( Gl.GL_RESCALE_NORMAL );
Gl.glEnable( Gl.GL_LIGHT0 );
Gl.glShadeModel( Gl.GL_SMOOTH );
float[] AmbientLight = new float[4] { pAmbientRed, pAmbientGreen, pAmbientBlue, 1.0f };
float[] DiffuseLight = new float[4] { pDiffuseRed, pDiffuseGreen, pDiffuseBlue, 1.0f };
float[] PositionLight = new float[4] { pX + 10.0f, pY, 0, 0.0f };
//Light position of Direction is 5 to the east of the player.
Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_AMBIENT, AmbientLight );
Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_DIFFUSE, DiffuseLight );
Gl.glLightfv( Gl.GL_LIGHT0, Gl.GL_POSITION, PositionLight );
Gl.glEnable( Gl.GL_COLOR_MATERIAL );
Gl.glColorMaterial( Gl.GL_FRONT_AND_BACK, Gl.GL_AMBIENT_AND_DIFFUSE );
}
You will need to provide normals for each surface. What is happening (without normals) is the directional light is essentially shining on everything east of zero, positionally, while everything there has a normal of 0,0,1 (it faces west.)
You do not need to send normals with each vertex as far as I can tell, but rather because GL is a state machine, you need to make sure that whenever the normal changes you change it. So if you're rendering a face on a cube, the 'west' face should have a single call
glNormal3i(0,0,1);
glTexCoord..
glVertex3f...
glTexCoord..
etc.
In the case of x-y-z aligned rectangular prisms, 'integers' are sufficient. For faces that do not face one of the six cardinal directions, you will need to normalize them. In my experience you only need to normalize the first three points unless the quad is not flat. This is done by finding the normal of the triangle formed by the first three sides in the quad.
There are a few simple tuts on 'Calculating Normals' that I found enlightening.
The second part of this is that since it is a directional light, (W=0) repositioning it with the player position doesn't make sense. Unless the light itself is being emitted from behind the camera and you are rotating an object in front of you (like a model) that you wish to always be front-lit, its position should probably be something like
float[] PositionLight = new float[4] { 0.0f, 0.0f, 1.0f, 0.0f };
Or, if the GLx direction is being interpreted as the East-West direction (i.e. you initially are facing north/south)
float[] PositionLight = new float[4] { 1.0f, 0.0f, 0.0f, 0.0f };
The concept is that you are calculating the light per-face, and if the light doesn't move and the scene itself is not moving (just the camera moving around the scene) the directional calculation will always remain correct. Provided the normals are accurate, GL can figure out the intensity of light showing on a particular face.
The final thing here is that GL will not automatically handle shadows for you. Basic GL_Light is sufficient for a controlled lighting of a series of convex shapes, so you will have to figure out whether or not a light (such as the sun) should be applied to a face. In some cases this is just taking the solid the face belongs to and seeing if the vector of the sun's light intersects with another solid before reaching the 'sky'.
Look for stuff on lightmaps as well as shadowmapping for this.
One thing that can trip up many people is that the position sent to glLightFv is translated by the current matrix stack. Thus if you want to have your light set to a specific position in world coordinates, your camera and projection matrices must be set and active on the matrix stack at the time of the glLightFv call.

How to get coordinates of an object in OpenGL

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

c++ OpenGL coordinate transformation

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!