tags:

views:

359

answers:

3

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.

+2  A: 

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.

Reed Copsey
I see your point about the perspective adding visual clues. I'm not convinced yet though that this'll feel natural to a user; for example what about handles that are clipped by other objects? I'll examine some other 3d modelers to see how they do it and try both approaches in my test application. Thanks for taking the time to answer.
Roel
One option is to allow the perspective to stay, but render these last with depth testing turned off. They'll always be visible (even on top of the other objects). I wouldn't make that the default way, but it's a nice option, so you can toggle on/off whether to always show the handles, even "through" an object.
Reed Copsey
I still need to find out how that exactly works with the depth buffer, but that would work I think. I have much trial and error before me :) Thanks.
Roel
Well, you'd turn off writing to and testing the depth buffer in that case - basically, it'd always draw your objects (on top of everything else). It's less intuitive, but useful as a toggle/option.
Reed Copsey
We used this method in my previous incarnation as a writer of 3D applications and it worked well. I wouldn't turn off the depth testing though.
ChrisF
I've done both. Turning off depth testing is a nice option if you have lots of other objects that may obscure your handles, but it needs to be an option. As a default, it's really confusing.
Reed Copsey
+1  A: 

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 :)

ParoXoN
This looks like a very useful technique that I can use in many other places in my code, thanks! I'm quite new to OpenGL so I'm still learning the ropes, tips and tricks like this one seem to be quite hard to come by. Thank you!
Roel
Glad to help XD
ParoXoN
+1  A: 

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.

tfinniga
Can you explain what your 'manipulator' does? It seems to be different from the 'handles' that I described in my question?
Roel
Sure.. a manipulator is the little thing that provides the handles for transforming geometry. This is typically objects, verts, edges, faces, or other components.Here's an image of Maya's manipulator: http://www.imanishi.com/mayablog/mayaPolygon/pC1.jpg
tfinniga