OpenGL 1.1 scene coordinates to screen coordinates - opengl

I know OpenGL 1.x is more than only outdated but due to the required target hardware which lacks better OpenGL drivers, I'm bound to this kind of legacy code. Or in other words: people pay for support of this old crap and who pays is the boss...
My problem: Before sending my objects coordinates, I set some transformation with functions glLoadIdentity(), glTranslatef(), glScaled(), glRotatef() to change the view to my objects by translating/zooming/rotating.
These parameters can be changed by the user to get a different view to the scene (by dragging the mouse on the related window).
My problem: how can I convert between the scene-coordinates (based on the transformation done by the functions described above) and the draw-canvas coordinates (means position of the mouse on the window that displays the scene)?
Thanks!

Related

Generic picking solution for 3D scenes with vertex-shader-based geometry deformation applied

I'm trying to implement a navigation technique for 3D scenes (in OpenSceneGraph with OpenGL). Among other things the user should be able to click on an scene object on the screen to move towards it.
The navigation technique should be integrated into another project which uses a vertex shader to apply a global deformation to the scene geometry. And here is the problem: Since the geometry is deformed using a vertex shader, it is not straight forward to un-project the mouse cursor position to the world coordinates of the spot the user actually selected. But I need those coordinates to perform the proper camera movement in my navigation technique.
One way of performing this un-projection would be to modify the vertex shader (used for the deformation) to let it also store the vertex' original position and normal in separate textures. Afterwards one could read those textures at the mouse position to get the desired values.
Now, as I said, the vertex shader belongs to another project which I actually don't want to touch. One goal of my navigation technique is to be as generic as possible to be easily integrated into other projects as well.
So here is the question: Is there any feature in OpenSceneGraph or OpenGL that I did not consider so far? Anything that allows me to get the world coordinates of a fragment, independently of the vertex shader coder?
Well, you could always do an OpenGL selection operation:
http://www.glprogramming.com/red/chapter13.html
Alternately, you could rasterize to a very small (1px*1px) framebuffer where the user clicked, read back the z-buffer and unproject the Z value you got into world space.

How to drag the line segment by selecting the vertex

the line_loop is created by opengl. I need to pick a vertex of the line segment and then drag it to somewhere in the 2D screen.
My thought is to pick up the vertex of the line by using Opengl picking method, and then the buffer storing the hit records is also created from glSelectBuffer. The problem is that how I can know which vertex is selected from information of the returned buffer? The buffer stores the name of the vertex. But it seems the vertex does not has a name in GL_RENDER mode?
Update: Is there any other convenient way to drag lines by mouse?
OpenGL is not a scene graph (gah, it seems every other question on OpenGL I answer begins with this statement). After you've drawn something, OpenGL no longer has any recollection of what you actually sent it. The old OpenGL selection mode is technically just testing if the geometry submitted is within the projections clip space range. On most OpenGL implementations selection mode falls back into software rendering mode, so you'll get a major performance hit.
There are several better ways to do selection (that's why selection mode has been removed from OpenGL after all). If it's just single vertices in specific geometry (like a selection rubberband) you're after, then you should perform the whole transformation of those points into normalized device coordinates yourself, sort them into some screen space spatial subdivision structure (2d Kd tree, quadtree, etc.) so that you can determine the point clicked on in O(log n) time – in contrast to the O(n) you'd have with selection mode, in which you have to "draw" the whole rubberband, so that all points are tested.
EDIT/Update
Since OpenGL is (just) a drawing API you also can't "drag around" things. You'll have to redraw them. Technically you should redraw the whole scene, or when starting a drag, draw the scene without the object about to be dragged into a texture (color and maybe depth), and then for each dragging step clear the view to the cached contents in the texture and then add the dragged objects in its updated position.

How to enable depth testing for the GL_SELECT buffer?

I am using the GL selection buffer to implement mouse picking. Unfortunately, OpenGL is returning hits in the selection buffer even for objects that are entirely occluded. For example, if there is a man hidden behind a wall, the selection buffer will include a hit record for the man even though he is not visible.
Selection is implemented in roughly the way described in the OpenGL Programming Guide: switch to the GL_SELECT render mode -- glRenderMode(GL_SELECT) -- render the scene, and then parse the selection buffer. The depth buffer and depth testing are enabled, but GL seems to ignore depth settings in GL_SELECT mode.
Is it possible for OpenGL to do depth culling in GL_SELECT mode? Is there another way of discarding hit records for hidden objects without re-implementing selection using another method?
The selection buffer will give you all the objects that match your mouse position regardless of depth from the camera. It's up to you to determine whether you want the closest, furthest or all objects. Remember the mouse only works in a 2D world and is trying to do selection for a 3D space. Imagine a ray shooting out into the -z direction at the x,y coordinate that you clicked your mouse. All the objects that intersect that ray are returned in the selection buffer. Sounds like you want to choose the closest one.
See jerome's tutorial and nehe's tutorial on selection.
The processHits function from the OpenGL programming guide shows how to get the z values of the object at the hit location. Use the z-value to sort the objects and pick the closest ones.

Ways to implement manipulation handles in 3d view

I'm building a simple solid modeling application. Users need to be able to manipulate object in both orthogonal and perspective views. For example, when there's a box in the screen and the user clicks on it to select it, it needs to get 'handles' at the corners and in the center so that the user can move the mouse over such a handle and drag it to enlarge or move the box.
What strategies are there to do this, and which one is the best one? I can think of two obvious ones:
1) Treat the handles as 3d objects. I.e. for a box, add small boxes to the scene at the corners of the 'main' box. Problems: this won't work in perspective view, I'd need to determine the size of the boxes relative to the current zoom level (the handles need to have the same size no matter how far the user is zoomed in/out)
2) Add the handles after the scene has been rendered. Render to an offscreen buffer, determine the 2d locations of the corners somehow and use regular 2d drawing techniques to draw the handles. Problems: how will I do hittesting? I'd need to do a two-stage hittesting approach, as well; how do I draw in 2d on a 3d rendered image? Fall back to GDI?
There are probably more problems with both approaches. Is there an industry-standard way of tackling this problem?
I'm using OpenGL, if that makes a difference.
I would treat the handles as 3D objects. This provides many advantages - it's more consistant, they behave well, hit testing is easy, etc.
If you want the handles to be a constant size, you can still treat them as 3D objects, but you will have to scale their size as appropriate based off the distance to camera. This is a bit of a hassle, but since there are typically only a few handles, and these are usually small objects, it should be fine performance wise.
However, I'd actually say let the handles scale with the scene. As long as you pick a rendering style for the handle that makes them stand out (ie: bright orange boxes, etc), the perspective effects (smaller handles in the background) actually makes working with them easier for the end-user in many ways. It is difficult to get a sense of depth from a 3D scene - the perspective effects on the handles help provide more visual clues as to how "deep" the handle is into the screen.
First off, project the handle/corner co-ordinates onto the camera's plane (effectively converting them to 2D coordinates on the screen; normalize this against the screen dimensions.)
Here's some simple code to enable orthogonal/2D-overlay drawing:
void enable2D()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
int wind[4];
glGetIntegerv(GL_VIEWPORT,wind);
glOrtho(0,wind[2],0,wind[3],-1,1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}
void disable2D()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
enable2D() caches the current modelview/projection matrices and replaces the projection matrix with one normalized to the screen (i.e. the width/height of the screen) and restores the identity matrix for modelview.
After making this call, you can make glVertex2f() calls using screen/pixel coordinates, allowing you to draw in 2D! (This will also allow you to hit-test since you can easily get the mouse's current pixel coords.)
When you're done, call disable2D to restore your old modelview/projection matrices :)
The hardest part is computing where the hitboxes fall on the 2D plane and dealing with overlaying (if two project to the same place, which to select on click?)
Hope this helped :)
I've coded up a manipulator with handles for a 3d editing package, and ran into a lot of these same issues.
First, there's an open source manipulator. I couldn't find it in my most recent search, probably because there's a plethora of names for these things - 3d widgets, gizmos, manipulators, gimbals, etc.
Anyhow, the way I did it was to add a manipulator object to the scene that, when drawn, draws all of the handles. It does the same thing for bounding box computation, and selection.
Reed's idea about keeping them the same size is interesting for handles that exist on objects, and might work there. For a manipulator, I found that it was more of a 3d UI element, and it was much more usable if it did not change size. I had a bug where the size was only determined based on the active viewport, which resulted in horrible huge/tiny manipulators in other viewports, very useless. If you're going to add them to the scene, you might want to add them per-viewport, or make them actually have a fixed size.
I know the question is really old. But just in case someone needs it:
Interactive Techniques in Three-dimensional Scenes (Part 1): Moving 3D Objects with the Mouse using OpenGL 2.1
Article is good and has an interesting link section at the bottom.

Combining OpenGL renderings into one view

I have a simple solid modeling application in which I want to implement several "navigation modes", ways for the user to navigate the camera through 3d space. One of them is the ubiquitous 'drag and pan/rotate' that is used in SketchUp, Blender etc.; I also want to implement something that is more relevant to my specific application. Specifically, I want to implement a mode where the camera floats on a 'ring' above the object being modeled (a building), and always looks at the center of the model; this way, a user can easily 'circle' around the object, a common operation in my application.
So, what I want to do is render the building in my view, and display a torus in the top right of the view, with a small sphere on the torus to represent the camera location. There would be a north arrow in the torus, and the user would drag the camera around the model object by dragging the sphere; moving the sphere would reposition the camera and redraw the scene.
It looks like what I should do is the following: render the 'main view', i.e. the building; then render the torus and sphere (with different perspective settings and lighting) to an offscreen buffer, and blit it from there to my main view.
Then however I get to the hit testing. I want to detect if the user clicks on the sphere, or the torus; from what I understand from OpenGL picking (it seems to be a hard subject :/ ), all picking methods apply only for selecting in one 'scene'. Apart from that, I still want to detect 'normal' picking operations in the building model, obviously.
So, my questions:
How do I render to an offscreen buffer and blit into another OpenGL context (with alpha blending & transparence like for the center of the torus)?
How do I do hit testing in the described scenario?
I don't think you need to do off-screen rendering for this. You should be able to just re-set the camera and viewport and render the overlay after the main scene. You might have issues with Z-ordering and/or buffering, but perhaps the "sub-scene" is simple enough for that not to matter, or you could of course just clear the Z buffer before rendering it.
As far as drawing the torus/sphere goes, create a separate class for that and implement a "draw" method. Have the class contain the location of both the sphere and torus and have draw() render those things on the screen.
Then just call myRing.draw() in your main drawing method and you'll have a sphere and torus!
If you mean you want to have a a circle/ring rendered in 2D (which might be easier) in the top right corner of the window, then the same sort of idea would apply as in your hitbox post (except without that annoying projection calculation!)
Lastly, I'd consider using a function key in combination with mouse drags to implement the functionality you want... E.g. the user holds "shift" and then click-drags the mouse across the screen. These mouse events are caught and the x-delta is used to compute the angle of rotation. The camera's location is updated as this happens and you get a smooth sliding motion :)
I agree with #unwind; you don't need an offscreen buffer. If you want to anyway, search for "render-to-texture".
As for hit testing, The OpenGL FAQ has an entry on it. It describes several solutions: using GL_SELECTION render mode, using gluUnproject() to get a 3D collision ray and a simple 2D solution using unique colors.