This question already has an answer here:
OpenGL, problems with GL_MODELVIEW GL_PROJECTION
(1 answer)
Closed 6 years ago.
I am trying to learn that but I really don't understand.
Using:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(0.5, -0.5, 0.5);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glEnd();
That's the only thing I do in the draw routine. I am drawing a face and it's all OK.
Now I want to see the same face closer and farther from the observer, so I change the Z coordinate. The problem is that the size of the face as it appears on the screen does not change.
I did a try setting a frustum with glFrustum(-15, 15, -15, 15, 0.1, 15), but then everything disappears (the face isn't in frustum view?).
All I want is to draw a face, setting a frustum and moving the face along the Z coordinate seeing as the face getting bigger or smaller. I know there are GL_MODELVIEW and GL_PROJECTION, but I don't understand what they are, maybe this is the trouble.
In OpenGL, by convention, the camera looks towards the negative direction of the Z-axis, i.e. the Z-axis points out of the screen. Your quad is located at Z = 0.5, effectively behind the camera. So to see at least something you have to move the quad to the negative coordinates:
glBegin(GL_QUADS);
glVertex3f(-0.5, -0.5, -0.5);
glVertex3f(0.5, -0.5, -0.5);
glVertex3f(0.5, 0.5, -0.5);
glVertex3f(-0.5, 0.5, -0.5);
glEnd();
Alternatively you can rotate the camera:
glMatrixMode(GL_PROJECTION);
glFrustum(-15, 15, -15, 15, 0.1, 15);
glMatrixMode(GL_MODELVIEW);
static const GLfloat m[] = { -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
glLoadMatrixf(m);
That being said, you are better to ditch the legacy OpenGL fixed-pipeline functionality and teach yourself the programmable pipeline.
Related
I have 3 rectangles and I need to place them in shape of podium. At this moment they look like this:
Code of display func:
glPushMatrix();
glRotated(rotate_x, 1.0, 0.0, 0.0);
glRotated(rotate_y, 0.0, 1.0, 0.0);
glScalef(1, 3, 1);
glColor3fv(gold);
glutSolidCube(2);
glPopMatrix();
glPushMatrix();
glTranslated(2, 0, -3);
glRotated(rotate_x, 1.0, 0.0, 0.0);
glRotated(rotate_y, 0.0, 1.0, 0.0);
glScalef(1, 2, 1);
glColor3fv(silver);
glutSolidCube(2);
glPopMatrix();
glPushMatrix();
glTranslatef(-2, 0, 0);
glScalef(1, 1, 1);
glRotated(rotate_x, 1.0, 0.0, 0.0);
glRotated(rotate_y, 0.0, 1.0, 0.0);
glColor3fv(bronze);
glutSolidCube(2);
glPopMatrix();
When I try to move silver rectangle a liitle bit down to make it on same level as yellow one by using glTranslatef(-2, 0, -2); it just becomes smaller:
The first two parameters of glTranslatef works just fine moving object left/right and closer/further, so why does third parameter changes object's size?
You moved it farther away. Objects which are farther away appear smaller; that's just how perspective works. And since you have no lighting, background objects, or any other depth cues, being farther away is visibly identical to scaling it to a smaller size.
I am starting to use tinker with OpenGL and I want to draw a cube. I went to a tutorial, followed that, and only got this weird square.
Here's my code.
#include <GLFW/glfw3.h>
void drawCube() {
float rotate_x{ 193 };
float rotate_y{ 112 };
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0); glVertex3f(0.5, -0.5, -0.5);
glColor3f(0.0, 1.0, 0.0); glVertex3f(0.5, 0.5, -0.5);
glColor3f(0.0, 0.0, 1.0); glVertex3f(-0.5, 0.5, -0.5);
glColor3f(1.0, 0.0, 1.0); glVertex3f(-0.5, -0.5, -0.5);
glColor3f(1.0, 1.0, 1.0);
glVertex3f(0.5, -0.5, 0.5);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5, -0.5, 0.5);
glColor3f(1.0, 0.0, 1.0);
glVertex3f(0.5, -0.5, -0.5);
glVertex3f(0.5, 0.5, -0.5);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(0.5, -0.5, 0.5);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, -0.5);
glVertex3f(-0.5, -0.5, -0.5);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(0.5, 0.5, -0.5);
glVertex3f(-0.5, 0.5, -0.5);
glVertex3f(-0.5, 0.5, 0.5);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.5, -0.5, -0.5);
glVertex3f(0.5, -0.5, 0.5);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, -0.5, -0.5);
glLoadIdentity();
glRotatef(30, 0.0, 1.0, 0.0);
glEnd();
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Triangle", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
drawCube();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
I'm using GLFW to do this, and I'm building it in Visual Studio 2017 Community Edition.
I also tried to rotate it at the end of drawCube().
The tutorial I followed was https://www.wikihow.com/Make-a-Cube-in-OpenGL but I tweaked it a bit to use glfw.
You are drawing a single polygon with 24 vertices. Since OpenGL requires the polygon to be concave and planar (which your data isn't) it draws some random stuff.
If you want to draw a cube, you either have to split the drawing the call glBegin(GL_POLYGON) and glEnd() for each face separately (as the tutorial shows in the second code sample in section 4), or you can change the primitive mode to GL_QUADS.
Note, that the OpenGL version you are using (fixed function pipeline) is outdated for more than 10 years now. You might want to consider switching to (at least) OpenGL 3.3 core profile and use shader.
Camera
I do not see you are setting the matrices anywhere... So my bet is that your matrices are unit resulting in 2D view no matter how you tweak the rendered axis aligned data.
Use gluPerspective for the GL_PROJECTION. Its a bit tricky to set up the perspective 3D view properly for rookies (as it views in -Z direction which is exact opposite than identity matrix) so your mesh is in viewable area.
CULL_FACE
for starters try glDisable(GL_CULL_FACE) as your data will most likely contain winding errors and you will not know what faces you already have or not otherwise.
cube mesh
right now you are hardcoding it using glVertex calls its much easier to use separate arrays for points and faces (QUADS or TRIANGLES). Also as BDL pointed out you are using forbidden commands inside glBegin/glEnd calls they are ignored and slows things down due to error handling.
lighting
to feel the 3D better you should also add normals for each face and enable lights. Otherwise you would need to color each face with different color to see the "3D".
Take a look at my:
complete GL+GLSL+VAO/VBO C++ example
just ignore the advanced stuff (GLSL,VAO/VBO...) and look for view settings and the cube mesh data. You just need to render it with for loop instead of VAO/VBO. Here example:
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
#ifndef vao_indices
glBegin(GL_QUADS);
for (int i=0;i<6*4*3;i+=3)
{
glNormal3fv(vao_nor+i);
glColor3fv (vao_col+i);
glVertex3fv(vao_pos+i);
}
glEnd();
#else
int i,j,k;
const GLfloat vao_nor[]=
{
// nx ny nz
0.0, 0.0,-1.0,
0.0, 0.0,+1.0,
0.0,-1.0, 0.0,
+1.0, 0.0, 0.0,
0.0,+1.0, 0.0,
-1.0, 0.0, 0.0,
};
glBegin(GL_QUADS);
for (j=0;j<6*4;j++)
{
i=vao_ix[j]; i+=i+i;
k=j>>2; k+=k+k;
glNormal3fv(vao_nor+k);
glColor3fv (vao_col+i);
glVertex3fv(vao_pos+i);
}
glEnd();
#endif
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
using the mesh from gl_simple in that linked QA in both modes (indices and direct).
I have written a program that creates a room that currently contains a triangle. I want to make more objects like this triangle, but I also want to add functionality that allows me to move the objects by clicking on them and dragging them. I am thinking the best way would be to create some sort of template/prototype etc. etc. that has the geometric data passed via a constructor but has a function for moving it around by mouse, but I am unsure if I have it right, and I am not entirely sure about what I actually need to do to get this working like that. Here is my current code, it allows rotation of scene using direction keys, but I am unsure how to make it so I can click on an object and drag it at this point (I have the beginnings of something I was trying for this commented out because I don't think it would work, but if it will let me know how):
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#include <stdlib.h>
#include <GL/glut.h>
void display();
void viewButtons();
//const double ZoomSTEP = 0.2;
//const double zoomFactor = 1.03;
double rotationY = 0;
double rotationX = 0;
// Mouse positions, normalized to [0,1].
//double xMouse = 0.5;
//double yMouse = 0.5;
//GLdouble startView = 2.0;
void display()
{
//Clear the screen and clear z-buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Rotate when user changes rotate_x and rotate_y
glRotatef(rotationX, 1.0, 0.0, 0.0);
glRotatef(rotationY, 0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
//Vertices and colors
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.5, -0.5, 0.5); // P1 is red
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.5, 0.5, 0.5); // P2 is green
glColor3f(0.0, 0.0, 1.0);
glVertex3f(-0.5, 0.5, 0.5); // P3 is blue
glColor3f(1.0, 0.0, 1.0);
glVertex3f(-0.5, -0.5, 0.5); // P4 is purple
glEnd();
/*// White side - BACK
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
glVertex3f(0.5, -0.5, 0.5);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5, -0.5, 0.5);
glEnd();*/
// Purple side - RIGHT
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 1.0);
glVertex3f(0.5, -0.5, -0.5);
glVertex3f(0.5, 0.5, -0.5);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(0.5, -0.5, 0.5);
glEnd();
// Green side - LEFT
glBegin(GL_POLYGON);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, -0.5);
glVertex3f(-0.5, -0.5, -0.5);
glEnd();
// Blue side - TOP
glBegin(GL_POLYGON);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.5, 0.5, 0.5);
glVertex3f(0.5, 0.5, -0.5);
glVertex3f(-0.5, 0.5, -0.5);
glVertex3f(-0.5, 0.5, 0.5);
glEnd();
// Red side - BOTTOM
glBegin(GL_POLYGON);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.5, -0.5, -0.5);
glVertex3f(0.5, -0.5, 0.5);
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, -0.5, -0.5);
glEnd();
glBegin(GL_POLYGON);
glColor3f(0.5, 0.6, 0.3);
glVertex3f(0.3, 0.1, 0.5);
glVertex3f(0.4, 0.1, 0.5);
glVertex3f(0.2, -0.2, 0.1);
glEnd();
glFlush();
glutSwapBuffers();
}
void viewButtons(int button, int x, int y)
{
if (button == GLUT_KEY_RIGHT)
rotationY += 5;
else if (button == GLUT_KEY_LEFT)
rotationY -= 5;
else if (button == GLUT_KEY_UP)
rotationX += 5;
else if (button == GLUT_KEY_DOWN)
rotationX -= 5;
//update display
glutPostRedisplay();
}
int main(int argc, char **argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(720, 640);
glutCreateWindow("Room with objects");
// register callbacks
glutDisplayFunc(display);
glutSpecialFunc(viewButtons);
glEnable(GL_DEPTH_TEST);
// enter GLUT event processing cycle
glutMainLoop();
return 1;
}
If you want to transpose/rotate/scale an arbitrary object the template for this is something like this:
save your current world matrix (you can do that using glPushMatrix)
translate you object to the position you want (using glRotate/glTranslate/glScale)
draw you object (the glBegin/glEnd part)
retrieve your old matrix (if you pushed it to the stack use glPopMatrix)
Repeat this process for every drawable object in your scene.
When manipulating objects you might define one matrix for each object so that you can manipulate them independently. You would then compute the matrices for each object yourself (have a look into glm - a neat framework for doing exactly such things) and then instead of step 2. use glMultMatrix and set you own matrix.
Also, you are using legacy openGL code, so I'am guessing you are learning right now how things work out. My suggestion is instead of learning the old stuff: Have a look into glsl shader programming, vertexbufferobjects and all the good stuff that is beyond opengl 1.4 there are some really good tuts out there http://www.opengl-tutorial.org/
I am trying to draw a large polygon behind the cube to appear like the floor. How ever when ever the background floor is behind the cube it disappears completely. Here is the display function including the background I want to add and one of the cubes sides.
void display(){
// Clear screen and Z-buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
//background floor
glBegin(GL_POLYGON);
glColor3f( 0.5, 0.5, 0.5);
glVertex3f( 1, -0.9, 1 ); // x-y-z right bottom
glVertex3f( 0.6, 0.5, 1 ); //right top
glVertex3f( -0.6, 0.5, 1 ); //left top
glVertex3f( -1, -0.9, 1 ); //left bottom
glEnd();
// Rotate when user changes rotate_x and rotate_y
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
// FRONT side of cube
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.5, 0.0 );
glVertex3f( 0.05, -0.05, -0.05 );
glVertex3f( 0.05, 0.05, -0.05 );
glVertex3f( -0.05, 0.05, -0.05 );
glVertex3f( -0.05, -0.05, -0.05 );
//I have omitted the other 5 sides
glEnd();
glFlush();
glutSwapBuffers();
}
I suspect your poligon is facing outwards.
Try disabling backface culling with glDisable(GL_CULL_FACE). If this works swap the order of the vertices (should be CCW or trigonometric, on the side that the polygon should be visible from).
Don't leave the face culling disabled, unless you don't care about performance.
I just started trying to folow simple "draw cube" openGl tutorial. After final victory over getting OpenGL to work, I still have very veird results. My problem is that the objects tend to resize themselves to match the window size. Instead, I'd like the window size determine the rendering area - the larger the window is, the more you may see.
Here are some screenshots of the resizing:
Normal size
Resized
Images kept as links intentionally!
This auto-resizing behavior brings a question what the coordinates used in OpenGL are.
First thing to keep in mind: OpenGL is a drawing API. It doesn't maintain a scene or something like that.
So what OpenGL does is, it maps geometry input coordinates in the form of vertex attributes to screen space. In the old fixed function there's a special vertex attribute called "vertex position" or just short "vertex" (the actual vertex is more than just position).
The position is transformed to what's usually called "screen" space (but depending on where the viewport is placed, it might as well be called "window" or "viewport) space) in a three step process:
1. Transformation into view/eye space: This is done by multiplying the vertex position with the modelview matrix.
Certain further calculations, like illumination calculation are done in view space.
2. Transformation to clip space: The view space position is transformed into clip space. This is usually called the projection and aptly the matrix describing this transformation is called the projection matrix
In clip space some special things happen, summarized as clipping, you don't have to worry about yet.
3. In the final step transformed the clipped geometry into normalized device coordinates (NDC). NDC space is practically a 1:1 mapping toward the viewport, i.e. the limits of the NDC volume directly correspond to the offset and dimension of the viewport set with glViewport.
You can't change the way the 3rd step happens, and the 1st step is reserved for transforming stuff into view space. So any adjustments must happen in the 2nd step.
So here's what you have to do: The projection limits must be directly proportional to the viewport extents. Like this for example
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-width/2, width/2, -height/2, height/2, -1, 1);
Oh, and just on a general note: You should always set the viewport and projection setup in the drawing function, too. If you see a tutorial that puts those statements in a window resize handler, just disregard it and just do it in the drawing code anyway. On the long term this really simplifies things.
The interesting part:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH ) / 300.0;
double h = glutGet( GLUT_WINDOW_HEIGHT ) / 300.0;
glOrtho( -1 * w, 1 * w, -1 * h, 1 * h, 10, -10);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
In context:
#include <GL/glut.h>
void display();
void specialKeys();
double rotate_y=0;
double rotate_x=0;
void display(){
// Clear screen and Z-buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH ) / 300.0;
double h = glutGet( GLUT_WINDOW_HEIGHT ) / 300.0;
glOrtho( -1 * w, 1 * w, -1 * h, 1 * h, 10, -10);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// Rotate when user changes rotate_x and rotate_y
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
//Multi-colored side - FRONT
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.0, 0.0 ); glVertex3f( 0.5, -0.5, -0.5 ); // P1 is red
glColor3f( 0.0, 1.0, 0.0 ); glVertex3f( 0.5, 0.5, -0.5 ); // P2 is green
glColor3f( 0.0, 0.0, 1.0 ); glVertex3f( -0.5, 0.5, -0.5 ); // P3 is blue
glColor3f( 1.0, 0.0, 1.0 ); glVertex3f( -0.5, -0.5, -0.5 ); // P4 is purple
glEnd();
// White side - BACK
glBegin(GL_POLYGON);
glColor3f( 1.0, 1.0, 1.0 );
glVertex3f( 0.5, -0.5, 0.5 );
glVertex3f( 0.5, 0.5, 0.5 );
glVertex3f( -0.5, 0.5, 0.5 );
glVertex3f( -0.5, -0.5, 0.5 );
glEnd();
// Purple side - RIGHT
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.0, 1.0 );
glVertex3f( 0.5, -0.5, -0.5 );
glVertex3f( 0.5, 0.5, -0.5 );
glVertex3f( 0.5, 0.5, 0.5 );
glVertex3f( 0.5, -0.5, 0.5 );
glEnd();
// Green side - LEFT
glBegin(GL_POLYGON);
glColor3f( 0.0, 1.0, 0.0 );
glVertex3f( -0.5, -0.5, 0.5 );
glVertex3f( -0.5, 0.5, 0.5 );
glVertex3f( -0.5, 0.5, -0.5 );
glVertex3f( -0.5, -0.5, -0.5 );
glEnd();
// Blue side - TOP
glBegin(GL_POLYGON);
glColor3f( 0.0, 0.0, 1.0 );
glVertex3f( 0.5, 0.5, 0.5 );
glVertex3f( 0.5, 0.5, -0.5 );
glVertex3f( -0.5, 0.5, -0.5 );
glVertex3f( -0.5, 0.5, 0.5 );
glEnd();
// Red side - BOTTOM
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.0, 0.0 );
glVertex3f( 0.5, -0.5, -0.5 );
glVertex3f( 0.5, -0.5, 0.5 );
glVertex3f( -0.5, -0.5, 0.5 );
glVertex3f( -0.5, -0.5, -0.5 );
glEnd();
glFlush();
glutSwapBuffers();
}
void specialKeys( int key, int x, int y ) {
// Right arrow - increase rotation by 5 degree
if (key == GLUT_KEY_RIGHT)
rotate_y += 5;
// Left arrow - decrease rotation by 5 degree
else if (key == GLUT_KEY_LEFT)
rotate_y -= 5;
else if (key == GLUT_KEY_UP)
rotate_x += 5;
else if (key == GLUT_KEY_DOWN)
rotate_x -= 5;
// Request display update
glutPostRedisplay();
}
int main(int argc, char* argv[]){
// Initialize GLUT and process user parameters
glutInit(&argc,argv);
// Request double buffered true color window with Z-buffer
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
// Create window
glutCreateWindow("Awesome Cube");
// Enable Z-buffer depth test
glEnable(GL_DEPTH_TEST);
// Callback functions
glutDisplayFunc(display);
glutSpecialFunc(specialKeys);
// Pass control to GLUT for events
glutMainLoop();
// Return to OS
return 0;
}