Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a game I'm working on in which items are "placed" and "selected".

In order to do this, I need to determine what triangle in a mesh the cursor is pointing to. I have no trouble with getting the cursor position or the orientation/position of the camera - the problem is figuring out how they relate.

I'm guessing that this involves ray-picking, but I have no idea on how to convert a cursor position to a ray that I can test for intersection with a triangle.

A little bit of background:
Game engine: Irrlicht
Language: C++

share|improve this question

3 Answers 3

up vote 2 down vote accepted

I found a solution, though not an in-depth explanation - seems like Irrlicht has a built in function for this:

irr::scene::ISceneCollisionManager::getRayFromScreenCoordinates

This will calculate a ray given a screen coordinate.

share|improve this answer
    
I wonder if ogre has an equivalent –  jokoon Dec 13 '10 at 12:55

To convert a cursor position to a ray, you can back-project the 2D co-ordinates onto two planes parallel to the view plane. Typically you might use the near and far planes. Two points define a ray.

This is simply a matter of doing the maths used to project a 3D point onto the screen, in reverse.

Typically from world space you would multiply by a view and projection matrix to get into clip-space, divide by Z to do the actual projection, and then scale the resulting values into pixel-values.

So in reverse you would scale the screen-coordinates into clip space, multiply by Z (taken from the plane you're interested in), and transform by the inverse of the view-projection matrix to get back into world space.

However as you've noticed, most engines and libraries can do this for you...

share|improve this answer
    
Thanks for explaining it though! I figured it would involve some kind of reverse projection. –  George Edison Nov 28 '10 at 22:56

Irrlicht Tutorials This link explains the triangle selection and ray casting, just need to convert screen to the world coords.

scene::ITriangleSelector* selector = 0;
scene::IAnimatedMeshSceneNode* node = 0;

    // Add an MD2 node, which uses vertex-based animation.
    node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/faerie.md2"),
                                            0, IDFlag_IsPickable | IDFlag_IsHighlightable); 
    node->setPosition(core::vector3df(-70,-15,-120)); // Put its feet on the floor.
    node->setScale(core::vector3df(2, 2, 2)); // Make it appear realistically scaled
    node->setMD2Animation(scene::EMAT_POINT);
    node->setAnimationSpeed(20.f);
    video::SMaterial material;
    material.setTexture(0, driver->getTexture("../../media/faerie2.bmp"));
    material.Lighting = true;
    material.NormalizeNormals = true;
    node->getMaterial(0) = material;

    // Now create a triangle selector for it.  The selector will know that it
    // is associated with an animated node, and will update itself as necessary.
    selector = smgr->createTriangleSelector(node);
    node->setTriangleSelector(selector);
    selector->drop();
    scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager();

In the main loop

while(device->run())
    if (device->isWindowActive())
    {
            driver->beginScene(true, true, 0);
            smgr->drawAll();
            scene::ISceneNode * selectedSceneNode =
                    collMan->getSceneNodeAndCollisionPointFromRay(
                                    ray,
                                    intersection, // This will be the position of the collision
                                    hitTriangle, // This will be the triangle hit in the collision
                                    IDFlag_IsPickable, // This ensures that only nodes that we have
                                                    // set up to be pickable are considered
                                    0); // Check the entire scene (this is actually the implicit default)

            // If the ray hit anything draw the triangle that was hit.
            if(selectedSceneNode)
            {
                    driver->setTransform(video::ETS_WORLD, core::matrix4());
                    driver->setMaterial(material);
                    driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0));

            }

            // We're all done drawing, so end the scene.
            driver->endScene();
     }
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.