I try to draw a simple square by OpenGL but the result its display a rectangle. I guess that the problem is in the reshape function but I have no idea why (I'm new to OpenGL).
I what to keep aspect when I resize the window, that is not to stretch or shrink my image.
image screenshot
my reshape function
#define WINDOW_W 640
#define WINDOW_H 480
void reshape(int width, int height) {
if (height == 0)
height = 1;
GLfloat aspect = (GLfloat)width / (GLfloat)height;
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width >= height)
gluOrtho2D(0.0f, (GLdouble)WINDOW_W * aspect, (GLdouble)WINDOW_H, 0.0f);
else
gluOrtho2D(0.0f, (GLdouble)WINDOW_W, (GLdouble)WINDOW_H / aspect, 0.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
my draw function
void display(void) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
// x=50 y=50 w=100 h=100 a square
glBegin(GL_QUADS);
glVertex2i(50, 50);
glVertex2i(50, 150);
glVertex2i(150, 150);
glVertex2i(150, 50);
glEnd();
glutSwapBuffers();
}
Right now, your "square" will always be exactly 1.3333 (640 / 480) times as tall as it is wide, because while you do take the actual window size into account and compute the actual aspect ratio given the actual window size, you multiply that with 640 for the width and 480 for the height, for whatever reason.
And that won't work since that will always stretch your actual aspect ratio by a factor of 1.3333 making your square always 1.3333 as tall as it is wide.
To solve this, just multiply the arguments to the gluOrtho2D() call with the same value, depending on what the extent in your world space or "view space" should be for a square view space with a square aspect ratio.
Related
In previous projects, I enabled depth testing used gluPerspective called once on startup to set up a 3D space. Currently, I am rendering a square between -0.5 and 0.5 with 0.0 as its origin after the 3D world has initialised with code below will cause a square to cover the entire screen:
glBegin(GL_QUADS);
{
glVertex3f(-0.5, -0.5, 0);
glVertex3f(-0.5, 0.5, 0);
glVertex3f(0.5, 0.5, 0);
glVertex3f(0.5, -0.5, 0);
}
glEnd();
What I am looking is a way to set the perspective so that shapes are rendered in world space. For example, the snippet below should cause a square of 200x200 to be rendered:
glBegin(GL_QUADS);
{
glVertex3f(-100, -100, 0);
glVertex3f(-100, 100, 0);
glVertex3f(100, 100, 0);
glVertex3f(100, -100, 0);
}
glEnd();
The code below is what I am currently using to initialise a 3D world.
// WINDOW_WIDTH = 1600, WINDOW_HEIGHT = 900
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(47, WINDOW_WIDTH / WINDOW_HEIGHT, 0.01, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
Have I missed any steps in setting up a 3D space and if gluPerspective is used to do this any suggestions why it is not working?
I am able to achieve this in 2D using ortho, it is important that the world is 3D.
Everything is being written in C using OpenGL and GLU up to 1.3 with my GLFW set up identical to this. Due to technical restraints, I am unable to use the modern pipeline.
First of all, the result of WINDOW_WIDTH / WINDOW_HEIGHT is 1, because WINDOW_WIDTH and WINDOW_HEIGHT are integral values. You have to perform a floating point division ((float)WINDOW_WIDTH / WINDOW_HEIGHT) to compute the correct aspect ratio.
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The projected size of an object on the viewport depends on its distance to the camera. The different size at different distances (depths) causes the perspective effect. The perspective projection matrix defines a Viewing frustum
The ratio of projected size and the distance to the camera depends on the field of view angle:
maxDim / cameraZ = tan(FOV / 2) * 2
So there is exactly 1 distance where an object with a length of 200 covers 200 pixel. For instance, If you have a filed of view angle of 90° then an object with a z distance of half the window height (height /2) and a vertical size of 200 covers 200 pixel (vertical) because tan(90° / 2) * 2 = 2.
When you use gluPerspective, then you define the field of view angle along the y axis. The field of view along the x axis depends on the aspect ratio. If the aspect ratio is set correctly, then the projection of a square which is parallel to the xy plane of the view is still a square.
Note, if you would use orthographic projection, then the size of the object is independent on the distance.
If I wanted to draw a plane in OpenGL, I would do something like the below:
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();
This draws a white plane that covers 50% of the canvas (from -0.5 to 0.5 on two axes). I want to use numbers instead, however. I don't want to use -1 to 1, but instead something like 0 to n, where n is the dimension of my canvas. For the above example, something like 250 to 750 on two axes on a 1000 pixel canvas rather than -0.5 to 0.5.
That's what the transformation matrices are for. In your case you'd set a ortho projection matrix with the limits as you desire. In your example case
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1000, 0, 1000, -1, 1);
would set up a viewing volume so that the boundaries are at 0,0 for the lower left corner and 1000,1000 for the upper right.
Note that this (and the code you've given) use the old, deprecated fixed function pipeline. You should drop that in favour of a shader based approach.
I currently have a cylinder
glPushMatrix();
glTranslatef(cylinder->pos[0], cylinder->pos[1], cylinder->pos[2]);
glRotatef(cylinder->angle, -1.0, 0, 0);
gluDisk(quad, 0.0, cylinder->radius, 300, 90);
gluCylinder(quad, cylinder->radius, cylinder->radius, cylinder->height, 30, 1);
gluDeleteQuadric(quad);
glPopMatrix();
but it only renders half of a cylinder instead of the whole thing (the half coming towards the view). Second issue is I don't know how to close the cylinder. The gludisk only closes the bottom of the cylinder and I'm not sure how to close the top side.
If I understand what you're describing, it sounds like you might have back face culling enabled. Do you have a glEnable(GL_CULL_FACE) call in your code? This will eliminate all polygons that face away from you. In any case, once you draw a cylinder that is closed at both sides, it will be fine to keep it enabled.
You can close the cylinder at the top with another gluDisk() call, after applying a translation that moves it to (0, 0, height). For correctness, I believe you need to rotate the disk that closes the cylinder at the bottom. Otherwise it will face to the inside of the cylinder instead of to the outside, which affects the normals, and would get it eliminated by back face culling when it should be visible.
For the full thing, it should look something like this (untested):
glPushMatrix();
glTranslatef(cylinder->pos[0], cylinder->pos[1], cylinder->pos[2]);
glRotatef(cylinder->angle, -1.0f, 0.0f, 0.0f);
gluCylinder(quad, cylinder->radius, cylinder->radius, cylinder->height, 30, 1);
glPushMatrix();
glTranslatef(0.0f, 0.0f, cylinder->height);
gluDisk(quad, 0.0f, cylinder->radius, 30, 1);
glPopMatrix();
glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
gluDisk(quad, 0.0f, cylinder->radius, 30, 1);
gluDeleteQuadric(quad);
glPopMatrix();
I am trying to find the screen coordinates from the opengl coordinates(projected in 3D space) I have used glproject call for this purpose,i have used rotation and translation to in my code
At certain point after performing some transformation, i called glproject api to get the screen coordinate of a particular projected point P(x,y,z)
glproject(x,y,z,modelMatrix,projectionmatrix,viewport,*x_s,*y_s,*z_s);
I am able to get x screen coordinate correctly in x_s , but y coordinates are different
The only change in y which is not in x is when initially i called the glperspective to set fovy(The field of view angle, in degrees, in the y-direction). gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
Let me Rephrase the question I have created a 3D point on screen and now i am getting the 2d(x,y) coordinates of that point through GLproject they come different from the mouse coordinates What could be the possible solution to get correct coordinates.
Here is the code snippet
#include<GL/glut.h> /* Header File For The GLUT Library */
GLint Window; /* The number of our GLUT window */
float tmp_x,tmp_y,tmp_z;
GLfloat w = 1200; /* Window size. Global for use in rotation routine */
GLfloat h = 1200;
GLint prevx, prevy; /* Remember previous x and y positions */
GLfloat xt=1.0,yt=1.0,zt=1.0; /* translate */
int width = 1600;
int height = 1200;
//This function will set windowing transformation
void transform(GLfloat Width , GLfloat Height )
{
glViewport(0,0, (GLfloat)Width, (GLfloat)Height);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
glTranslatef(0.0, 0.0, -15.0f); /* Centre and away the viewer */
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
GLvoid draw_room()
{
int i;
glPushMatrix();
glShadeModel(GL_SMOOTH);
glLineWidth(1.0);
glPointSize(4.0); /* Add point size, to make it clear */
glBegin(GL_POINTS); /* start drawing the cube.*/
glColor3f(0.0f,0.0f,1.0f); /* Set The Color To Orange*/
glColor3f(1.0f,0.0f,0.0f); /* Set The Color To Orange*/
glVertex3f(3.1f,2.1f,2.1f);
glEnd(); /* Done Drawing The Cube*/
glEnable(GL_DEPTH_TEST);
}
//OpenGl Display callback Function It call init room
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
printf("%f %f %f\n",xt,yt,zt);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(xt,yt, zt);
draw_room();
glPopMatrix();
glutSwapBuffers(); /* Swap buffers */
glFlush();
}
GLvoid Mouse( int b , int s, int xx, int yy)
{
double a1,a2,a3;
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
//gluProject(xt+3.1f,yt+2.1f,zt+2.1f, modelview, projection, viewport, &a1, &a2, &a3);
gluProject(3.1f,2.1f,2.1f, modelview, projection, viewport, &a1, &a2, &a3);
printf("Mouse: %d %d\n",xx,yy); // Both Print are giving different coordinaes.
printf("Unproject %f %f %f\n",a1,a2,a3);
switch (b) {
case GLUT_LEFT_BUTTON: /* only stash away for left mouse */
prevx = xx - w/2;
prevy = h/2 - yy;
break;
case GLUT_MIDDLE_BUTTON:
break;
case GLUT_RIGHT_BUTTON:
break;
}
}
What could be the possible solution for this?
OpenGL uses lower left corner of screen as coordinate system orign. Window system usually uses upper left corner as coordinate system orign. You need to handle this difference. Example:
printf("Mouse: %d %d\n",xx,yy);
printf("Unproject %f %f %f\n",a1,viewport[1]-a2,a3);
A side issue:
gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
You have a very large ratio between your near and far plane distance. This is very bad for depth resolution. As a general rule you should set the near clip plane distance as far as possible, as the scene allows. The far clip plane for a projection as created by gluPerspective should be set as near as possible (it's also possible to set the far clipping plane to infinity if the projection matrix is built slightly different).
Anyway, your low depth resolution will have a negative impact on your mouse pointer screen position back projection.
Let me Rephrase the question I have created a 3D point on screen and now i am getting the 2d(x,y) coordinates of that point through GLproject they come different from the mouse coordinates What could be the possible solution to get correct coordinates.
Most window systems put the pointer coordinate system origin to the upper left. OpenGL sets the viewport coordinate system origin into the lower left. So you'll have to invert the mouse position in the window along the Y=Up axis.
I have a single 640x480 texture that needs to fill the screen. So far, I can make it work with a square texture, but not a rectangular one.
glViewport(0, 0, display->w, display->h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspectRatio = (double)display->w / (double)display->h;
if (display->w <= display->h)
glOrtho(-1, 1, -1 / aspectRatio, 1 / aspectRatio, -1, 1);
else
glOrtho(-1 * aspectRatio, 1 * aspectRatio, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
What modifications do I need to make so that it will fit any texture to the screen, regardless of its aspect ratio?
This may have some relevance.
Tiling texture bmp file as texture onto a rectangle in OpenGL?
You may wish to consider ARB extension texture rectangle as an alternative approach to (assuming glTexImage2D?) http://glprogramming.com/red/chapter09.html