I am trying to render a rectangle onto the screen. When the program is run, only the clear color shows up, and no rectangle.
Here's the code:
glClearColor(0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, 1280, 720);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1280, 720, 0, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT); //Clear the screen and depth buffer
int x = 100;
int y = 100;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + 10, y);
glVertex2f(x + 10, y + 10);
glVertex2f(x, y + 10);
glEnd();
gsm->update();
gsm->render();
glfwSwapBuffers(window);
}
It got culled. You had inverted Y axis with your projection, by supplying bottom =720 larger than top 0. Your quad is counterclockwise in your local coordinates, but in normalized coordinates it is clockwise. Remember, projection matrix is a part of global transform matrix! Now, if that's default state, then out of those two winding directions
the GL_CCW is the actual one, it is considered "Front". By default OpenGL culls triangles with mode glCullFace(GL_BACK), and quad internally is considered as pair of triangles).
Either change order of vertices
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x, y + 10);
glVertex2f(x + 10, y + 10);
glVertex2f(x + 10, y);
glEnd();
or change culling mode to match left-handedness of your coordinate system or disable culling.
See also:
1. https://www.khronos.org/opengl/wiki/Viewing_and_Transformations
2. The answer to Is OpenGL coordinate system left-handed or right-handed?
Related
I draw many lines to form a grid. I want to see the grid rotated on its X-axis, but I never get the intended result. I tried glRotatef and gluLookAt which does not work the way I want. Please see the pictures below.
this is the grid
this is how I want to see it
Edit: geez, posting the code here is also hard, lol, anyway here it is.
Edit2: removed, only leave the code that has issues.
Please find the code below, no matter how I set the gluLookAt, the grid result won't be in the perspective I want.
#include <GL/glut.h>
void display() {
...
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for (int i = 0; i < 720; i += 3)
{
glColor3f(0, 1, 1);
glVertex3f(linePoints[i], linePoints[i + 1], linePoints[i + 2]);
}
glEnd();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -2, 1.25, 0, 0, 0, 0, 1, 0);
}
Lets assume, that you have a grid in the xy plane of the world:
glColor3f(0, 1, 1);
glBegin(GL_LINES);
for (int i = 0; i <= 10; i ++)
{
// horizontal
glVertex3f(-50.0f + i*10.0f, -50.0f, 0.0f);
glVertex3f(-50.0f + i*10.0f, 50.0f, 0.0f);
// vertical
glVertex3f(-50.0f, -50.0f + i*10.0f, 0.0f);
glVertex3f( 50.0f, -50.0f + i*10.0f, 0.0f);
}
glEnd();
Ensure that the distance of to the far plane of the projection is large enough (see gluPerspective). All the geometry which is not in between the near an far plane of the Viewing frustum is clipped.
Further more ensure that the aspect ratio (4.0 / 3.0) match the ratio of the viewport rectangle (window).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 200);
For the use of gluLookAt, the up vector of the view has to be perpendicular to the grid. If the grid is arranged parallel to the xy plane, then the up vector is z axis (0, 0, 1).
The target (center) is the center of the grid (0, 0, 0).
The point of view (eye position) is ought to be above and in front of the grid, for instance (0, -55, 50). Note the point of view is used for a grid with the bottom left of (-50, -50, 0) and a top right of (50, 50, 0).
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -55.0, 50.0, 0, 0, 0, 0, 0, 1);
The code below creates 2 square polygons, red and green.
I'm trying to place a red square on top of the green, but I can't.
The depth buffer is declared, cleaned when necessary, an orthogonal system is configured correctly.
If I specify a value outside the range (2;-2), the polygon disappears as it should.
#include <...>
constexpr auto FPS_RATE = 120;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;
void init();
void idleFunction();
void displayFunction();
double getTime();
double getTime()
{
using Duration = std::chrono::duration<double>;
return std::chrono::duration_cast<Duration>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
}
const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;
void init()
{
glutDisplayFunc(displayFunction);
glutIdleFunc(idleFunction);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void idleFunction()
{
const double current_time = getTime();
if ((current_time - last_render) > frame_delay)
{
last_render = current_time;
glutPostRedisplay();
}
}
void displayFunction()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
//move the red square to the foreground
glTranslatef(-32.5, -32.5, 2);
glColor3f(1, 0, 0);
glBegin(GL_POLYGON);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glPopMatrix();
glPushMatrix();
//move the green square to the background
glTranslatef(32.5, 32.5, -2);
glColor3f(0, 1, 0);
glBegin(GL_POLYGON);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
glutCreateWindow("Window");
init();
glutMainLoop();
return 0;
}
You've to enable the Depth Test:
glEnable( GL_DEPTH_TEST );
The default depth test function (glDepthFunc) is < (GL_LESS).
If the distance to the far plane is 2.0 and the geometry is drawn with z coordinate of 2.0, then the geometry is clipped by the far plane, because the depth of the geometry is not less than the initialization depth of the depth buffer.
Change the depth function to <= (GL_LEQUAL):
glDepthFunc( GL_LEQUAL );
In a Right-handed system the viewspace z-axis points out of the viewport.
So if the z coordinate is "less than", then the object is "behind" an other object.
The projection matrix transforms from view space to normalized device space. In compare to the view space, the normalized device space is a left handed system, where the z-axis points in the viewport. The normalized device z-coordinate in range [-1, 1] (from the front to the back), is mapped to the depth value (in general in range [0, 1]), which is used for the depth test.
To deal with that glOrtho inverts the z-axis, if the near parameter is set less then the far parameter (this is how the function is suggested to be used).
This cause that the depth (z) order doesn't change, when the geometry is transformed form view space to normalized device space.
Note, glOrtho(-w, w, -h, h, -z, z) is the same as glScaled(1.0/w, 1.0/h, -1.0/z)
Since the z-axis is not inverted by the orthographic projection in your example, because near > far,
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);
the z coordinate has to be greater, to be "behind".
If the green rectangle should be behind the red one, then you've to change the orthographic projection (near < far). e.g.:
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -2, 2);
If you don't want to change the projection, then you've to swap the z-coordinates of the geometry:
glPushMatrix();
//move the red square to the foreground
glTranslatef(-32.5, -32.5, -2.0); // foreground because near > far
// ...
glPopMatrix();
glPushMatrix();
//move the green square to the background
glTranslatef(32.5, 32.5, 2.0); // background because near > far
// ...
glPopMatrix();
I am a beginner in OpenGl and I am struggling a bit with setting up the glOrtho camera to match the window size so that I can draw a line using the window's coordinates. For example, if I want to draw a line from coordinates 0,10 (x,y) to 600,10. I managed to draw the line (which will be a "Separator" from the viewport and a toolbar with buttons) in my current set up but it was by "try end error" approach and the coordinates that I needed to put don't make any sense to me. When I tried to draw a line using the above-mentioned coordinates, the line simply did not show up. What I need to change in the glOrtho set up in order to work with these (1000x600) screen size and draw my vertices and not these:
glVertex3f(-2.0, 11.0, 0.0);
glVertex3f(20.0, 11.0, 0.0);
Note, my current window size is 1000x600 (width/height)
This is the line (on the top that crosses the whole screen):
This is my OGWindow class that handles all of the drawing:
void OGWindow::MyReSizeGLScene(int fwidth, int fheight)
{
// Store window size in class variables so it can be accessed in myDrawGLScene() if necessary
wWidth = fwidth;
wHeight = fheight;
// Calculate aspect ration of the OpenGL window
aspect_ratio = (float) fwidth / fheight;
// Set camera so it can see a square area of space running from 0 to 10
// in both X and Y directions, plus a bit of space around it.
Ymin = -1;
Ymax = 12;
Xmin = -1;
// Choose Xmax so that the aspect ration of the projection
// = the aspect ratio of the viewport
Xmax = (aspect_ratio * (Ymax -Ymin)) + Xmin;
glMatrixMode(GL_PROJECTION); // Select The Projection Stack
glLoadIdentity();
glOrtho(Xmin, Xmax, Ymin, Ymax, -1.0, 1.0);
glViewport(0, 0, wWidth, wHeight); // Viewport fills the window
}
void OGWindow::myDrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the drawing area
OGWindow::myDrawModel();
drawToolbar();
glutSwapBuffers(); // Needed if we're running an animation
glFlush();
}
void OGWindow::myDrawModel(GLvoid)
{
switch ( squareColour ) {
case RED:
glColor3f(1.0, 0.0, 0.0);
break;
case BLUE:
glColor3f(0.0, 0.0, 1.0);
break;
}
glBegin( GL_QUADS );
glVertex3f( squareX, squareY, 0.0 ); // Coordinates of bottom-left corner of square
glVertex3f( squareX + squareWidth, squareY, 0.0 );
glVertex3f( squareX + squareWidth, squareY + squareHeight, 0.0 );
glVertex3f( squareX, squareY + squareHeight, 0.0 );
glEnd();
}
// Convert from screen coords returned by mouse
// to world coordinates.
// Return result in worldX, worldY
void OGWindow::screen2World(int screenX, int screenY, double & worldX, double & worldY)
{
// Dimensions of rectangle viewed by camera projection
double projWidth = Xmax -Xmin;
double projHeight = Ymax - Ymin;
// Screen coords with origin at bottom left
int screenLeft = screenX;
int screenUp = wHeight - screenY;
worldX = Xmin + screenLeft * projWidth / wWidth ;
worldY = Ymin + screenUp * projHeight / wHeight ;
}
//Method to draw the toolbar separator line
void OGWindow::drawToolbar(GLvoid) {
//draw toolbar line separator
glColor3f(0.0,0.0,0.0);
glBegin(GL_LINES);
glVertex3f(-2.0, 11.0, 0.0);
glVertex3f(20.0, 11.0, 0.0);
glEnd();
//draw create button
glPushMatrix();
glTranslatef(2.0, 10.0, 0.0);
glutSolidCube(2.0);
glPopMatrix();
}
This is my main class where I am ivoking the methods from OGWindow:
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize( 1000, 600 );
glutInitWindowPosition(0, 0);
glutCreateWindow("OpenGL Demo");
glEnable(GL_DEPTH_TEST); // enable the depth buffer test
glutDisplayFunc(DrawGLScene);
glutReshapeFunc(ReSizeGLScene);
glutMouseFunc(mouseClick);
glutMotionFunc(mouseMotion);
glutPassiveMotionFunc(mousePassiveMotion);
glutIdleFunc(Idle);
theWindow.initGL();
glutMainLoop();
}
Check out the documentation of glOrtho function. As you see, there are 6 parameters: left, right, bottom, top, near, far. You made mistake by setting window width to top instead of bottom parameter. Here's proper use of function:
glOrtho (0, 1000, 600, 0, -1.0, 1.0)
So, first your ortho settings. If you want your camera to match the screen dimensions, glOrtho has to use the same dimensions.
// This will anchor the camera to the center of the screen
// Camera will be centered on (0,0)
glOrtho( -screenWidth/2.f, screenWidth/2.f, -screenHeight/2.f, screenHeight/2.f, -1, 1 );
// This will anchor the camera to the lower left corner of the screen
// Camera will be centered on (screenWidth/2, screenHeight/2)
glOrtho( 0, screenWidth, 0, screenHeight, -1, 1 );
Try both and see the difference. Although if you are making some sort of editor, where your camera doesn't move, you may be looking for the second ortho setup.
Second, you only ever use (apparently) the GL_PROJECTION matrix mode. You must use this mode to set the camera projection and GL_MODELVIEW to apply transforms to the camera or the objects.
So when you call resize and don't change the matrix mode back to GL_MODELVIEW, you'll be applying translations to the projection matrix.
If you did forget to initialize the modelview matrix it may contain garbage values and yield unexpected results.
Okay, so my program opens a file, reads in xyz-points, then draws a line strip out of it. I originally had this program written in SharpGL (implemnted as WPF window) and it worked, but not well due to using immediate mode, so I have moved onto OpenGL in C++. I have (somewhat) figured out VBO's and I now I am trying to add mouse functionality now. My problem is I can't move the picture with my mouse, I want to be able to click and 'drag' the picture. My mouseClickFunc and mouseMotion work (my cout statements execute), however it seems like my translate call is never being executed (i.e. the picture starts partially 'clipped' in the scene and I would like the ability to drag it and center it). I know this is a shot in the dark but I am really not sure what to do.
MotionFunc:
void mouseMotion(int x, int y)
{
if (moveable)
{
xMove += xTransform(x) - xTransform(xDown);
yMove += yTransform(y) - yTransform(yDown);
xDown = x;
yDown = y;
cout << yMove << "---" << xMove << endl;
glutSwapBuffers();
glutPostRedisplay();
}
}
Display Function:
void RenderFunction(void)
{
++FrameCount;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glOrtho(xMin - 1, xMax + 1, yMin - 1, yMax + 1, -diameter * zScale, diameter * zScale);
// Reset the modelview matrix.
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(xMove, -yMove, 0);
//glViewport((GLint)xMove*100, (GLint)-yMove*100, CurrentWidth, CurrentHeight);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_LINE_STRIP, 0, 29000);
glPopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
I am sure there is more code that I need to show, this is just where I think the problem is. Any help would be greatly appreciated.
Here is a picture of a console output and the screen (OpenGL context) as I see it.
UPDATE: Updated my code. It looks like my coordinates are moving, but the picture is not if that makes sense. If you look at my output, if I keep 'dragging' the picture, you can see in the console that the variable xMove and yMove can get as large or small as they want, again translate is just never moving it.
You pop your matrix before drawing things, which resets the matrix to the state of last push matrix. Move glPopMatrix(); below draw call
You're popping the matrix before you call glDrawArrays(), so this naturally negates the effect of the translation. It also negates the glOrtho() call, but that should be issued on the projection matrix and not on the modelview matrix in the first place.
And, of course, the problem is in your code, and not in OpenGL.
In this code excerpt :
glLoadIdentity();
glPushMatrix();
glTranslatef(xMove, -yMove, 0);
//glViewport((GLint)xMove*100, (GLint)-yMove*100, CurrentWidth, CurrentHeight);
glOrtho(xMin - 1, xMax + 1, yMin - 1, yMax + 1, -diameter * zScale, diameter * zScale);
glPopMatrix();
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_LINE_STRIP, 0, 29000);
you are :
setting the identity as the view matrix
push it into the queue
modify it by glTranslate
pop it of the stack
render the image
Therefore, your translation is ignored.
This is correct operation :
glLoadIdentity();
glPushMatrix();
glTranslatef(xMove, -yMove, 0);
//glViewport((GLint)xMove*100, (GLint)-yMove*100, CurrentWidth, CurrentHeight);
glOrtho(xMin - 1, xMax + 1, yMin - 1, yMax + 1, -diameter * zScale, diameter * zScale);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_LINE_STRIP, 0, 29000);
glPopMatrix();
You are multiplying projection before translation, remember to always read matrix transformation from bottome to top in OpenGL 1.1 which you should upgrade IMO. Another issue is that you are poping the matrix before drawing.
Correct code:
//glViewport((GLint)xMove*100, (GLint)-yMove*100, CurrentWidth, CurrentHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(xMin - 1, xMax + 1, yMin - 1, yMax + 1, -diameter * zScale, diameter * zScale);
// Reset the modelview matrix.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(xMove, -yMove, 0);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_LINE_STRIP, 0, 29000);
glPopMatrix();
I am trying to make a tank game. I have successfully loaded an OBJ model, and calculated its bounding box for the model at the origin.
I am now trying to apply the transformations done to my model in the game logic to the original coordinates for the bounding box. For this, I grab the modelview matrix right before drawing my model, then multiply this matrix for the two vectors that define the BBox.
Here is the code that draws my tank:
void drawTank()
{
bBox = calcBBox(modelo, 1);
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, texTank);
glScalef(0.2, 0.2, 0.2);
glTranslatef(posTank.x,posTank.y,posTank.z);
glRotatef(anguloTanque, 0, 1, 0); // rotate around Y (horizontal)
glRotatef(90, 0, 1, 0);
glRotatef(-90, 1, 0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glmDraw(modelo, GLM_TEXTURE | GLM_MATERIAL);
glColor3f(1,0,0);
drawBBox(bBox);
glPopMatrix();
}
With this snippet, my bbox is properly drawn over the tank model (transformations are applied in rendering by the glTranslate & glRotate functions). As you can see I also grab here my ModelView matrix.
Then I apply this matrix as follows (this is my entire display function):
void Display(void) {
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
camera();
glEnable(GL_TEXTURE_2D);
//glTranslatef(0,-40,150);
//PLANE
glBindTexture(GL_TEXTURE_2D, texArena);
glBegin(GL_POLYGON);
glTexCoord2f( 0.0f, 0.0f );
glVertex3f(-500, 0, -500);
glTexCoord2f( 5.0f, 5.0f );
glVertex3f(500, 0, -500);
glTexCoord2f(5.0f, 0.0f );
glVertex3f(500, 0, 500);
glTexCoord2f( 0.0f, 5.0f );
glVertex3f(-500, 0, 500);
glEnd();
drawTank();
glPopMatrix();
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
The function that multiplies a vector by a matrix:
void multVectorByMatrix(float* matrix, point3D vector, point3D &result)
{
result.x = (matrix[0] * vector.x) +
(matrix[4] * vector.y) +
(matrix[8] * vector.z) +
matrix[12];
result.y = (matrix[1] * vector.x) +
(matrix[5] * vector.y) +
(matrix[9] * vector.z) +
matrix[13];
result.z = (matrix[2] * vector.x) +
(matrix[6] * vector.y) +
(matrix[10] * vector.z) +
matrix[14];
}
If I draw the bounding box with this render loop, then my bounding box gets drawn but transformations are not applied properly. I can see the bounding box moving correctly with translations, but rotations are not done right.
What might be the problem here?
edit: some screenshots
Your problem is in this code.
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
You take two vertices from your box and then apply transformations to them, then you use this transformed vertices to display a box, which of course will be axis aligned, because that's the only box you can get from just two opposite vertices. And you can see on your screenshot, that you bbox and the correct bbox have common vertices - these are exactly the vertices you applied your transformations to. So, in order to get a correct bbox, you need to get all vertices of the bbox and apply these transformations to all of them. Then you'll get exactly what you want.