Maybe I set up GLUT wrong. I want verticies to be relative to their size in pixels. Right now if I create a hexagon, it takes up the whole screen even though the units are 6.
#include <iostream>
#include <stdlib.h> //Needed for "exit" function
#include <cmath>
//Include OpenGL header files, so that we can use OpenGL
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
using namespace std;
//Called when a key is pressed
void handleKeypress(unsigned char key, //The key that was pressed
int x, int y) { //The current mouse coordinates
switch (key) {
case 27: //Escape key
exit(0); //Exit the program
}
}
//Initializes 3D rendering
void initRendering() {
//Makes 3D drawing work when something is in front of something else
glEnable(GL_DEPTH_TEST);
}
//Called when the window is resized
void handleResize(int w, int h) {
//Tell OpenGL how to convert from coordinates to pixel values
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
//Set the camera perspective
glLoadIdentity(); //Reset the camera
gluPerspective(45.0, //The camera angle
(double)w / (double)h, //The width-to-height ratio
1.0, //The near z clipping coordinate
200.0); //The far z clipping coordinate
}
//Draws the 3D scene
void drawScene() {
//Clear information from last draw
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset the drawing perspective
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON); //Begin quadrilateral coordinates
//Trapezoid
glColor3f(255,0,0);
for(int i = 0; i < 6; ++i) {
glVertex2d(sin(i/6.0*2* 3.1415),
cos(i/6.0*2* 3.1415));
}
glEnd(); //End quadrilateral coordinates
glutSwapBuffers(); //Send the 3D scene to the screen
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(400, 400); //Set the window size
//Create the window
glutCreateWindow("Basic Shapes - videotutorialsrock.com");
initRendering(); //Initialize rendering
//Set handler functions for drawing, keypresses, and window resizes
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
glutMainLoop(); //Start the main loop. glutMainLoop doesn't return.
return 0; //This line is never reached
}
How can I make it so that the coordinates:
(0,0),
(10,0),
(10,10),
and (0,10) define a polygon starting at the top left of the screen and is a width and height of 10 pixels?
If you want the objects to be scaled that sort of way, you should use an orthographic projection.
Right now, with perspective, things are scaled not only by their size, but by their Z-axis position. So use this function instead of gluPerspective:
gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
That function basically defines the space you can see, which is like a big rectangular prism. That makes far things appear the same size as near things.
As for the exact scaling, it will also change relative to the viewport size. To get the pixels exactly right, you would have to constantly change the projection, or keep the viewport size fixed.
For it to work out as 1:1, if your viewport is x pixels wide, the orthographic projection should be x pixels wide as well.
If you're drawing in 2D, you don't want to use perspective projection. If you set up your camera with gluOrtho2D(0, window_width, window_height, 0); then you should get what you're looking for.
Related
I am having some trouble running a simple program:(code below text)
i would like to print as an output a square with [50,50],[-50,-50],[50,-50],[-50,50] coordinates.
I'm setting up a glOrtho matrix in init() and then in my display func i print the square with the above coordinates as glVertex2f (for example glVertex2f(50.0,-50.0)) Is it the correct way or does glVertex2f not take real coordinates as values?
Anyway here is the code: (it compiles nicely, however it doesnt show anything in graphics window)
#include <iostream>
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <windows.h>
#include <GL/glut.h>
#endif
#define SCR_WID 640
#define SCR_HEI 480
#include "imageloader.h"
using namespace std;
//*****************************CUSTOM FUNCS***********************************//
void init()
{
glViewport(0,0,SCR_WID,SCR_HEI);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho((double)SCR_WID,0.0,(double)SCR_HEI,0.0,-5.0,-20.0);
glMatrixMode(GL_MODELVIEW);
}
//*****************************CALLBACKS (win 1)******************************//
void resizeFunc(int w, int h)
{
glutReshapeWindow(SCR_WID,SCR_HEI);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
glBegin(GL_QUADS);
glVertex2f(1.0,1.0);
glVertex2f(-1.0,1.0);
glVertex2f(1.0,-1.0);
glVertex2f(-1.0,-1.0);
glEnd();
glutSwapBuffers();
}
void key(unsigned char key, int x, int y)
{
if (key == 'q' || key == 27 )
exit(0);
glutPostRedisplay();
}
//**********************************main func*********************************//
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(SCR_WID,SCR_HEI);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("TestGlut");
glutReshapeFunc(resizeFunc);
glutDisplayFunc(display);
glutIdleFunc(display);
glutKeyboardFunc(key);
init();
glutMainLoop();
return EXIT_SUCCESS;
}
Your init function is a little odd
glViewport(0,0,SCR_WID,SCR_HEI);
The default viewport is already the full window, so this is redundant.
glPushMatrix();
You never call glPopMatrix or manipulate the matrix stack in any other way elsewhere, so why are you doing this?
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho((double)SCR_WID,0.0,(double)SCR_HEI,0.0,-5.0,-20.0);
Calling glLoadIdentity immediately before glOrtho is a waste. glOrtho overwrite the current matrix, so it doesn't matter what it was before. Also glLoadIdentity resets the matrix value back to it's default of an identity matrix, which is what it would be anyway at program start, so it's doubly redundant.
Also, the glOrtho params are 'left right bottom top near far'. You've reversed the X and Y axes by putting a larger number for left and bottom than for right and top. At best this will give you a projection that will put the (0,0) coordinate at the lower right of the screen, which is pretty unusual. Finally, your near and far planes lie completely in negative Z space. That means that vertices that are specified with only two values (glVertex2f as you're using) will always be excluded since they have an implicit 0 for their z coordinate.
void resizeFunc(int w, int h)
{
glutReshapeWindow(SCR_WID,SCR_HEI);
}
Why bother with a resize function if you're going to ignore the input width and height?
glBegin(GL_QUADS);
glVertex2f(1.0,1.0);
glVertex2f(-1.0,1.0);
glVertex2f(1.0,-1.0);
glVertex2f(-1.0,-1.0);
glEnd();
Aside from the fact that these coordinates will produce clipped vertices (because their Z value is implicitly 0, and thus outside of your near/far clip region), you're specifying them in what appear to be in normalized clip coordinates. If you corrected the Z shape problem that genpfault mentioned (by swapping vertex 3 and 4) then these would take up the whole screen if you were working with the default projection matrix. By setting an ortho matrix using the screen pixel dimensions, you've created a square that would be 2 pixels wide and two pixels tall, located in the lower right hand corner of the screen.
void key(unsigned char key, int x, int y)
{
...
glutPostRedisplay();
}
Why? If you want your program to render continuously, and not just when someone hits a key, then you should have glutPostRedisplay() in an idle function, not in the keypress function.
int main(int argc, char *argv[])
{
...
glutIdleFunc(display);
...
}
Don't set your idle function to the display function. If you want your program to animate, make an actual idle function that calls glutPostRedisplay.
I am fairly new to using GLUT, and I have been attempting to compile a program (which I found here, first response) that uses the mouse to draw a rectangle by recording the starting and ending points of a click-and-drag.
As a clean copy/paste, it will compile but not draw anything. It just displays a white screen, even after changing the background color to black (in the setup() function). I've read several sources to verify that this program doesn't miss anything in its draw and reshape functions, and it's all there.
I create a window, set the viewport to the window dimensions, and then use the gluOrtho2D function to set the mapping (since the window and viewport are the same dimensions, I set the mapping to the window dimensions). The mouse callback records where I left-click, and where I release left-click, then calls the glutPostRedisplay() function to redraw the window with the new coordinates. After a bit of debugging, I discovered the coordinates are recorded and saved appropriately, and are measured in pixels (x and y are integers between 0 and window dimension), so I should be able to draw a rectangle from one vertex to the other vertex using the coordinates. But, like I said, it only displays a white screen.
So, is there something wrong with the way I am drawing the rectangle? Am I mapping the window incorrectly? I am seriously lost, and any feedback would be greatly appreciated.
EDIT2: I changed the glutInitDisplayMode from GLUT_SINGLE to GLUT_DOUBLE, and that fixed the whole non-interactive white screen thing. Now it will draw a rectangle with the mouse with a flipped y-coordinate (which I fixed), and it works great now. Thank you very much for the suggestion.
Here is my program (EDIT1: added comments):
#include <cstdlib>
#include <GL/glut.h>
using namespace std;
GLsizei width, height;
struct Position
{
Position() : x(0), y(0) {}
float x;
float y;
};
Position start; // Records left-click location
Position finish; // Records left-click release location
void display()
{
glClear(GL_COLOR_BUFFER_BIT); // clear window
glColor3ub(rand()%256, rand()%256, rand()%256); // generates random color
glBegin(GL_QUADS);
glVertex2f(start.x,start.y);
glVertex2f(finish.x,start.y);
glVertex2f(finish.x,finish.y);
glVertex2f(start.x,finish.y);
glEnd();
glutSwapBuffers(); // display newly drawn image in window
}
void reshape( int w, int h )
{
glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); // set to size of window
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0.0, (float)w, 0.0, (float)h );
width = w; // records width globally
height = h; // records height globally
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
switch(button)
{
case GLUT_LEFT_BUTTON:
if(state==GLUT_DOWN)
{
start.x = x; //x1
start.y = y; //y1
}
if(state==GLUT_UP)
{
finish.x = x; //x2
finish.y = y; //y2
}
break;
glutPostRedisplay();
}
}
void motion( int x, int y )
{
finish.x = x;
finish.y = y;
glutPostRedisplay();
}
void setup()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // *should* display black background
}
int main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,100);
glutCreateWindow("");
setup();
// initializing callbacks
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutMainLoop();
return 0;
}
As my comment suggested:
change:
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
to:
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
I would like to know how to draw the length of a line with respect to the the dimensions of the enclosing window. Note that I am using the combination of GLUT and OpenGL.
For example, say I wanted to draw a line from the bottom center of the screen (I assume this would be at coordinate (WINDOW_LENGTH/2, 0) to the center of the window (WINDOW_LENGTH/2, WINDOW_HEIGHT/2)
How do I do this in OpenGL? Right now I have the following:
//Initializes 3D rendering
void initRendering() {
//Makes 3D drawing work when something is in front of something else
glEnable(GL_DEPTH_TEST);
}
//Called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
//Set the camera perspective
glLoadIdentity(); //
gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}
//Draws the 3D scene
void drawScene() {
//Clear information from last draw
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
glLoadIdentity(); //Reset the drawing perspective
glTranslatef(0, 0, -1);
glBegin(GL_LINES);
//lines
glVertex2f(0, 0);
glVertex2f(0, .25);
glEnd();
glutSwapBuffers(); //Send the 3D scene to the screen
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(400, 400); //Set the window size
//Create the window
glutCreateWindow("Basic Shapes - videotutorialsrock.com");
initRendering(); //Initialize rendering
//Set handler functions for drawing, keypresses, and window resizes
glutDisplayFunc(drawScene);
//glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
cout << "GLUT_WINDOW_X: " << GLUT_WINDOW_X << endl;
cout << "GlUT_WINDOW_Y: " << GLUT_WINDOW_Y << endl;
glutMainLoop(); //Start the main loop. glutMainLoop doesn't return.
return 0; //This line is never reached
}
This gives me the following result:
What does not make sense to me is that my window has dimension 400 X 400 but the coordinates: glVertex2f(0, 0) and glVertex2f(0, .25). draw a line from about the center of the window to about 80% of the height of the window. I have a few speculations:
I know that my call to glTranslatef(0, 0, -1); sets the origin to the global coordinate (0, 0, -1) What is puzzling to me:
How does the -1 correspond to moving the image that far over?
Does the .25 in the second coordinate correspond to 25% of the height?
What would the code look like to draw a line from (WINDOW_LENGTH/2, 0) to (WINDOW_LENGTH/2, WINDOW_HEIGHT/2) That is the line from the bottom center of the window to the center of the window.
If you need more information let me know.
Let me try answer your questions:
You are working in a model-view (world to view) system. So you start modelling in world coordinates and transform it to the view coordinates. Therefore, glTranslatef is moving your world 1 coordinates points away from de camera.
What you do in openGL is weakly related to your windows coordinates. So, 0.25 really means 0.25 to openGL and nothing more. This means that you can stablish any semantics to points, like meters, kilometres, milimeters and so on. The correlation between openGL buffer and windows coordinates is stablished in the function gluPerspective, in which it says, basically, the region of your world that must be mapped to your windows coordinate system. The second function, glViewport only says how this map will be translated to you windows coordinates. In your case, you are telling to use all the windows.
As I said before, you need to manipulate your gluPerspective to control how much the openGL world will be mapped to your windows coordinates. To do that, you change the angle of the perspective. Greater angles, more openGL regions will be mapped, and you get an effect of zoom out. Lesser angles, less openGL regions will be mapped, and you get an effect of zoom in
I'm trying to load 3D models from .obj format and it draws the object on the scren without any problem but when I resize the screen everything disappear. Here's the code:
Obj* object = new Obj();
GLuint texture[1];
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(double)w / (double)h,1.0,200.0);
}
void initRendering() {
object->GetObj("cube.obj");
glShadeModel(GL_LINEAR);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glEnable(GL_DEPTH_TEST);
}
void handleKeypress(unsigned char key, int x, int y) {
switch (key) {
case 27:
{
exit(0);
break;
}
}
}
void drawScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glRotatef(45.0,0.0,1.0,0.0);
object->DrawObj();
glPopMatrix();
glutSwapBuffers();
glFlush();
}
int _tmain(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(400, 400);
glutCreateWindow("3D");
initRendering();
glutReshapeFunc(handleResize);
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutMainLoop();
return 0;
}
And here's the code for Obj.DrawObj():
glBegin(GL_TRIANGLES);
for(int i = 0;i < faces.capacity()-1;i++)
{
glVertex3f(vertices[faces[i].vertex1].cordinate1,vertices[faces[i].vertex1].cordinate2,vertices[faces[i].vertex1].cordinate3);
glVertex3f(vertices[faces[i].vertex2].cordinate1,vertices[faces[i].vertex2].cordinate2,vertices[faces[i].vertex2].cordinate3);
glVertex3f(vertices[faces[i].vertex3].cordinate1,vertices[faces[i].vertex3].cordinate2,vertices[faces[i].vertex3].cordinate3);
}
glEnd;
In your drawing code you set the projection matrix, which is good. However you set it to identity. In the resize handler you're setting the projection matrix as well, but you shouldn't do it there; yes I know the tutorials have it all there, but this is very bad style. You should move all the code currently in the reshape handler into the drawing handler, replacing the current setting of the projection matrix.
I can see that you're still confused by reading your PasteBin. Let me try to explain:
The reason why you can see your object the first time you draw it is because you have not set a projection matrix. So your object is drawn directly in normalized device coordinates (-1 to 1 range).
When you resize, you're setting the projection matrix for the first time, and this changes what viewing region is drawn to your screen. Your object as it is initially drawn is outside of the viewing region defined by your projection matrix (it is on top of the camera and I guess in front of the near plane. You have to move the object back away from the camera so that it is inside the view frustum. This is what datenwolf was suggesting.
However at the same time you introduced other errors into your code, particularly that you stopped resetting the projection matrix in handleResize. You have to always clear the projection matrix before you call gluPerspective, or else you will get a bogus result.
If you take the exact code from your pastebin, and add a glLoadIdentity to handleResize, I think that should work then:
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //<--- add
glLoadIdentity(); //<--- add
gluPerspective(45.0,(double)w / (double)h,1.0,200.0);
}
Also, you're still clearing the projection matrix during the drawScene function. When you clear the matrix, you're throwing away the perspective setting that you just set in handleResize, you don't want to do that.
So basically:
Set the Projection matrix in handleResize and on initialization
Don't touch the projection matrix in drawScene
Translate the object so that it fits into the viewing frustum.
I have written a simple openGL program in C++. This program draws a sphere in 3D perspective projection and tries to draw a line joining the center of the sphere to the current cursor position in 2D orthographic projection. Now for drawing the line I can't figure out the coordinate of center of the sphere.
This is my code :
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
void passive(int,int);
void reshape(int,int);
void init(void);
void display(void);
void camera(void);
int cursorX,cursorY,width,height;
int main (int argc,char **argv) {
glutInit (&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
glutInitWindowSize(1364,689);
glutInitWindowPosition(0,0);
glutCreateWindow("Sample");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutPassiveMotionFunc(passive);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display() {
glClearColor (0.0,0.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render 3D content
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,(GLfloat)width/(GLfloat)height,1.0,100.0); // create 3D perspective projection matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
camera();
glTranslatef(-6,-2,0);
glColor3f(1,0,0);
glutSolidSphere(5,50,50);
glPopMatrix();
// Render 2D content
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width,height, 0); // create 2D orthographic projection matrix
glMatrixMode(GL_MODELVIEW);
glColor3f(1,1,1);
glBegin(GL_LINES);
glVertex2f( centreX,centreY ); // coordinate of center of the sphere in orthographic projection
glVertex2f( cursorX,cursorY );
glEnd();
glutSwapBuffers();
}
void camera(void) {
glRotatef(0.0,1.0,0.0,0.0);
glRotatef(0.0,0.0,1.0,0.0);
glTranslated(0,0,-20);
}
void init(void) {
glEnable (GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_COLOR_MATERIAL);
}
void reshape(int w, int h) {
width=w; height=h;
}
void passive(int x1,int y1) {
cursorX=x1; cursorY=y1;
}
I can,t figure out the values for centreX and centreY. Anyway I can get the correct values to draw the line?
You may be interested in using something like gluProject to go from your object coordinates to the actual (projected) position on screen. Once you have the screen coordinates of the object, it's easy to draw a line from one point to another.
In this case, you'll want to project the centre point of the sphere. For more complex objects I've found that it makes sense to project all of the corners of the object's bounding box and then take the extents of the screenspace position of those corners.
You should get the modelview, viewport and projection matrices before you switch to your orthographic projection (2D mode).
Obviously, in order to go from a screen position (say, where you clicked in the window) to a world position, you'll want to use its companion function, gluUnProject.
Note that the coordinates that come out of gluProject do not necessarily correspond directly to the window position; you might have to flip the "Y" coordinate.
Take a look at this GDSE discussion for some other ideas about how to solve the problem.