I wrote some code, expecting to see a square in the middle of the screen, instead the square appears higher up, in some aspect ratios near the top of the screen, and slightly to the left.
With another aspect ratio:
Here's the relevant part of my code:
void resize(uint32_t height, uint32_t width){
glViewport(0, 0, width, height);
glMatrixMode (GL_PROJECTION); //set the matrix to projection
glLoadIdentity();
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}
void draw(){
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
//set up camera
glLoadIdentity();
gluLookAt(0,10,0,0,0,0,0.001,0.999,0);
//draw a square in the center of the screen
glBegin(GL_TRIANGLE_FAN);
glColor4f(0,1,1,1);
glVertex3f(-1,0,-1);
glVertex3f(-1,0,1);
glVertex3f(1,0,1);
glVertex3f(1,0,-1);
glEnd();
glPopMatrix();
}
Isn't 0,0,0 supposed to be the middle of the screen? And isn't gluLookAt supposed to put whatever coordinate i specify in the center of the screen?
Change the value of up vector
gluLookAt(0,10,0,0,0,0,0,0,1);
your eyes is at positive y-axis and reference point at center and up (head) vector must be along z-axis.
You have done another mistake in your resize function
void resize(uint32_t height, uint32_t width){
glViewport(0, 0, width, height);
.....................
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}
your variable height stores width of screen and variable width stores height, you have defined the glViewport and in gluPerspective you think your are taking ratio width by height, but actually you are taking ratio height by width, so it occurs the problem. Edit you code as follows:
void resize(uint32_t width, uint32_t height){
glViewport(0, 0, width, height);
..................
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}
Related
I've created a program in OpenGL that draws some shapes. I want the user to be able to zoom in on the shapes if they want to. This is the code that draws the shapes:
/*Initialise the required OpenGL functions*/
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, screenWidth, screenHeight, 0.0, -1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_CULL_FACE);
glClear(GL_DEPTH_BUFFER_BIT);
/*Draw a square*/
glColor3f(1, 0, 0);
glBegin(GL_QUADS);
glVertex2f(screenWidth * 0.75, screenHeight * 0.08333);
glVertex2f(screenWidth * 0.75, screenHeight * 0.16666);
glVertex2f(screenWidth * 0.86666, screenHeight * 0.16666);
glVertex2f(screenWidth * 0.86666, screenHeight * 0.08333);
glEnd();
glColor3f(0, 0, 0);
/*Let the user zoom*/
if (GetAsyncKeyState(VK_UP))
{
/*"zoom" is a global variable*/
zoom += 0.005;
}
glScaled(1 + zoom, 1 + zoom, 1);
/*Everything that is drawn from this point on (A sphere and a cube) should be scaled*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-0.3, 0, 0);
glutSolidSphere(3, 20, 20);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.55, 0.36, 0);
glutSolidCube(0.05);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glutSwapBuffers();
The code draws the shapes properly, but the shapes can't be scaled. I've used similar code in some other functions, so I believe that it may be because I am using 3D shapes or it may have something to do with me calling "glMatrixMode" multiple times. Either way, how should I change my code so that the cube and sphere are scaled based on user input, but the first square is not affected?
glScaled() changes the current matrix. So as soon as you call glLoadIdentity() you are undoing your scaling. You are doing lots of unnecessary calls to glMatrixMode() and glLoadIdentity() that should be eliminated. So try something more like this:
// You probably don't really need to do these, but if you do, do it once up top.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix(); // Save the current matrix
glScaled(1 + zoom, 1 + zoom, 1); // Scale it
/*Everything that is drawn from this point on (A sphere and a cube) should be scaled*/
glTranslatef(-0.3, 0, 0);
glutSolidSphere(3, 20, 20);
glTranslatef(0.55, 0.36, 0);
glutSolidCube(0.05);
glPopMatrix(); // Undo the glScaled() call above
glutSwapBuffers();
So I'm trying to make a menu , and when I select an option I want it to draw the scene and to be able to pick from the scene in order to run the game. The game is checkers. I can do this without the 2D Menu, I perform the picking and the game is fine. But when I add the menu and try to switch between both, either I get no image (all black) or I set a perspective view and the Picking is no longer available in the same range.
to setup the 2D I make:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 600, 600, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
//draw 2D
to setup the 3D I use
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluPerspective(45.0, (GLdouble)600/(GLdouble)600, 1.0, 200.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//draw 3D
With this I'm no longer able to pick objects from the scene, but I can pass from 2D to 3D and watch the entire scene.
To perform the picking:
void PickInterface::performPicking(int x, int y) {
glSelectBuffer (BUFSIZE, selectBuf);
glRenderMode(GL_SELECT);
glInitNames();
glMatrixMode(GL_PROJECTION);
glPushMatrix ();
GLfloat projmat[16];
glGetFloatv(GL_PROJECTION_MATRIX,projmat);
glLoadIdentity();
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
gluPickMatrix ((GLdouble) x, (GLdouble) (CGFapplication::height - y), 5.0, 5.0, viewport);
glMultMatrixf(projmat);
((PickScene*)scene)->selectMode=true;
scene->display();
((PickScene*)scene)->selectMode=false;
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glFlush();
GLint hits;
hits = glRenderMode(GL_RENDER);
processHits(hits, selectBuf);
}
My origin is not at top left corner, when I resize my window. And the 2d coordinates are not in pixel coordinates:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rnd::initDraw();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, mainPanelx, mainPanely, 0.0, -1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
//glPushMatrix(); ----Not sure if I need this
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0);
glVertex2f(0.0, 0.0);
glVertex2f(10.0, 0.0);
glVertex2f(10.0, 10.0);
glVertex2f(0.0, 10.0);
glEnd();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glutSwapBuffers();
Resize function:
void resize(int width, int height)
{
if (height == 0) height = 1;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* note we divide our width by our height to get the aspect ratio */
gluPerspective(45.0, width / height, 1.0, 400.0);
glMatrixMode(GL_MODELVIEW);
mainPanelx = width;
mainPanely = height;
std::cout<<mainPanelx<<", "<<mainPanely<<"\n";
}
How do i get the origin constant at the top left corner of my window and how do i get the 2d coordinates in pixel coordinates?
You forgot to call glViewport in your resize function.
This means OpenGL will still render to the old sized viewport.
I need to scale the result of glDrawPixels image.
I'm drawing a 640x480 pixels image buffer with glDrawPixels in a Qt QGLWidget.
I tryed to do the following in PaintGL:
glScalef(windowWidth/640, windowHeight/480, 0);
glDrawPixels(640,480,GL_RGB,GL_UNSIGNED_BYTE,frame);
But it doesn't work.
I am setting the OpenGL viewport and glOrtho with the size of the widget as:
void WdtRGB::paintGL() {
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup the OpenGL viewpoint
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, -1.0, 1.0);
glDepthMask(0);
//glRasterPos2i(0, 0);
glScalef(windowWidth/640, windowHeight/480, 0);
glDrawPixels(640,480,GL_RGB,GL_UNSIGNED_BYTE,frame);
}
//where windowWidth and windowHeight corresponds to the widget size.
/the init functions are:
void WdtRGB::initializeGL() {
glClearColor ( 0.8, 0.8, 0.8, 0.0); // Background to a grey tone
/* initialize viewing values */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, -1.0, 1.0);
glEnable (GL_DEPTH_TEST);
}
void WdtRGB::resizeGL(int w, int h) {
float aspect=(float)w/(float)h;
windowWidth = w;
windowHeight = h;
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
if( w <= h )
glOrtho ( -5.0, 5.0, -5.0/aspect, 5.0/aspect, -5.0, 5.0);
else
glOrtho (-5.0*aspect, 5.0*aspect, -5.0, 5.0, -5.0, 5.0);
//printf("\nresize");
emit changeSize ( );
}
It sounds like what you actually need to do instead of calling glDrawPixels () is to load your image data into a texture and draw a textured quad the size of the window. So something like this:
glGenTextures (1, &texID);
glBindTextures (GL_TEXTURE_RECTANGLE_EXT, texID);
glTexImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, 640, 480, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, frame);
glBegin (GL_QUADS);
glTexCoord2f (0, 0);
glVertex2f (0, 0);
glTexCoord2f (640, 0);
glVertex2f (windowWidth, 0);
glTexCoord2f (640, 480);
glVertex2f (windowWidth, windowHeight);
glTexCoord2f (0, 480);
glVertex2f (0, windowHeight);
glEnd();
Or if that's too much work, glPixelZoom (windowWidth / 640, windowHeight / 480), might do the trick, too.
Just for further reference: Instead of doing the glScalef(windowWidth/640, windowHeight/480, 0); before the glDrawPixels you should do a pixel zoom:
glRasterPos2i(0,0);
GLint iViewport[4];
glGetIntegerv(GL_VIEWPORT, iViewport);
glPixelZoom(iViewport[2]/640, iViewport[3]/480);
glDrawPixels(640,480,GL_RGB,GL_UNSIGNED_BYTE,frame);
I need to scale the result of glDrawPixels image.
glDrawPixels directly goes to the framebuffer. So every incoming pixel is mapped 1:1 to the output. There is a function (ah, why am I telling you this) glPixelZoom, which allows you to zoom glDrawPixels.
BUT I urge you, not to use glDrawPixels!
Use textures quads instead. glDrawPixels is a depreciated function, no longer supported by modern OpenGL-3. And even when it was not deprecated it still is a very slow function. Textured quads are better in every regard.
I'm setting up so I can switch between either one or four viewports but I got some trouble.
In my bottom right viewport I got camera view, the same camera that I can switch to full view on. The other three viewports are working with fixed locations but the bottom right viewport is compressed on the y scale and half of the picture on the x scale is missing.
void display(int what)
{
if(what==5){glViewport(0, 0, w, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ca.lookAt();}
if(what==1){glViewport(0, 0, w/2, h/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(75,15,-5,0,5,-5,0,1,0);}
if(what==2){glViewport(w/2, h/2, w, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,110,0,20,0,20,1,0,0);}
if(what==3){glViewport(w/2, 0, w, h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(320) / float(240), 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ca.lookAt();}
if(what==4){glViewport(0, h/2, w/2, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(185,75,25,0,28,0,0,1,0);}
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
////gluLookAt(cos(shared.time) * shared.distance, 10, sin(shared.time) * shared.distance, 0, 0, 0, 0, 1, 0); // Roterar kameran kring origo genom att skapa en ny vymatris varje bildruta
////ca.orbitYaw(0.05);
//ca.lookAt();
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
drawScene();
drawCamera();
glutSwapBuffers();
}
void viewport(){
glEnable(GL_SCISSOR_TEST);
if(!divided_view_port)
{
glViewport(0, 0, w, h);
glScissor(0,0,640,480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 100.0f);
display(5);
}
else
{
////////////////////// bottom left - working
glViewport(0, 0, w/2, h/2);
glScissor(0,0,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(1);
//////////////////////
////////////////////// top right - working
glViewport(w/2, h/2, w, h);
glScissor(w/2,h/2,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(2);
//////////////////////
////////////////////// bottom right -working
glViewport(w/2, 0, w, h/2);
glScissor(w/2,0,w,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(3);
////////////////////////
////////////////////////// top left
glViewport(0, h/2, w/2, h);
glScissor(0,h/2,w/2,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(4);
///////////////////////////
}
glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_MODELVIEW);
}
glViewport() takes an offset and a size.
Your code seems to be passing lower-left and upper-right coordinates.
Try these:
glViewport( 0, 0, w/2, h/2); // lower-left
glViewport(w/2, 0, w/2, h/2); // lower-right
glViewport(w/2, h/2, w/2, h/2); // upper-right
glViewport( 0, h/2, w/2, h/2); // upper-left