3D Orthographic Projection - opengl

I want to construct a Orthographic projection to make my sun's shadow map look right. Unfortunately, the code is not achieving the desired results as using the regular perspective projection. Here's my code for setting up the projection matrix:
glViewport (0, 0, (GLsizei)shadowMap.x, (GLsizei)shadowMap.y);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
//suns use this
glOrtho(0, shadowMap.x, 0, shadowMap.y, 0.1,1000.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
From what I understand that should be correct. However, after a quick debug render, I noticed that the scene was rendering in a tiny portion of the screen. After some experimentation, I found changing the shadowMap values in glOrtho made it cover the whole texture, but it was really zoomed in. In my perspective projection I use 0.1 and 1000.0 for my near and far, and I've experimented with those and it does change the results, but not get the desired results still. The only time that I get the correct results is when the values are kept with shadowMap.x and shadowMap.y, but like I said, its rendering really small.
What am I doing wrong here? Everything I've read said that the initial code is correct.
EDIT:
Apparently it wasn't clear that this is for the shadow map pass, the regular pass is rendered with perspective and is fine.

Shadow mapping is multi pass algorithm.
You are reffering to the first pass (point 1).
Render scene form light source view into depth texture
Render scene from camera view with depth texture projection mapping enabled.
current fragment xy+depth is then transformed into light projection coordinates and is compared to stored depth on depth texture
if both depths are equal (or nearly equal) current fragment should be considered as lit, otherwise as shadowed.
So everything's fine with your code, store depth values from this pass to depth texture and proceed to point 2.
One thing you should think about is how wide area your light should cover (in world space). With loadidentity on modelview you are attempting to cover 1 world unit x 1 world unit area for you light only.
Consider we have a sphere at 0,0,0 with radius 5.0
We have depth texture of 256,256 dims.
We want to project it along Z onto sphere.
glVieport(0,0,256,256);
glMatrixMode(GL_PROJECTION);
glLoadidentity();
glOrtho(-2.5,2.5,-2.5,2.5,-1000,1000);
glMatrixMode(GL_MODELVIEW);
glLoadidentity();
//flip z, we cast light from obove
glRotate(1,0,0,180);

I don't see where you set the light modelview matrix. You can render a shadow map using the code below:
double* getOrthoMVPmatrix(vector3 position,vector3 lookat,
GLdouble left, GLdouble right,
GLdouble bottom, GLdouble top,
GLdouble nearVal, GLdouble farVal)
{
glPushMatrix();
double projection[16];
double modelView[16];
double *matrix = new double [16];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( left, right, bottom, top, nearVal, farVal) ;
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
gluLookAt(position.x,position.y,position.z,lookat.x,lookat.y,lookat.z,0,1,0);
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glPopMatrix();
matrix = projection*modelView;
return matrix ;
}
void renderShadowMap(void)
{
//"Bind your depth framebuffer"
glViewport(0,0,"Your SM SIZE","Your SM SIZE");
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
double *MVP = getOrthoMVPmatrix( "your light position","your light position" + "your light direction",
-"left","right",
"bottom","top",
"near","far"
) ;
//"call glUseProgram to bind your shader"
// set the uniform MVP we made "
//"Draw your scene "
glViewport(0,0,"screen width","screen height");
}
Your will need to make a multiplication operator for double [16] array. In my case i made a matrix class but do it your way.
Dont forget to call glCullFace(GL_BACK) before drawing your real scene and free MVP after.

Related

Draw oval with sphere in Opengl

I want to draw an oval by projection the sphere on the screen (like rasterize). Here is my code but it doesn't show anything on the screen. Should I use more functions to initialize the projection? Is this way possible to draw oval on screen by using sphere?
GLfloat xRotated, yRotated, zRotated;
GLdouble radius=1;
void display(void);
void reshape(int x, int y);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800,800);
glutCreateWindow("OVAL");
zRotated = 30.0;
xRotated=43;
yRotated=50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void)
{
glMatrixMode(GL_PROJECTION);
glOrtho(0.1, 1.0, 0.1, 1.0, -1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glColor3f(0.9, 0.3, 0.2);
glRotatef(xRotated,1.0,0.0,0.0);
glRotatef(yRotated,0.0,1.0,0.0);
glRotatef(zRotated,0.0,0.0,1.0);
glScalef(1.0,1.0,1.0);glutSolidSphere(radius,20,20);
glFlush();
}
void reshape(int x, int y)
{
if (y == 0 || x == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(39.0,(GLdouble)x/(GLdouble)y,0.6,21.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,x,y);
}
You are drawing a sphere compltely outside of the viewing volume, so it should be no surprise that it can't be seen.
There are a couple of issues with your code:
All OpenGL matrix functions besides glLoadIndentity and glLoadMatrix always post-multiply a matrix to the current top element of the current matrix stack. In your display function, you call glOrtho without resetting the projection matrix to identity before. This will result in totally weird - and different - results if the display callback is called more than once.
You should add a call to glLoadIdentity() right before calling glOrtho.
You set up the model view transformations so that the sphere's center will always end up at (0,0,-5) in eye space. However, you set a projectiom matrix which defines a viewing volume which goes from z=1 (near plane) to z=-1 (far plane) in eye space, so your spehre is actually behind the far plane.
There are several ways this could be fixed. Changing the viewing frustum by modifying the parameters of glOrtho might be the easisest. You could for example try (-2, 2, -2, 2, 1, 10) to be able to see the sphere.
It is not really clear what
I want to draw an oval by projection the sphere on the screen (like rasterize).
exactly means. If you just want the sphere to be distorted to an ellipsoid, you could just apply some non-uniform scaling. This in principle could be done in the projection matrix (if no other objects are to be shown), but this would make much more sense to apply it to the model matrix of the sphere - you already have the glScale call there, you could try something like glScalef(1.0f, 0.5f, 1.0f);.
Also note that the ortho parameters I suggested previously will result in some distortion if your viewport is not exactly square. In a real world, one wants to incorporate the aspect ratio of the viewport into the projection matrix.
If you want to see the sphere deformed as by a perspective projection, you would have to skip the glOrtho altogheter and switch to a perspective projection matrix.
The code you are using is totally outdated. The OpenGL matrix stack has been deprecated in OpenGL 3.0 (2008) and is not available in core profiles of modern OpenGL. The same applies for builtin vertex attributes like glColor or immediate mode drawing and client-side vertex arrays. As a result, GLUT's drawing functions can also not be used with modern GL any more.
If you really intend learning OpenGL nowadays, I stronly advise you to ignore this old cruft and star learning the modern way.

OpenGL switching between ortho and perspective

I have a tile engine using orthographic projection in immediate mode and I'm just trying to draw a 3d cube on top of my tile scene, in hopes that I can eventually incorporate 3d models into my engine instead of just sprites / textured quads. I would also like to make the tiles 3d for that slight bit of extra eye candy.. Hopefully I can eventually convert this to use modern OpenGL so I can take advantage of those extra features. Not on the top of my priority list at the moment. So on to the question.
I'm initializing OpenGL with this:
void initGL()
{
glDisable(GL_DEPTH_TEST);
glViewport( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//...setting some various other attributes, omitted for brevity...
glEnable(GL_TEXTURE_2D);
glClearColor( 0, 0, 0, 0 );
}
I have a function for drawing a cube that works.
void draw_cube()
{
/* position object */
glRotatef(30.0F, 1.0F, 0.0F, 0.0F);
glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
/* draw six faces of a cube */
glBegin(GL_QUADS);
...vertices... (removed for brevity)
glEnd();
}
I made 2 functions for setting the 2d and 3d projection modes.
void set3d()
{
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(0,SCREEN_WIDTH,0,SCREEN_HEIGHT, 0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void set2d()
{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
For the sake of completeness, some pseudocode of my textured quad drawing..
pushmatrix();
translate();
rotate();
-translate();
glbegin();
...vertices
glend();
popmatrix();
So far I have managed to get the cube to draw on top of the tiles, but it disappears after approximately 1 second to never be seen again until I run the program again.
Basically what I'm doing in the main loop is this:
move objects around, process collisions, etc.
set2d();
draw textured quads, lines, text, etc. in 2d mode.
set3d();
draw_cube();
My question is: Why is the cube disappearing, and are there any errors in my set2d() and set3d() functions?
You have quite a few problems in this code, too many to list in comments in fact.
Your projection matrices are changing the handedness of your post-projected coordinate space, which will affect polygon winding.
Stick to a single handedness, unless you want to reverse the direction used for front- / back-facing polygon facets (glFrontFace (...)) - it is CCW by default, but you will have to change it to CW when you use set3d (...) to maintain consistent behavior.
This problem arises because you have the Y-axis going different directions
The behavior your are describing, where the object appears briefly and then disappears is indicative of an issue with your matrix stack.
Are you calling initGL (...) more than once in your software? You will run into a stack overflow if you do this enough times since you needlessly push the current matrix onto the stack and never pop it off.
You cannot use 0.0 for zNear with a perspective projection matrix, this will result in wonky math during the perspective divide step that comes after transformation to clip-space; the depth buffer will not work correctly.
In fact, glFrustum (...) will generate a GL_INVALID_VALUE error and do exactly nothing if you pass a value ≤ 0.0 for zNear. On a related note, gluPerspective (...) will not do this since it is not actually part of OpenGL, but it is equally invalid behavior to pass such a value to gluPerspective (...).

gluProject and 2D display

I would like to display a 2D image at a 2D point calculated from a 3D point using gluProject().
So I have my 3D point, I use gluProject to get its 2D coordinates, then I display my image at this point.
It works well but I have a problem with Z coordinate which makes my image appear two times on the screen : where it should really appear and at "the opposite".
Let's take an example : the camera is at (0,0,0) and I look at (0,0,-1) so in direction of negative Z.
I use 3D point (0,0,-1) for my object, gluProject gives me as 2D point the center of my window which is the good point.
So when I look in direction of (0,0,-1) my 2D image appears, when I rotate, it moves well until the point (0,0,-1) is not visible, which makes the 2D image go out of screen so not displayed.
But when I look at (0,0,1), it also appears. Consequently, I get the same result (for the display of my 2D image) if I use 3D point (0,0,-1) and (0,0,1) for example. I assume there is something to do with the Z coordinate that gluProject returns but I don't know what.
Here is my code : my zNear=0.1 and zFar=1000
GLint viewport[4];
GLdouble modelview[16];
GLdouble viewVector[3];
GLdouble projection[16];
GLdouble winX, winY, winZ;//2D point
GLdouble posX, posY, posZ;//3D point
posX=0.0;
posY=0.0;
posZ=-1.0;//the display is the same if posZ=1 which should not be the case
//get the matrices
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
viewVector[0]=modelview[8];
viewVector[1]=modelview[9];
viewVector[2]=modelview[10];
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
int res=gluProject(posX,posY,posZ,modelview,projection,viewport,&winX,&winY,&winZ);
if(viewVector[0]*posX+viewVector[1]*posY+viewVector[2]*posZ<0){
displayMyImageAt(winX,windowHeight-winY);
}
So, what do I need to do to get the good display of my 2D image, that's to say to take Z into account?
gluProject works correctly, you projection matrix projects points on the screen plane, you should check whether point is behind, you can achieve this by calculating dot product of your view vector and vector to point, if it is less then 0 then point is behind.
what is your DisplayImageAt function?
is it similar to this display function given in my code?
I am trying to as well get 2D coordinate of a point selected 3d coordinates.
here is my display pretty much all..
`void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMultMatrixd(_matrix);
glColor3f(0.5,0.5,0.5);
glPushMatrix(); //draw terrain
glColor3f(0.7,0.7,0.7);
glBegin(GL_QUADS);
glVertex3f(-3,-0.85,3);
glVertex3f(3,-0.85,3);
glVertex3f(3,-0.85,-3);
glVertex3f(-3,-0.85,-3);
glEnd();
glPopMatrix();
glPushMatrix();
myDefMesh.glDraw(meshModel);
glPopMatrix();
glutSwapBuffers();
}'

Setting the coordinate system for drawing in OpenGL

I just started reading initial chapters of Blue book and got to understand that the projection matrix can be used to modify the mapping of our desired coordinate system to real screen coordinates. It can be used to reset the coordinate system and change it from -1 to 1 on left, right, top and bottom by the following (as an example)
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); //With 1's in the diagonal of the identity matrix, the coordinate system is rest from -1 to 1 (and the drawing should happen then inside those coordinates which be mapped later to the screen)
Another example: (Width: 1024, Height: 768, Aspect Ratio: 1.33) and to change the coordinate system, do:
glOrtho (-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 100.0, 1000.0);
I expected the coordinate system for OpenGL to change to -133 on left, 133 on right, -100 on bottom and 100 on top. Using these coordinates, I understand that the drawing will be done inside these coordinate and anything outside these coordinates will be clipped.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-100 * aspectRatio, 100 * aspectRatio, -100, 100, 100, 1000);
glMatrixMode(GL_MODELVIEW);
glRectf(-50.0, 50.0, 200, 100);
However, the above command doesn't give me any output on the screen. What am I missing here?
I see two problems here:
The rect should not by show at all, since glRectf() draws at depth z=0, but you set up your orthorgraphic projection to cover the z range [100,1000], so the object lies before the near plane and should be clipped away.
You do not specifiy waht MODELVIEW matrix you use. In the comments, you mention that the object does show up, but not in the place where you expect it. This also violates my first point, but could be explained if the ModelView matrix is not identity.
So I suggest to first use a different projection matrix with like glOrtho(..., -1.0f, 1.0f); so that z=0 is actually covered, and second insert a glLoadIdentity() call after the glMatrixMode(GL_MODELVIEW) in the above code.
Another approach would be to keep the glOrtho() as it is and to specify a translation matrix wich moves the rect somewhere between z=100 and z=1000.

Rotation of camera used for perspective projection

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.