• Advertisement
Sign in to follow this  

RTS Selection box in 3D, How?

This topic is 4519 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

as what the title said how to perform selection box in 3D? i already have my box working(rendering using mouse) and my object picking(but only 1 object) in 3D working all i have to do is multiple selection using selection box..

Share this post


Link to post
Share on other sites
Advertisement
Hi there yuppies,
How are you doing?

The Problem
The problem is that you need to click 'n drag the mouse and draw a rectangle.

The Solution
I would say that the easiest method would be to check for a mouse pressed and a mouse release event. Which will signify when the mouse is pressed and when a mouse is released. You then have 2 points which will form a rectangle. You just do a test of all your selectable objects/units to see if they are in the rectangle and if they are highlight/add/select them.

I hope this makes sense.
Take care.

Share this post


Link to post
Share on other sites
thanks for answering my question. But i Think the approach you are saying applies only in 2D :) i knw how to do this in 2D but my question is on 3D
I already have the selection box rendere during mouse events but the problem is selecting the objects inside the selection box in 3D

anyone here tried develping 3D RTS in DX?

Share this post


Link to post
Share on other sites
I can think of two approaches off the top of my head:

--------------------------------

1. Perform the selection in screenspace

Project a point or set of points representing each entity into window space. Select those entities for which the screenspace bounding box of the projected points intersects the selection rectangle.

2. Perform the selection in world space

Unproject the corners of the selection rectangle into world coordinates at the near and far planes. Use the resulting 8 points to form a selection volume. Select those entities whose bounding volumes intersect the selection volume.

--------------------------------

There may also be other methods I'm not thinking of. Which method to use, and whether it can be optimized for your particular circumstances, depends on your game. I tend to prefer worldspace solutions, so I'd probably go with the second option if it were my game.

Share this post


Link to post
Share on other sites
I'd go with a world space solution as well, like jyk recommend. But instead of doing a volume intersection, I'd just do 4 half space tests. You have the min and max points from the button down and button up, just use those coords to form the 4 planes(top,bottom,left,right). Then its as simple as doing a dot product with each of the planes to see if they are all on the inside of the rectangle selection.

- Dave

Share this post


Link to post
Share on other sites
Quote:
Then its as simple as doing a dot product with each of the planes to see if they are all on the inside of the rectangle selection.
That's basically what I had in mind. By 'selection volume' I just meant the intersection of the positive half-spaces of the planes you mentioned.

Share this post


Link to post
Share on other sites
I'm doing this too - I got single unit selection down (and multiple by shift-clicking), but wasn't sure about dragging. Creating a box to test against is probably the most accurate way but a bit fiddly. I suppose it's pretty much the same as testing an object agaisnt the camera frustum though so I could rip that code?

Other solutions I thought of were simpler to code but not 100 % accurate if the selected terrain area was particularly uneven.

Share this post


Link to post
Share on other sites
can u guys show me some code since i cant get it to work?
can u guys take a look whats wrong with this


//m_oldx,m_oldy are the old mouse coords during mouse down
//m_newx,m_enwy are the new mouse coords during mouse move

D3DXVECTOR3 v1, v2, v3, v4;
D3DXVECTOR3 v[4];

//top left NEAR
v1.x = m_oldx;
v1.y = m_oldy;
v1.z = 0.0f;

//Bottom right NEAR
v2.x = m_newx;
v2.y = m_newy;
v2.z = 0.0f;

//swap
if( m_newx <m_oldx )
{
v1.x = m_newx;
v2.x = m_oldx ;
}

if( m_newy< m_oldy )
{
v1.y = m_newy;
v2.y = m_oldy;
}

//Top left FAR
v3.x = v1.x;
v3.y = v1.y;
v3.z = 1.0f;

//Bottom right FAR
v4.x = v2.x;
v4.y = v2.y;
v4.z = 1.0f;

D3DXVECTOR3 vTopLeftNear, vBottomRightNear;
D3DXVECTOR3 vTopLeftFar, vBottomRightFar;
D3DVIEWPORT9 vp;
D3DXMATRIX proj;
D3DXMATRIX view;
D3DXMATRIX world;
D3DXVECTOR3 vDir;

m_pDevice->GetViewport(&vp);
m_pDevice->GetTransform(D3DTS_PROJECTION, &proj);
m_pDevice->GetTransform(D3DTS_VIEW, &view);
m_pDevice->GetTransform(D3DTS_WORLD,&world);

D3DXVec3Unproject( &vTopLeftNear,&v1,&vp,&proj,&view,&world );
D3DXVec3Unproject( &vBottomRightNear,&v2,&vp,&proj,&view,&world );
D3DXVec3Unproject( &vTopLeftFar,&v3,&vp,&proj,&view,&world );
D3DXVec3Unproject( &vBottomRightFar,&v4,&vp,&proj,&view,&world );
D3DXPLANE ClippingPlanes[6];

D3DXVECTOR3 vLeftBottomFar (vTopLeftFar.x, vBottomRightFar.y,vTopLeftFar.z);
D3DXVECTOR3 vLeftBottomNear (vTopLeftNear.x, vBottomRightNear.y,vTopLeftNear.z);
D3DXVECTOR3 vRightTopNear (vBottomRightNear.x, vTopLeftNear.y,vBottomRightNear.z);
D3DXVECTOR3 vRightTopFar (vBottomRightFar.x, vTopLeftFar.y,vBottomRightFar.z);

//Left plane:
D3DXPlaneFromPoints(&ClippingPlanes[0], &vLeftBottomFar, &vTopLeftFar, &vTopLeftNear);
//Right plane:
D3DXPlaneFromPoints(&ClippingPlanes[1], &vRightTopNear, &vRightTopFar, &vBottomRightNear);
//Top plane:
D3DXPlaneFromPoints(&ClippingPlanes[3], &vTopLeftNear, &vRightTopFar, &vRightTopNear);
//Bottom plane:
D3DXPlaneFromPoints(&ClippingPlanes[2], &vBottomRightFar, &vLeftBottomFar, &vBottomRightNear);
//Near clip plane:
D3DXPlaneFromPoints(&ClippingPlanes[4], &vTopLeftNear, &vRightTopNear, &vBottomRightNear);
//Far clip plane:
D3DXPlaneFromPoints(&ClippingPlanes[5], &vRightTopFar, &vTopLeftFar, &vBottomRightFar);



and heres how i did the checking for bounding box of every object



bool BoxInClippingPlane( D3DXPLANE plane[6], D3DXVECTOR3 min,D3DXVECTOR3 max )
{
for( char p = 0; p < 6; p++ )
{
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( min.x, min.y, min.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( max.x, min.y, min.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( min.x, max.y, min.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( max.x, max.y, min.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( min.x, min.y, max.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( max.x, min.y, max.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( min.x, max.y, max.z ) ) >= 0.0f )
continue;
if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( max.x, max.y, max.z ) ) >= 0.0f )
continue;

return false;
}

return true;
}



sometimes this one work but most of the times it is not?
what possibly os wrong with this?

Share this post


Link to post
Share on other sites
Hi,

There are a lot of details there and I didn't check them all. But I'll offer some observations/suggestions:

1. Test the AABB-plane function by itself. Just make an AABB that you can move around, and draw it in different colors depending on where it is in reference to some test plane. Once you're sure that works, you can eliminate that as a possible source of the problem.

2. There are faster/better AABB-plane tests that you may want to look into at some point.

3. I think the code would be easier to read with consistent corner variable names. That is, always go in the order left/right, bottom/top, near/far. So for example, you would have leftBottomNear, rightBottomNear, rightTopNear, leftTopNear. And so on.

4. You're taking a shortcut in computing the corners that I don't think will work. In 2d you can construct one corner from the components of another, as you are doing, but in world space I think you'll need to unproject each corner individually.

5. Make sure your winding is consistent in the plane construction.

Share this post


Link to post
Share on other sites
You're close enough to getting your current method working that you might just want to stick with it. However, after considering the problem I realized I would probably use a different method than the one I recommended.

OpenGL has a 'pick matrix' function intended for use with OpenGL feedback mode. The functionality however is API independent, and has the generic effect of redefining the current view frustum to reflect the ratio between the window and a rectangular selection area.

So here's what I'd do (in fact I may try it later today). Multiply your projection matrix with a picking matrix to derive the new frustum. Use this algorithm to extract the frustum planes from the combined view, world, and projection matrices. These planes then form the selection volume.

Some advantages of this method:

1. Generally you need frustum plane extraction and AABB-frustum testing for visibility. This approach allows you to re-use this code for selection.

2. It might be a little faster than the other method (although I doubt it would matter much).

To implement this method, you'd need code to extract frustum planes and to create a picking matrix. So it might take some work, but I think you'd be happy with the results.

Share this post


Link to post
Share on other sites
Quote:
http://www.gpwiki.org/index.php/Object_selection_lasso
The OP can correct me if I'm wrong, but I think his code is already based off that article.

Share this post


Link to post
Share on other sites
Try using an identity matrix for the matWorld matrix;

D3DXMatrixIdentity(&matWorld);

And you need to use transformed coordinatres for comparison:

if( D3DXPlaneDotCoord( &plane[p], &D3DXVECTOR3( min.x, min.y, min.z ) ) >= 0.0f )
continue;

Those min/max values need to be transformed, since it's the bounding box of your object, simpply transform it by the matrix you used to render the object/unit.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement