Extracting a box of planes from a screenspace rect?

Started by
5 comments, last by Zakwayda 17 years, 10 months ago
Hello. Im trying to do "area selection". You know in 3d-modelling software where you press the left mouse button, drag, and then then release, and it selects the objects that is inside the rect you created by dragging the mouse. Iv figured out i should do this by creating four planes (or five or six, if far and near planes are used too) that represent the screenspace rect, but are going inwards into the scene from your viewpoint. And then i just check for intersection or complete containment for all the 3d-models and the planes. But i suck at plane extraction. =) Anyone know how to build these five or six(far) planes from a screenspace rect? Thanks in advance!
Shields up! Rrrrred alert!
Advertisement
Quote:Original post by peter_b
Hello. Im trying to do "area selection". You know in 3d-modelling software where you press the left mouse button, drag, and then then release, and it selects the objects that is inside the rect you created by dragging the mouse.

Iv figured out i should do this by creating four planes (or five or six, if far and near planes are used too) that represent the screenspace rect, but are going inwards into the scene from your viewpoint. And then i just check for intersection or complete containment for all the 3d-models and the planes.


But i suck at plane extraction. =)

Anyone know how to build these five or six(far) planes from a screenspace rect?

Thanks in advance!
Here's how I've done this in the past, IIRC.

The first step is to get 'regular' frustum plane extraction working. This can be a little tricky to debug, since you're usually viewing the world from the camera's point of view and can't necessarily see if the frustum is correct. One way to test your frustum code is to instead associate the frustum with another object that you can view externally.

There are a couple of different ways to extract the planes; I use the algorithm in the widely available article that, I think, appeared in one of the GPG books. Google 'frustum plane extraction' to find it, or ask here if you need a link.

To test the frustum it's helpful to be able to see it. One way to do this is to intersect the frustum planes in sets of three to find the corners and then render the results in wireframe.

Once you're confident that your frustum code is correct, you then need a 'pick' matrix. This matrix, when applied to the view/projection matrix product, restricts the frustum to a volume associated with an onscreen rectangle with a given center, width and height. These latter values can easily be derived from the 'min' and 'max' corners of your 'dragging' rect.

That leaves out a lot of details, but I'll be glad to try and fill in anything that's missing.

Note that although this has worked well for me in the past, there may be other methods that would be simpler to implement. For example, you could just unproject the four corners of the drag rect and build planes from them and the camera position. The reason I advocate the perhaps more complicated approach above is that it's generally a good idea to have the frustum planes available anyway, and if that code is already in place the 'pick matrix' method is pretty straightforward. But YMMV.
Hello! Thanks for your awnser.

I have code for frustum culling inplace and it works, but i dont quite understand how to construct the pick-matrix. Could you explain that a little more?

Lets see if i get this right.
1. I construct a pick matrix from the selection rect's min&max.
2. I multiply with view & projection matrices.
3. I extract the frustum planes from that matrix.


Is that correct?
Shields up! Rrrrred alert!
Hey there. The good news is that this problem is probably a lot easier than it sounds. We need two things to specify a plane, the planes normal vector and a point in that plane (from which the origin offset (D value) can be calculated). The normal of each plane will simply be the positive or negative of either the cameras x or y vectors depending on the plane (if the camera looks down its z axis that is). The 3d point in the plane can be determined from its screen location and the camera projection matrix. According to a guide I found through google:

Vector3 v; v.X = (((2.0f * mouseLoc.X) / screenWidth) - 1) / proj.M11;v.Y = -(((2.0f * mouseLoc.Y) / screenHeight) - 1) / proj.M22;v.Z = 1.0f; 


Hope that helps



Edit: Blimey, leave the screen for 10 mins half way through writing a reply and by the time I click post there's already two responses ^^. I just made the above up on the spot but from the sounds of it maybe I'm treating this a little too simplisticly.
[size="1"] [size="4"]:: SHMUP-DEV ::
Quote:Original post by peter_b
Hello! Thanks for your awnser.

I have code for frustum culling inplace and it works, but i dont quite understand how to construct the pick-matrix. Could you explain that a little more?

Lets see if i get this right.
1. I construct a pick matrix from the selection rect's min&max.
2. I multiply with view & projection matrices.
3. I extract the frustum planes from that matrix.


Is that correct?
I didn't follow Motorherp's example, but maybe it's easier than the solution I'm proposing; I'm not sure. In any case, here's some pick matrix code:

template <class T> void Matrix4<T>::pick(T px, T py, T pw, T ph, T vx, T vy, T vw, T vh){    T invpw = (T)1.0 / pw;    T invph = (T)1.0 / ph;    /* Use this code if you're using row vectors, e.g. DirectX */    {        Set(vw * invpw,                        (T)0.0,                            (T)0.0, (T)0.0,            (T)0.0,                            vh * invph,                        (T)0.0, (T)0.0,            (T)0.0,                            (T)0.0,                            (T)1.0, (T)0.0,            (vw + (T)2.0 * (vx - px)) * invpw, (vh + (T)2.0 * (vy - py)) * invph, (T)0.0, (T)1.0);        }    /* Use this code if you're using column vectors, e.g. OpenGL */    {        Set(vw * invpw, (T)0.0,     (T)0.0, (vw + (T)2.0 * (vx - px)) * invpw,            (T)0.0,     vh * invph, (T)0.0, (vh + (T)2.0 * (vy - py)) * invph,            (T)0.0,     (T)0.0,     (T)1.0, (T)0.0,            (T)0.0,     (T)0.0,     (T)0.0, (T)1.0);    }}

This should go in the transform sequence right after the projection matrix (what this means in terms of matrix multiplication again depends on your vector convention).

If all goes well, you should be able to just apply your usual frustum plane extraction code to the resulting matrix and get the selection volume you're after. But, there are a lot of little things that can go wrong.

Also, make sure you compute the signs of the pick rect width and height correctly, since they'll vary depending on where the current mouse location is relative to the original location.
Thanks guys, il try both.

jyk: Can you tell me what the arguments for that function are? (T px, T py, T pw, T ph, T vx, T vy, T vw, T vh). Seems it takes two rects? p* and v*?
Shields up! Rrrrred alert!
Quote:Original post by peter_b
jyk: Can you tell me what the arguments for that function are? (T px, T py, T pw, T ph, T vx, T vy, T vw, T vh). Seems it takes two rects? p* and v*?
Hehe, yeah, that's old code, and not commented very well :-) Anyway, if I'm not mistaken:
px = pick rect center xpy = pick rect center ypw = pick rect widthph = pich rect heightvx = viewport origin xvy = viewport origin yvw = viewport widthvh = viewport height
I'm pretty sure that's right. I think that code was written with OpenGL in mind, so if you're using DirectX it may or may not work as is (I'm not sure how the D3D viewport is set up). If so though modifying it should be as easy as switching some signs.

This topic is closed to new replies.

Advertisement