Sign in to follow this  

Extracting a box of planes from a screenspace rect?

This topic is 4198 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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!

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 x
py = pick rect center y
pw = pick rect width
ph = pich rect height
vx = viewport origin x
vy = viewport origin y
vw = viewport width
vh = 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.

Share this post


Link to post
Share on other sites

This topic is 4198 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this