How to perform a box selection?

kungfoomasta

11-02-2008 23:57:34

I'm reading the PhysX tutorials, and I see the following intersections:


1. NxScene::overlapSphereShapes() - test for shapes in the scene intersecting a sphere
2. NxScene::overlapAABBShapes() - test for shapes in the scene intersecting an AABB
3. NxScene::cullShapes() - test for shapes in the scene culled inside a set of planes (you can use this for view frustum culling)

4. NxScene::checkOverlapSphere() - test to see if the sphere intersects any shapes in the scene
5. NxScene::checkOverlapAABB() - test to see if the AABB intersects any shapes in the scene


I'm assuming AABB is Axis Aligned Bounding Box. I want to project a cube from the camera, so that I can make a box selection using PhysX. (Grabbing objects by their Shape and not by Ogre::MovableObject)

Any ideas how to do this?

betajaen

12-02-2008 00:08:04

Via the intersection class my friend, or if you just want a one off piece of code then Scene::getActorsFromRegion and Scene::getActorsFromLastRegion will do the same job.

kungfoomasta

12-02-2008 17:57:59

Thanks for the direction. :)

For anybody else who wants a quick reference to the code:


SimpleBox* shape = static_cast<SimpleBox*>(mShape);
NxBox box = NxBox(shape->getPose().t, shape->getDimensions(), shape->getPose().M);
mScene->getNxScene()->overlapOBBShapes(box, mShapeFilter, 0, NULL, this);

betajaen

12-02-2008 18:07:23

This is easier, and more in line with NxOgre. ;)

mScene->getActorsFromRegion(mShape);

kungfoomasta

20-03-2008 02:41:21

Has anybody ever done this? The problem with this is that I don't know how to set the dimensions and position of the SimpleBox shape I want to use.

The orientation of the box (I think) is the same as the camera's. Problems:

I use a 2d rectangular box to outline the selection. I can get the dimensions of the 2d box, ie (0.5,0.5), but I don't know how to convert this to Ogre units. Something to do with the camera or frustum...
I'm guessing the 2d width is the x dimensions of the box, and the 2d height is the y dimensions of the box. The z dimensions is the box as it goes into the screen. Not sure what value to use here, I could make something up like 2000.

Any help with this would be greatly appreciated.

moagames

11-04-2008 18:01:33

Hi,

I also need to perform a multi selection using a rectangle on the screen.

To get the rectangle in 3d world i can use the getCameraToViewportRay from Ogre for the 4 corners of the rectangle.

But how can i now get all the actors AND characters in this region ?

Thank you very much

P.S.: I am using 0.9

moagames

12-04-2008 12:36:11

no ideas ????????

SiWi

13-04-2008 10:26:31

Characters also use an Actor, though I´m not sure if getActorsFromRegion() filters out the Characteractors as Raycaster does.
The other way would be a manual approach by using the Characters positions.

betajaen

13-04-2008 11:49:55

This is what I use in Cake Bleeding, it's slightly buggy but for the most part works.

if (dragMode == DRAG_NONE && mKeyboard->isKeyDown(KC_LSHIFT) && mMouse->getMouseState().buttonDown(OIS::MB_Left)) {
mDragger->setXY(mGUI->mMousePointer->getLeft(), mGUI->mMousePointer->getTop());
mDragger->show();

dragMode = DRAG_SIZE;
return;
}

if (dragMode == DRAG_SIZE && mMouse->getMouseState().buttonDown(OIS::MB_Left)) {
mDragger->setWH(mGUI->mMousePointer->getLeft(), mGUI->mMousePointer->getTop());
}
else if (dragMode == DRAG_SIZE) {

mDragger->hide();
dragMode = DRAG_NONE;

Ogre::Vector3 pos = mCamera->getDerivedPosition();
Ogre::Quaternion quat = mCamera->getDerivedOrientation();

NxReal width = widthTo3D(mCamera, mDragger->mOverlayContainer->getLeft(), mDragger->mOverlayContainer->getWidth());
NxReal height = heightTo3D(mCamera, mDragger->mOverlayContainer->getTop(), mDragger->mOverlayContainer->getHeight());

std::cout << "Width => " << width << ", Height => " << height << std::endl;
NxReal length = 10;
Ogre::Vector3 direction(width, height, length);

// Place the intersection half way through.
pos += (quat * Vector3(0,0,-length * 0.5f));

if (intersection == 0) {
sbox = new SimpleBox(direction * 0.5f, NxOgre::Pose(pos, quat));
intersection = new Intersection(mScene, sbox);

inode = mSceneMgr->getRootSceneNode()->createChildSceneNode("inode");
Entity* ent = mSceneMgr->createEntity("ient", "cube.1m.mesh");
ent->setMaterialName("Drag");
inode->attachObject(ent);
inode->setPosition(pos);
inode->setOrientation(quat);
inode->setScale(direction);
}
else {
sbox->setDimensions(NxVec3(direction.x, direction.y, direction.z));
sbox->setPose(NxOgre::Pose(pos, quat));

inode->setPosition(pos);
inode->setOrientation(quat);
inode->setScale(direction);
}

intersection->intersect();
for (Actor* actor = intersection->begin(); actor = intersection->next();) {
std::cout << actor->getName() << "\n";
quickSetMaterial(actor, "gloss-red");
}

}


void quickSetMaterial(Actor* actor, const NxString& mat) {
if (actor->getUserData()->RenderPtr == 0)
return;

// Dangerous.....
RenderableSource* rs = actor->getUserData()->RenderPtr;
OgreNodeRenderable* nr = static_cast<OgreNodeRenderable*>(rs->getRenderable());
nr->setMaterial(mat);

}

Ogre::Vector3 screenTo3D(Ogre::Camera *cam, float x = 0.5, float y = 0.5) {
Ogre::Ray ray = cam->getCameraToViewportRay(x, y);
return ray.getOrigin();
}

float widthTo3D(Ogre::Camera *cam, float x0, float x1) {
return (screenTo3D(cam, x0, 0.5) - screenTo3D(cam, x1, 0.5)).length();
}

float heightTo3D(Ogre::Camera *cam, float y0, float y1) {
return (screenTo3D(cam, 0.5, y0) - screenTo3D(cam, 0.5, y0)).length();
}

"mDragger" is just a wrapped BetaGUI window, you don't need to know the implementation.

kungfoomasta

10-11-2008 08:58:51

Unless I'm doing this wrong, I think PhysX has a bug with its cullShapes function, regarding filtering. All other ray casting and intersection queries I've done so far works with filtering correctly. Here is my code:


//do volumequery
Ogre::Ray topLeft = camera->getCameraToViewportRay(sides[SelectionRectangle::LEFT], sides[SelectionRectangle::TOP]);
Ogre::Ray topRight = camera->getCameraToViewportRay(sides[SelectionRectangle::RIGHT], sides[SelectionRectangle::TOP]);
Ogre::Ray bottomLeft = camera->getCameraToViewportRay(sides[SelectionRectangle::LEFT], sides[SelectionRectangle::BOTTOM]);
Ogre::Ray bottomRight = camera->getCameraToViewportRay(sides[SelectionRectangle::RIGHT], sides[SelectionRectangle::BOTTOM]);

NxPlane worldPlanes[5];
NxVec3 point1, point2, point3;

// front plane
point1 = NxVec3(topLeft.getPoint(3).x, topLeft.getPoint(3).y, topLeft.getPoint(3).z);
point2 = NxVec3(topRight.getPoint(3).x, topRight.getPoint(3).y, topRight.getPoint(3).z);
point3 = NxVec3(bottomRight.getPoint(3).x, bottomRight.getPoint(3).y, bottomRight.getPoint(3).z);
worldPlanes[0] = NxPlane(point3, point2, point1);

// top plane
point1 = NxVec3(topLeft.getOrigin().x, topLeft.getOrigin().y, topLeft.getOrigin().z);
point2 = NxVec3(topLeft.getPoint(100).x, topLeft.getPoint(100).y, topLeft.getPoint(100).z);
point3 = NxVec3(topRight.getPoint(100).x, topRight.getPoint(100).y, topRight.getPoint(100).z);
worldPlanes[1] = NxPlane(point3, point2, point1);

// left plane
point1 = NxVec3(topLeft.getOrigin().x, topLeft.getOrigin().y, topLeft.getOrigin().z);
point2 = NxVec3(bottomLeft.getPoint(100).x, bottomLeft.getPoint(100).y, bottomLeft.getPoint(100).z);
point3 = NxVec3(topLeft.getPoint(100).x, topLeft.getPoint(100).y, topLeft.getPoint(100).z);
worldPlanes[2] = NxPlane(point3, point2, point1);

// bottom plane
point1 = NxVec3(topLeft.getOrigin().x, topLeft.getOrigin().y, topLeft.getOrigin().z);
point2 = NxVec3(bottomRight.getPoint(100).x, bottomRight.getPoint(100).y, bottomRight.getPoint(100).z);
point3 = NxVec3(bottomLeft.getPoint(100).x, bottomLeft.getPoint(100).y, bottomLeft.getPoint(100).z);
worldPlanes[3] = NxPlane(point3, point2, point1);

// right plane
point1 = NxVec3(topLeft.getOrigin().x, topLeft.getOrigin().y, topLeft.getOrigin().z);
point2 = NxVec3(topRight.getPoint(100).x, topRight.getPoint(100).y, topRight.getPoint(100).z);
point3 = NxVec3(bottomRight.getPoint(100).x, bottomRight.getPoint(100).y, bottomRight.getPoint(100).z);
worldPlanes[4] = NxPlane(point3, point2, point1);

NxU32 nbShapes = mNxScene->getNbDynamicShapes() + mNxScene->getNbStaticShapes();
NxShape** shapes = new NxShape* [nbShapes];
for (NxU32 i = 0; i < nbShapes; i++)
shapes[i] = NULL;

this->getNxScene()->cullShapes(5, worldPlanes, NX_ALL_SHAPES, nbShapes, shapes, NULL, collisionMask);

for (NxU32 i = 0; i < nbShapes; i++)
if(shapes[i])
selectedObjects.push_back(static_cast<Gaia::GameObject*>(shapes[i]->getActor().userData));


The only collision groups I have are '1', '2', and '3'. The mask as used in the code is '4', which is (1 << 2). Unfortunately all shapes are being returned, regardless of my selection size. I'll probably check out the physx forums and post there, unless somebody here spots anything wrong with my code.

kungfoomasta

10-11-2008 21:55:24

I was never sent an activation email, and I can't post on any relevant PhysX forums. Can anybody help me out, or at least post this issue and bring it to their attention? I'm fairly certain there is a bug, where the function "cullShapes" does not apply the collision filter. :(