OpenGL coordinates question - opengl

I have a simple OpenGL drawing. When the user changes the window's size, I want the drawing to maintain it's aspect ration. I accomplished that by setting the glViewport to the maximum rectangle with the appropriate aspect ration whenever the reshape method is called.
My problem is that I want to draw a square that will always remain in the top right corner of the window, no matter what the size or shape of the window is. Right now, that square moves around the screen whenever the window is reshaped.
Can anyone please explain how to do this?
Thank you,

You need to move/size the square when the screen is re-sized. You can fix a square to the top left by using device coordinates but it won't necessarily be square of the aspect ratio changes. Therefore you need to resize the square to keep it square.

One way of doing this would be to create a new ortho matrix that maps to pixel coordinates (left = 0, bottom = 0, right = window-width, top = window-height) and set the gl-viewport to cover the entire window whenever the window changes. That way, you can draw a square by specifying pixel coordinates, if you make sure you have an identity model-view matrix set up.
It's not the only way, though. No matter what non-singular transformation you have, you should be able to come up with a way of hitting the correct pixels as long as the gl-viewport covers those, it's just easier this way.

If I understand correctly, you wish to draw a square at the top right corner of the window, regardless of where your scene viewport is positioned.
The easiest way to do this is to, after having rendered your normal scene with desired aspect, change the gl viewport to the square you want to draw in the top corner. Then draw a "full-screen" quad to fill the square, with full-screen in-fact becoming full-viewport in this case.
Untested semi-pseudo code would go something like this:
// Draw normal scene
glViewport(x, y, w, h);
drawScene();
// Draw top-right red square
glViewport( windowWidth - squareWidth, windowHeight - squareHeight,
squareWidth, squareHeight );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glColor3f(1.f, 0.f, 0.f);
glRectf(-1.f, -1.f, 1.f, 1.f);
Making sure that the winding of the glRectf matches your current gl cull face configuration. Alternatively, just temporarily disable culling by glDisable(GL_CULL_FACE) / glEnable(GL_CULL_FACE).

To draw a square in the top-right corner of the window, you need the viewport to cover this area. Having a viewport smaller than the window won't allow drawing in the corner.
You want your viewport to cover all the window (as done usually), and your square coordinates should be mapped to something like:
X0 = 1-2*s/width
X1 = 1
Y0 = 1-2*s/height
Y1 = 1
where s is the side of the square (pix), and width, height the dimensions of the window (pix).

Related

Any solutions for perspective view openGL qt

I have the following problem, when I zoom in on the image. I have not been able to solve it. I am currently developing in Qt with c ++. I have a question about orthogonal projection and perspective projection. I need to zoom without traversing the image. I tried to make the glViewport bigger, but it does not work for me. The xmin, xmax... are the maximum and minimum values ​​for each axis.
void MeshViewer::resizeGL(int width, int height)
{
int side = qMin(width, height);
if ( height == 0 )
height = 1;
glViewport(((GLint)(width - side)/2.0), (GLint)((height -side)/2.0), (GLint)side, (GLint)side);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(xmin, xmax, ymin, ymax, zmin, zmax);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
glViewport specifies the mapping of normalized device coordinates to window coordinates (pixels).
If you want that the entire geometry which is inside the clip space, is mapped to the window, then it has to be:
glViewport(0, 0, width, height)
What the window displays is a frustum, defined by six planes. Normally, these planes are parallel, as in a cube. Anything that lies outside the frustum is not displayed.
"Zoom" may be interpreted, in a generic way, as "see bigger, nearer, more detail".
There are several ways of achieve the zoom effect:
Scale the objects. This works, the flaw is that objects (or parts of them) may lie before the near plane or behind the far plane of the frustum.
Move the camera towards the object. Same matter with near/far planes. Also, take care of moving through the model, you can set a "barrier" (perhaps a box) to prevent the camera moving too deep.
For an orthogonal projection, set left/right/top/bottom planes nearer to the object. This makes the frustum smaller, thus it's normal that some objects get clipped.
For a perspective projection you can do the same trick as with orthogonal. This trick is just to reduce the FOV (field of view) angle. If objects are too far, the perspective effect may be less obvious.

GPU mouse picking OpenGL/WebGL

I understand i need to render only 1x1 or 3x3 pixel part of the screen where the mouse is, with object id's as colors and then get id from the color.
I have implemented ray-cast picking with spheres and i am guessing it has something to do with making camera look in direction of the mouse ray?
How do i render the correct few pixels?
Edit:
setting camera in direction of mouse ray works, but if i make the viewport smaller the picture scales but what (i think) i need is for it to be cropped rather than scaled. How would i achieve this?
The easiest solution is to use the scissor test. It allows you to render only pixels within a specified rectangular sub-region of your window.
For example, to limit your rendering to 3x3 pixels centered at pixel (x, y):
glScissor(x - 1, y - 1, 3, 3);
glEnable(GL_SCISSOR_TEST);
glDraw...(...);
glDisable(GL_SCISSOR_TEST);
Note that the origin of the coordinate system is at the bottom left of the window, while most window systems will give you mouse coordinates in a coordinate system that has its origin at the top left. If that's the case on your system, you will have to invert the y-coordinate by subtracting it from windowHeight - 1.

C++ OpenGL dragging multiple objects with mouse

just wondering how someone would go about dragging 4 different
objects in openGL. I have very simple code to draw these objects:
glPushMatrix();
glTranslatef(mouse_x, mouse_y, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x2, mouse_y2, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x3, mouse_y3, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x4, mouse_y4, 0);
glutSolidIcosahedron();
glPopMatrix();
I understand how to move an object, but I want to learn how to drag and drop any one of these objects.
I've been researching about the Name Stack and Selection Mode, but it just confused the hell out of me.
And I also know about having to have some sort of glutMouseFunc.
It's just the selection of each shape I'm puzzled on.
First thing that you need to do is capturing the position of mouse on the screen when the button is clicked. There are plenty of ways to do it but I believe it's outside of the scope of this question. When you have screen X,Y coords you must detect if any object is selected and which one it is. There are two possible approaches. You can either keep track of a bounding rectangle positions of each object (in screen space) and the test if the cursor is inside any of those rectangles will be quite simple. Or you can cast a ray from eye through cursor position in world space and check intersection of this ray with each object.
The second approach is more versatile for 3D graphics but you seem to be using only X and Y coords so you don't need to worry about Z order of objects.
In case of the first solution the main problem is: how to know how big is your object on the screen. glutSolidIcosahedron() renders an object of radius 1. To calculate it's screen radius you can either use some matrix math or in that case a simple trigonometry. You will need to know the distance from camera to the drawing plane (I believe you're using some glTranslatef(0,0,X) before you render. X is your distance) You also need to know the view angle of the camera. You set it in projection matrix. Now take a piece of paper, draw a cone of angle alpha, intersecting a plane at distance X and knowing that an object has radius 1 you can easily calculate how large area of the screen it occupies. (I'll leave this calculation for you)
Now if you know the radius on screen, simply test the distance from your click position to each object. if the distance is below radius it's selected. If more than one object passes this test just select first one of them.

Clicking on a Quad and getting screen coords in opengl

Say I make a quad like so:
float botBaseY = -0.5;
glBegin(GL_QUADS); // Box
glVertex2f(-.05, botBaseY + -.05);
glVertex2f(-.05, botBaseY + .05);
glVertex2f(.05, botBaseY + .05);
glVertex2f(.05, botBaseY + -.05);
glEnd();
OK, well now say I want to determine if the user clicked inside of that quad.
Well when you click, you receive screen coordinates, so if your main window is
600x600 pixels, then your click will yield an x and y value less than 600.
But I'm comparing a click at say (375,400) to a quad that was created using
values from -1.0 to 1.0 to define the 4 vertices.
How can I determine if the user clicked inside of the quad?
I currently see 2 ways to do this.
if your 'interface' is completely 2D and directly mapped into screen - you could just use screen coordinates for drawing. Just set correct orthographic matrix and your click coordinates will be the same as 2D elements coordinates - simple range comparison (x < click_x < x+width). See gluOrtho2D, glOrtho manuals (please note that glOrtho and other matrix functions are not available in newest GL profiles).
if first variant isn't fitting your situation - you need to map 2D coordinates to view space and use resulting point as ray direction. Then trace this ray's intersection with element's plane you want to click. Take a look at http://www.toymaker.info/Games/html/picking.html - doesn't matter that it's for d3d, math is always the same). Then, when you'll take resulting click point on a plane you've interested in - it's again just range comparison (although it will be a little trickier if your plane is not parallel to screen - but i don't think it still the same question).
I never ended up getting a useful answer on here, but I did end up figuring it out the next day. My box was being drawn using coordinates that were from -1 to 1. But my click had large screen coordinates such as 200,300. I needed to know how to convert the -1 to 1 into screen coordinates, or how to just draw it compatible coordinates.
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0, 400, 0, 400);
glBegin(GL_QUADS); // Box
glVertex2f(xOffset + topBaseX + -15, topBaseY + -15);// bottom left vert
glVertex2f(xOffset + topBaseX + -15, topBaseY + 15); // top left vert
glVertex2f(xOffset + topBaseX + 15, topBaseY + 15);// top right vert
glVertex2f(xOffset + topBaseX + 15, topBaseY + -15);// bottom right vert
glEnd();
glLoadIdentity();
That was all I had to do to draw my box at something like 200,300 and then I could simply check the boundaries of my box on each click.
Easiest and most accurate (but not necessarily most efficient) way:
Render the scene again (into an off-screen buffer) with the target object white and all else black. If the pixel under the cursor is white, the target was clicked. If you want to be able to click through some transparent materials, just skip rendering those objects.
For efficiency, you can do this with blending turned off and a unique color (perhaps an index) for each object. And use new OpenGL capabilities to fill the picker color plane during normal rendering instead of taking an additional pass.

How to design a plane to be in the center of the viewport at any window size

I need to draw a plane (with GL_QUADS) in OpenGL (c++, OS: windows) so that it is aligned to the center of the screen.
What I mean is that the origin will be in the center of the plane at any window resize.
I know I have to use the viewport coordinates and sizes, but I cannot configure how to use them.
Also, I am using gluPerspective.
The origin has nothing to do with your window size. When you resize the window, recalculate the aspect ratio of the window (window.width / window.height) and reset your projection matrix with another call to gluPerspective using the new aspect.
After this, as long as you glLoadIdentity() into the modelview matrix you should be able to draw a quad at the center of the screen using
glBegin(GL_QUADS);
glVertex3f(-.5f,.5f,-1);
glVertex3f(-.5f,-.5f,-1);
glVertex3f(.5f,-.5f,-1);
glVertex3f(.5f,.5f,-1);
glEnd();
That should place a unit sized quad at the center of the screen.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
glVertex3f(-.5f,.5f,-1);
glVertex3f(-.5f,-.5f,-1);
glVertex3f(.5f,-.5f,-1);
glVertex3f(.5f,.5f,-1);
glEnd();
glPopMatrix();
Note that this still uses all of your 3D rendering state, such as depth test, shading, etc.. Most likely you'll want to turn that off.