Anybody knows how to keep a triangle without deformations and always at the middle of the windows whatever is his size?
I know I have to do one callback with reshape function and then define it, but I'm not sure what is going inside resize function:
void resize(int width, int height) {
viewport(0,0,width,height);
...?
}
I have this main help. glutInitWindowSize(600, 600);
Since the GL calls use normalised vertex coordinates ranging from -1 to +1, it is possible to keep any object in the center of the screen by using the right coordinates independent of the screen pixel sizes.
However, the same independency also brings in the behaviour that, depending on the screen aspect ratio (or window aspect ratio, as the case may be) the object will also change, unless explicitly accounted for. See the discussions in How can i convert an oval to circle openGL ES2.0 Android
Here's a important hint: Don't use the resize callback to do anything with OpenGL.
I know I have to do one callback with reshape function and then define it, but I'm not sure what is going inside resize function:
Then you knew wrong.
It leads to a lot of confusion. OpenGL is a state based drawing API and like all state machines it should be reset into a well known state before you use it. That includes projection and viewport. With that in mind your problem becomes trivial
void display()
{
/* draw some stuff */
glViewport(...);
setup_projection();
setup_modelview();
draw_stuff();
/* draw some other stuff with different projection and modelview */
glViewport(...);
setup_other_projection();
setup_other_modelview();
draw_other_stuff();
/* ... */
swapBuffers();
}
If you're using GLUT you can use glutGet(GLUT_WINDOW_WIDTH) and glutGet(GLUT_WINDOW_HEIGHT) to retrieve the window's size for the viewport calls.
So in your case you'd use a glViewport that covers your whole window and a projection that always maps a certain view space into that viewport. For example
void display()
{
int const win_width = glutGet(GLUT_WINDOW_WIDTH);
int const win_height = glutGet(GLUT_WINDOW_HEIGHT);
float const win_aspect = (float)win_width / (float) win_height;
glViewport(0, 0, win_width, win_height);
/* Using fixed function pipeline for brevity */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* map the vertical range -1…1 to the window height and
a symmetric range -aspect … 0 … +aspect to the viewport */
glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
draw_triangle();
/* ... */
glutSwapBuffers();
}
Related
I am new to openGL and wondering how to redimension a window in opengl without resizing objects in it (for example a quad drawn in opengl). I currently have a simple C++ function such as :
void ProjectionOrtho::redimensionWindow(int width, int height)
{
glViewport(0, 0, width, height);
}
Here is a simple image to illustrate the problem:
Note : I have tried glViewPort(0,0, 665, 365) which are the initial height and weight of myBlueQuad, but that is not what i want since i want to be able to see the rest of the 3d universe to the right (for instance if i translate the quad to the right, i want to be able to see it)
Based on this thread: the difference between glOrtho and glViewPort in openGL I am pretty sure I need to use glOrtho but not sure how.. ive tried the following as #tkausl suggested:
glViewport(0, 0, width, height);
glOrtho(0, width, height, 0, -1.0, 1.0); //width and height of window panel
But unfortunately, i get the same result as before. It seems that glOrtho is never applied, i've also tried calling glLoadIdentity() before my glOrtho call, it has no effect on the end result.
The below code works perfectly fine with no fatal error but, when i use arguments "w","h" in "gluortho2d" as gluortho2d(0,w,h,0) in reshape function I get text on screen whereas if I put these arguments "0,0" as gluortho2d(0,0,0,0) I get shape of box.
How can I get both of them(box and text) simultaneously on screen?
#include"glut.h"
void drawBitmapText(char *string, float x, float y, float z);
void reshape(int w, int h);
void display(void);
void drawBitmapText(char *string, float x, float y, float z)
{
char *c;
glRasterPos3f(x, y, z);//define position on the screen where to draw text.
for (c = string; *c != '\0'; c++)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
}
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void)
{
glBegin(GL_POLYGON);//1
glVertex2f(-0.2, 0.6 - 0.3);
glVertex2f(-0.1, 0.6 - 0.3);
glVertex2f(-0.1, 0.5 - 0.3);
glVertex2f(-0.2, 0.5 - 0.3);
glEnd();
glColor3f(0, 1, 0);
drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Usama OGL Window");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
By not following bad tutorials and placing calls to glViewport and projection matrix setup at the only place valid: The display function. Setting the viewport and projection matrix in the reshape handler is an anti-pattern. Don't do it.
Do this
void display(void)
{
int const w = glutGet(GLUT_WINDOW_WIDTH);
int const h = glutGet(GLUT_WINDOW_HEIGHT);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(-1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_POLYGON);//1
glVertex2f(-0.2, 0.6 - 0.3);
glVertex2f(-0.1, 0.6 - 0.3);
glVertex2f(-0.1, 0.5 - 0.3);
glVertex2f(-0.2, 0.5 - 0.3);
glEnd();
/* viewport doesn't change in this
* application, but it's perfectly
* valid to set a different
* glViewport(...) here */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0, 1, 0);
drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);
glutSwapBuffers();
}
Update (due to request in coments):
Why is it wrong to set the viewport and projection parameters in the reshape handler? Well, you just experienced the reason yourself: They are not "one size fits all" state and throughout rendering slightly more complex frames that go beyond just a mesh drawn, you're going to want to mix and match different viewports and projections throughout rendering. Here's a (incomplete) list of things that require to have different viewports and projections while rendering a single frame:
render-to-texture (FBO) – needs viewport withing the bounds of the texture, and usually also a different projection (important for shadow mapping, dynamic cubemaps and lots of other advanced, multipass rendering techniques)
minimaps / overview frames or similar in the corner (viewport covering just the corner)
text annotation overlays (different projection; usually a plain identity transform so to draw text rectangles directly in NDC space)
"magnifying glass" overlay
Since changing viewport and projection state happens multiple times in only slightly more complex OpenGL drawing, it makes
a) zero sense to set it in the reshape handler: whatever the handler sets will be set only at the beginning of the drawing of the first frame and thereafter the frame drawing code itself would have to reset to what the reshape handler sets. So why even bother doing it in the reshape handler at all?
b) placing viewport and projection setup code in the reshape handler a burden in the long run, because it might cause other parts of the program getting dependent on that. And if that happens, once you realize your mistake and try to move that viewport and projection setup code to where it belongs other parts of the program that relied on it being called from the reshape handler break and you have to fix those, too.
All in all, there are no reasons to place any drawing related calls (and glViewport and projection setup definitely are drawing related) in the reshape handler. Of course "one time" initialization is perfectly fine there, i.e. if you want to adjust the size of FBO render targets to match the window, or if you want to prepare an overlay image that later on gets applied repeatedly.
You can make this much simpler. For what you're doing, there's no need to bother with setting transformations at all.
It looks like, for the box, you're trying to use coordinates in the range [-1.0, 1.0] for both coordinate directions. This corresponds to the OpenGL NDC (Normalized Device Coordinates) coordinate system, which is the coordinate space vertices are in after both the modelview and projection transformations are applied. If you keep these at their default identity matrix, you can specify coordinates directly in NDC space. In other words, to use coordinates in the range [-1.0, 1.0], do... nothing at all, and just keep everything at its default.
The reason the box rendering works for you when you call:
gluOrtho2D(0.0, 0.0, 0.0, 0.0);
is that this call will result in an error, as documented on the man page:
GL_INVALID_VALUE is generated if left = right, or bottom = top, or near = far.
and will therefore keep the defaults untouched, which is exactly what you need.
Now, for the text, it looks like you want to specify the position in units of pixels. The problem you're having is that glRasterPos*() runs the specified coordinates through the transformation pipeline, meaning that, with the default identity modelview and projection transformations, it expects the input coordinates to be in the range [-1.0, 1.0] just like the coordinates you pass to glVertex2f().
Fortunately, there's a very easy way to avoid that. There's a very similar glWindowPos*() call, with the only difference that the coordinates passed to it are in window coordinates, which are in units of pixels.
So in summary:
Remove all glMatrixMode() calls.
Remove all glLoadIdentity() calls.
Remove all gluOrtho2D() calls.
In drawBitmapText(), replace the glRasterPos3f() call by:
glWindowPos2f(x, y);
The only thing to watch out for is that the origin of window coordinates is in the bottom left corner. So if your text position is given relative to the top left corner, you'll need something like:
glWindowPos2f(x, windowHeight - y);
To address some misleading information in another answer: It's perfectly fine to call glViewport() in the reshape() function, as long as you use the same viewport for all your rendering. In more complex applications, you will often need different viewports for different parts of the rendering (e.g. when you render to FBOs, or to only part of the window), so you will need to call glViewport() at the proper places during rendering. But for a simple example, where you do all your rendering to the entire window, there's nothing wrong with calling it in reshape().
here is my code:
void drawClock(void)
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
for(int i=0; i<12; i++){
glRotatef(30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
}
glFlush();
}
Here is my reshape function (without it I don't see anything, although I'm not sure how it really works)
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0) h = 1;
float ratio = 1.0* w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,70.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
}
So I am trying to draw the hour marks of a clock using wire cubes of size 2.0, and each of these cubes must be 5.2 units away from the center. This is for an assignment, I know it is probably very simple but I just can't manage to make it work properly. My problem is that the cubes appear in 3D, but I want them to appear in 2D, as in I would only see one face. Also, the circle is not centered, I do not understand why. I know I am supposed to use pushMatrix and popMatrix but no matter how I use it it doesn't work.
3d Problem
gluPerspective makes a perspective projection. To accomplish what you need you should apply an orthographic projection instead.
The best way to do this with your current code is to us glOrtho to provide a left, right, bottom, top, far,near box within which everything will 'appear' 2D. Try the code below in place of gluPerspective.
glOrtho(10.0f,-10.0f,10.0f,-10.0f,10.0f,-10.0f,10.0f);
Position problem
I'm not so sure about the transformation as I've not used immediate mode for a while. Note the order of operations makes a difference.
As for the push/pop of matrices, it is basically a stack of 4x4 matrices detailing the transformations. I'm sure it works along the lines of
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate(x,y,z);// Where x,y,z is the starting point of your clock
for(int i=0; i<12; i++){
glPushMatrix();
glRotatef(i * 30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
glPopMatrix();
}
I've been studying Computer Graphics and I'm very confused about the role of the viewport, gluortho and when to use GL_MatrixMode and GL_Projection.
Here is a sample code I wrote that confuses me.
void init()
{
glClearColor(1.0,1.0,1.0,1.0);//Background Color of Viewport
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-200,200,-200,200,-50,50);
glMatrixMode(GL_MODELVIEW);
}
void wheel()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0.2,0.2);
glLoadIdentity();
glViewport(0,0,200,200);
glutSolidCube(100);
glFlush();
}
void main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitWindowSize(400,400);
glutInitWindowPosition(400,400);//Position from the top left corner
glutCreateWindow("Car");
init();
glutDisplayFunc(wheel);//Shape to draw
glutMainLoop();
}
When I change the Cube's size to 200 it disappears, why? Is that because it's larger than the z clipping?
When I remove glMatrixMode(GL_MODELVIEW) the cube disappears why?
If I don't flush at the end of the display function the cube disappears as well,why?
When I make the viewport smaller the object get smaller does that mean the object coordinates are relative to the viewport and not the world coordinates?
When you change the cubes size to 200, its faces extend beyond the near and far clipping planes, which you've set in your glOrtho call to -50 and 50. Technically you'd then be viewing the inside of the cube, but the far side of the cube is also outside of the far clipping plane, so you can't see its backface.
Removing the call to set the matrix mode to GL_MODELVIEW means your glLoadIdentity call operates on the fixed functionality projection matrix (I'm pretty sure), and so the cube is directly translated into Normalized Device Coordinates, and it once again extends beyond all the clipping planes.
Finally, glViewport defines the size of the buffer you should be rendering to, and therefore usually matches your screen size. Making it smaller effectively makes your screen size smaller, but does not change the actual GLUT window size. In mathematical terms, it changes the way fragments are projected from normalized device coordinates into screen coordinates.
Assuming I use Orhographic Projection, and have a reshape function like this:
void reshape(f32 width, f32 height){
aspect = width/height;
glViewport(0, 0, width, height);
// guaranted 960x640 HUD canvas
if(640*aspect>=960){
ortho.x = 640*aspect;
ortho.y = 640;
}else{
ortho.x = 960;
ortho.y = 960/aspect;
}
glOrtho(0, ortho.x, ortho.y, 0, -1.0f, 1.0f);
}
How can I make sure, that all vertices >ortho.x or >ortho.y (normally offscreen) are didn't drawn?
Because if I scale the windows to something with a bigger aspect ratio than 1.5f (960/640) I see the objects, that schouldn't be full visible (because the viewport is so big like the window).
Is there something like a clipping pane in orthographic projection?
What you want is to use [glScissor][1] to ensure that the rendered area never goes beyond a certain size. glScissor takes a rectangle in window coordinates (remember: window coordinates have the origin at the bottom-left). The scissor test prevents the generation of fragments outside of this area.
To activate the scissor test, you must use glEnable(GL_SCISSOR). Unless you do that, the above call won't actually do anything.
Use constant values for the limit parameters of glOrtho, but use glViewport and glScissor (enable with glEnable(GL_SCISSOR_TEST)) to limit rendering to a sub-portion of your window.
BTW: You should set the projection and viewport in the rendering function. Doing it in the reshape handler makes not much sense. In any serious OpenGL application you'll switch projection modes several times during a full render, so just do it that way from the very beginning.