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.
Related
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.
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.
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'm in the middle of a project teaching the basics of OpenGL. I've got most of the requirements working fine in terms of camera rotation, translation etc. However I'm struggling a lot with the lighting.
This picture is a comparison of my current program (left) vs the sample solution (right).
In case you can't tell, I'm getting very monochrome colours on the truck. The shadows are very sharp and dark, the high points are singly coloured instead of specular.
The project calls for the use of textures; the one I've shown here is a basic texture of plain grey pixels but i could use any texture (including the beach sand one being used for the ground).
I'm drawing the object from a mesh:
GLfloat ambient[] = {0.1, 0.1, 0.1, 1};
GLfloat diffuse[] = {0.1, 0.1, 0.1, 1};
GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat shine = 100.0;
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, shine);
glEable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureNumber);
glBegin(GL_TRIANGLES);
for (int i = 0; i < meshes[n]->nTriangles; i++) {
for (int j = 0; j < 3; j++) {
glNormal3fv(mesh -> normals[mesh->triangles[i][j]]);
glTexCoord2fv(mesh->texCoords[mesh->triangles[i][j]]);
glVertex3fv(mesh -> vertices[mesh->triangles[i][j]]);
}
}
glEnd();
There is one light in the scene:
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST)
GLfloat diffuse0[]={1.0, 1.0, 1.0, 1.0};
GLfloat ambient0[]={1.0, 1.0, 1.0, 1.0};
GLfloat specular0[]={1.0, 1.0, 1.0, 1.0};
GLfloat light0_pos[]={1.0, 1.0, 1,0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 2.0);
Is there something major that I'm missing that could be causing this severe difference? Particular values I should play with? Or a glEnable call I've missed?
Any help, advice or pointers to elsewhere much appreciated.
To eliminate the sharp drop-off, amp up the ambient light. There's no global illumination model in OpenGL so that parameter has absolutely no effect beyond being the colour the face will be if no other light falls upon it.
Since you're using glVertex-type calls, I'll go out on a limb and guess you're using the fixed functionality pipeline? If so then lighting is calculated at vertices, then interpolated across polygon surfaces. That means that specular highlights don't work very well on 'large' polygons — roughly speaking, the highlight can't appear in the middle of a polygon. GPUs with programmable pipelines (which includes the ones in mobile phones nowadays) can calculate lighting per pixel instead of per vertex but OpenGL doesn't do this for you, so you'd need to delve into shader programming yourself. Or just ensure that your model is made up of small enough polygons.
Your shininess exponent is also quite high - have you tried dialling that down a few notches?
when looking at the background, it looks like a spotlight on the right just bathing the Scene into warm light, and a Flakscheinwerfer on the left basking everything in extreme lightning, eliminating every shadow
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