The problem I am having is that my objects become stretched when I use full screen. I want it to fit the full screen coordinates, so it looks exactly the same as Image A. I know that glViewport determines the portion of the window to which OpenGL is drawing to, and it can help set my objects to the entire window. However, I haven't used glViewport, instead I am used gluOrtho2D.
Click here to see the full code
Image A (screen size: 700, 600)
Image B (full screen size)
gluOrtho2D code
// this is the initialisation function, called once only
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // set what colour you want the background to be
glMatrixMode(GL_PROJECTION); // set the matrix mode
gluOrtho2D(0.0, winWidth, 0.0, winHeight); // set the projection window size in x and y.
}
I am originally using gluOrtho2D and it is used to set up a two-dimensional orthographic viewing region.
glViewport defines the region of the (default) framebuffer which is rendered to.
If you don't want to render to the full screen, thn you can shrink the area which is rendered to, by glViewport. You can let some black stripes on the borders.
The aspect ratio for your application is winWidth : winHeight
With glutGet, using the parameters GLUT_WINDOW_WIDTH respectively GLUT_WINDOW_HEIGHT the size of the current window can be get and the current aspect ratio can be calculated:
int currWidth = glutGet( GLUT_WINDOW_WIDTH );
int currHeight = glutGet( GLUT_WINDOW_HEIGHT );
float window_aspcet = (float)currWidth / (float)currHeight;
With this information the view can be perfectly centered to the viewport:
void display() {
float app_aspcet = (float)winWidth / (float)winHeight;
int currWidth = glutGet( GLUT_WINDOW_WIDTH );
int currHeight = glutGet( GLUT_WINDOW_HEIGHT );
float window_aspcet = (float)currWidth / (float)currHeight;
if ( window_aspcet > app_aspcet )
{
int width = (int)((float)currWidth * app_aspcet / window_aspcet + 0.5f);
glViewport((currWidth - width) / 2, 0, width, currHeight);
}
else
{
int height = (int)((float)currHeight * window_aspcet / app_aspcet + 0.5f);
glViewport(0, (currHeight - height) / 2, currWidth, height);
}
// [...]
}
Or you can adept the aspect ration and the center of the orthographic projection
void display() {
float app_aspcet = (float)winWidth / (float)winHeight;
int currWidth = glutGet( GLUT_WINDOW_WIDTH );
int currHeight = glutGet( GLUT_WINDOW_HEIGHT );
float window_aspcet = (float)currWidth / (float)currHeight;
glViewport(0, 0, currWidth, currHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if ( window_aspcet > app_aspcet )
{
float delta_width = (float)currWidth * (float)winHeight / (float)currHeight - (float)winWidth;
gluOrtho2D(-delta_width/2.0f, (float)winWidth + delta_width/2.0f, 0.0, (float)winHeight);
}
else
{
float delta_height = (float)currHeight * (float)winWidth / (float)currWidth - (float)winHeight;
gluOrtho2D(0.0, (float)winWidth, -delta_height/2.0f, (float)winHeight + delta_height/2.0f);
}
Related
I have a problem regarding the gluOrtho2D function. I want to resize the window size and calibrate its coordinates, but i have problems with the function. I think that the coordinates calculated
The problem is that if i click somewhere on the window, the point isn't on the cursor, but somewhere near it ( ~20 pixels). If i resize the window, i want the window points to be converted to the new window size, that's why the gluOrtho2D function had those parameters. Maybe i didn't figure it out the good way.
GLdouble mouseX = ( double )(2* widthValue * x / windowWidthSize) - widthSize ;
GLdouble mouseY = -( double )(2 * heightValue * y / windowHeightSize) + heightValue;
are good as i want them to take values from -30 to +30 (both x and y), but the
gluOrtho2D( -width / widthValue , width / widthValue , -height / heightValue , height / heightValue);
function doesn't convert them as i want. Any ideas to fix it?
#include<windows.h>
#include<GL/Glut.h> //includes the opengl, glu, and glut header files
#include<stdlib.h> //includes the standard library header file
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
vector<pair<GLdouble,GLdouble>>v;
GLdouble heightValue = 30.0; // the points X and Y coordinates would be [-30,30]
GLdouble widthValue = 30.0; // the points X and Y coordinates would be [-30,30]
void initGL()
{
glClearColor(1,1,1,0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0);
glBegin(GL_POINTS);
glColor3f(1.0f, 1.0f, 0.0f);
// prints the points
for(auto i : v)
glVertex2d(i.first, i.second);
glEnd();
glFlush();
}
void reshape(GLsizei width, GLsizei height) {
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset the projection matrix
// here is the problem with the coordinates. Any help??
gluOrtho2D(-width/ widthValue, width/ widthValue,-height / heightValue ,height / heightValue);
}
void mouseClick(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) // left button is pressed
{
double windowHeightSize = glutGet(GLUT_WINDOW_HEIGHT); // gets window's size
double windowWidthSize = glutGet(GLUT_WINDOW_WIDTH); // gets window's size
// converts the click coordinate on the screen to the coordinate on the window
GLdouble mouseX = (double)(60.0 * x / windowWidthSize) - 30.0;
GLdouble mouseY = -(double)(60.0 * y / windowHeightSize) + 30.0;
v.push_back(make_pair(mouseX,mouseY) ); // insert the point's coordinates in the vector
display();
}
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitWindowSize(800, 600);
glutInitWindowPosition(50, 50);//sets the position of the window in pixels from top left corner
glutCreateWindow("Program Find Convex Hull");
glutDisplayFunc(display);
glutReshapeFunc(reshape); // functia este apelata cand redimensionam fereastra
glutMouseFunc(mouseClick);
// initGL();
glutMainLoop();//loops the current event
return 0;
}
If the Orthographic projection is set by:
gluOrtho2D(-ortho_x, ortho_x, -ortho_y, ortho_y);
then the transformation of the moue position (window coordinates) to view coordinates is:
GLdouble mouseX = (double)(x/windowWidthSize * 2*ortho_x) - ortho_x;
GLdouble mouseY = ortho_y - (double)(y/windowHeightSize * 2*ortho_y);
Apply that to your example:
GLdouble ortho_x = 30.0;
GLdouble ortho_y = -30.0;
void reshape(GLsizei width, GLsizei height) {
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset the projection matrix
ortho_x = width / widthValue;
ortho_y = height / heightValue;
gluOrtho2D(-ortho_x, ortho_x, -ortho_y, ortho_y);
}
void mouseClick(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) // left button is pressed
{
double windowHeightSize = glutGet(GLUT_WINDOW_HEIGHT); // gets window's size
double windowWidthSize = glutGet(GLUT_WINDOW_WIDTH); // gets window's size
// converts the click coordinate on the screen to the coordinate on the window
GLdouble mouseX = (double)(x/windowWidthSize * 2*ortho_x) - ortho_x;
GLdouble mouseY = ortho_y - (double)(y/windowHeightSize * 2*ortho_y);
v.push_back(make_pair(mouseX,mouseY) ); // insert the point's coordinates in the vector
glutPostRedisplay();
}
}
Note, it is not necessary to change (ortho_x, ortho_y) in reshape. Since you mentioned in your question "i want them to take values from -30 to +30", it is even possible to keep (30.0, 30.0).
I have a square and I'm trying to make it stay a square when the window is resized, instead of stretching with the window. I have some code which I thought would work but when I resize the window the square shrinks and disappears. It doesn't come back when I return the window to it's original size. Can someone tell me what I've done wrong and how to fix it?
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
return;
}
void reshape(int w, int h) {
const float aspectRatio = ((float)w) / h;
float xSpan = 1;
float ySpan = 1;
if (aspectRatio > 1) {
xSpan *= aspectRatio;
}
else {
ySpan *= aspectRatio;
}
gluOrtho2D(-1*xSpan, xSpan, -1*ySpan, ySpan);
glViewport(0, 0, w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutCreateWindow("simple");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
}
The functions gluOrtho2D and glOrtho multiply the current matrix by the new orthographic projection matrix.
This causes that if the reshape is called a 2nd time, the matrix which was set by gluOrtho2D before, is multiplied by the new one and you get consecutive changes.
You have to "reset" the matrix (init the identiy matrix) on the matrix stack by glLoadIdentity. Further you should choose the projection matrix stack by glMatrixMode:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1*xSpan, xSpan, -1*ySpan, ySpan);
The setup of the viewport glViewport is correct and you also consider the aspect ratio correctly (in gluOrtho2D). But there is an issue if the aspect ratio is less than 1.0. It should be ySpan /= aspectRatio;
I recommend to do the setting of the viewport and the projection matrix in the display function and just to set a notification flag in the reshape function. Note, the viewport and the projection matrix should be changed as rare as possible.
bool vp_valid = true;
int width, height;
void reshape(int w, int h) {
vp_valid = false;
width = w;
height = h;
}
void display(void)
{
if (!vp_valid)
{
const float aspectRatio = (float)width / height;
float sx = aspectRatio > 1.0f ? aspectRatio : 1.0f;
float sy = aspectRatio > 1.0f ? 1.0f : 1.0f/aspectRatio;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-sx, sx, -sy, sy);
glViewport(0, 0, width, height);
}
.....
}
I am making a 3d project in OpenGL which contain a ground (drawn as line loops). The issue I have is when the project starts only a single line is drawn as shown in the next image:
When I resize or maximize the window then the actual ground gets displayed like this:
Any idea how to resolve this issue? I'm a beginner in OpenGL programming.
Here is the code :
void drawHook(void);
void timer(int);
void drawFlorr();
float L = 100;
const int screenWidth = 1000; // width of screen window in pixels
const int screenHeight = 1000; // height of screen window in pixels
float ww = 800;
float wh = 800;
float f = 520, n = 10.0;
static GLdouble ort1[] = { -200, 200, -33, 140 };
static GLdouble viewer[] = { 525, 25, -180 };
static GLdouble objec[] = { 525.0, 25, -350 };
float x, y = 0.0, z, z1;
float xmax = screenWidth - 200.0;
float zmax = screenWidth - 200.0;
float xmin, zmin;
float step = 5.0;
float fov = 80;
void myInit(void)
{
glClearColor(0.0,0.0,0.0,0.0); // background color is white
glPointSize(2.0); // a 'dot' is 2 by 2 pixels
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, screenWidth, 0.0, screenHeight);//dino window
glViewport(0, 0, screenWidth, screenHeight);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(viewer[0], viewer[1], viewer[2], objec[0], objec[1], objec[2], 0, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, 1.333, n, f);
glPointSize(2.0);
glMatrixMode(GL_MODELVIEW);
drawFlorr();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // set display mode
glutInitWindowSize(screenWidth, screenHeight); // set window size
glutInitWindowPosition(10, 10); // set window position on screen
glutCreateWindow("Dino Line Drawing"); // open the screen window
glutDisplayFunc(myDisplay); // register redraw function
myInit();
//glutTimerFunc(1,timer,1);
glutMainLoop(); // go into a perpetual loop
return 1;
}
void drawFlorr()
{
xmin = -100;
zmin = -100;
for (x = xmin; x < xmax; x += step)
{
for (z = zmin; z < zmax; z += step)
{
z1 = -z;
glBegin(GL_LINE_LOOP);
glVertex3f(x, y, z1);
glVertex3f(x, y, z1-step+1.0);
glVertex3f(x + step - 1.0, y, z1 - step + 1.0);
glVertex3f(x+step-1.0, y, z1);
glEnd();
}
}
}
Your code is broken in many ways:
Your myDisplay function uses whatever the current matrix mode is to set the view matrix on.
Initially, you leave the matrix mode as GL_PROJECTION in myInit()
These two together mean that for the first frame, you just use identity as MODELVIEW matrix, and just overwrite the projection matrix twice. After a resize, the frame ais drawn again, and your code does waht you probably intented to do.
However, there is more:
You do not have any resize handler, so your viewport will not change when you resize the window.
You are setting an ortho matrix initailly for the projection, although you are not planning to use it at all.
and, the most import point:
All of your code depends on deprecated functionality which is not even available in modern OpenGL at all. You should really not use this in 2016, but learn modern OpenGL instead (with "modern" meaning "only a decade old" here).
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.
I am using Qt + OpenGl for 2D rendering.
I am a beginner at OpenGL and for the life of me i am not able to figure out this aspect ratio issue. Everytime i think i have understood glOrtho and gViewPort, but very next time i am into another issue with them. While if coordinates are symmetric like between -1 and 1, my code works else it doesn't. I really want to get through these for once and all. All the suggestions i have searched and applied have gone fruitless for me.
My Problem Statement:
I am rendering a square and a triangle and i switch between them with keystroke "R". I am also zooming in and out. While square is maintaining aspect ratio, triangle is not. Coordinates for shapes are:
Square: (-10, -250), (500, -250), (500, -260), (-10, -260);
Triangle: (250, 0), (310, 0), (280, 30)
Basically I am not able to render above triangle. Here is code for same:
My Code
#include <QtGui/QMouseEvent>
#include <qdebug.h>
#include "GLWidget.h"
#include "stdio.h"
#include "qgl.h"
#include "qimage.h"
GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent)
{
setMouseTracking(true);
}
void GLWidget::initializeGL()
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glEnable(GL_POLYGON_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(1, 1, 1, 0);
glEnable( GL_POINT_SMOOTH ); // For Circular Points
}
void GLWidget::resizeGL(int w, int h)
{
canvas_width = (double)w;
canvas_height = (double)h;
aspect_ratio = canvas_width/canvas_height;
left_plane = 250;
right_plane = 310;
bottom_plane = 0;
top_plane = 60;
z_near_plane = 1;
z_far_plane = -1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if( canvas_width > canvas_height ){
glOrtho(left_plane*aspect_ratio, right_plane*aspect_ratio, bottom_plane, top_plane, z_near_plane, z_far_plane);
}else{
glOrtho(left_plane, right_plane, bottom_plane/aspect_ratio, top_plane/aspect_ratio, z_near_plane, z_far_plane);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0); // red
glBegin(GL_POLYGON);
//glVertex2f(-30,0);
//glVertex2f(30,0);
//glVertex2f(0,60);
glVertex2f(250,0);
glVertex2f(310,0);
glVertex2f(280,60);
glEnd();
}
I do not see any traingle because left_plane*aspect_ratio clips my drawing (250 is minimum X, 250*1.4 > 310, 310 is maximum X).
I hope i have made myself clear.
I will try to place images as well (i guess i will have to upload images to some other site and link them here?).
Your problem is that the bounding box (the values assigned to left/right/top/bottom_plane) doesn't have the same aspect ratio as the viewport. If you have the bounding box for the object, you need to find viewport coordinates with the correct aspect ratio (w/h). The viewport needs to be both centered on the bounding box center, and be big enough to fit the bounding box. But the aspect ratio of the viewport has nothing to do with the size of the bounding box.
In general you have a 3D bounding box (8 corner points). You would project each corner onto the screen, then use min/max to get a rectangle that needs to be centered on screen. You then check the aspect ratio ar = wr/hr of that rectangle against the aspect ratio of the viewport a=w/r. If a < ar, you need to fit wr to w, otherwise fit hr to h.
void GLWidget::resizeGL(int w, int h)
{
// First set up the projection.
double canvas_width = (double)w;
double canvas_height = (double)h;
double a = canvas_width / canvas_height;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-a, +a, -1, +1, -1, +1);
// Now set up the view matrix.
double leftBoundingRectangle = 250;
double rightBoundingRectangle = 310;
double bottomBoundingRectangle = 0;
double topBoundingRectangle = 60;
double widthBoundingRectangle = rightBoundingRectangle - leftBoundingRectangle;
double heightBoundingRectangle = topBoundingRectangle - bottomBoundingRectangle;
double ar = widthBoundingRectangle / heightBoundingRectangle;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Center on bounding rectangle center.
double tx = (leftBoundingRectangle + rightBoundingRectangle)/2.0, ty = (topBoundingRectangle + bottomBoundingRectangle)/2.0;
glTranslated(tx, ty, 0.0); // or is it -tx, -ty?
// Scale to fit bounding box.
double s;
if (ar > a)
{
s = ... // sorry, but you have to figure this one out for yourself. :)
}
else
{
s = ...
}
glScaled(s,s,s);
}