Hi all!

 

I'm trying to use a osgUtil::PolytopeIntersector

to find the closest object in my 3D scene graph (with OSG ver.2.2).

I read on the OSG QSG that it should return the closest object

as the first in the list of intersections.

But it is not like that!

I mean that the array of intersections correctly contains all of

the objects hit by the intersection volume,

but the first of those is not necessary the closest.

BTW, it seems to be the object with the shortest node path. Might it be?

 

Any idea of my mistake?

 

Thank you in advance.

 

Gianluca

 

P.S.=attached is the source file (look into the class PickHandler,

    in the method pick; first I tried getting directly the first
intersection in

        the list, picker->getFirstIntersection(); then I tried to sort

        the intersection on my own. But I pick always the background
rectangle!)

 

// Test 11: OSG 3D application with node callback to dynamically modify the 
graph,
//          changing the color of an object when it is picked by the user (and 
restoring
//          it to the original color once no object is selected any more).
//          It creates a scene graph, and shows it in a window created by the 
osgViewer::Viewer.
//          The camera is kept rotating around the scene to let it be seen from 
many different
//          points of view (that is accomplished by directly modifying the 
modelview matrix
//          of the camera in the main loop).
//          When the user picks a point onto the screen (picking is checked by 
deriving a class
//          from an osgGA::GUIEventHandler), a Polytope intersector is created 
and
//                      passed to an IntersectionVisitor. So, at the end it 
will return the list of selected
//          objects, sorted from the nearest to the viewer up to the farthest.
//                      Then the picker will attach a ChangeColor callback to 
the nearest selected node, in
//          order to change its current color to the 'selection' color in the 
next update traversal.
//          Note that the color is changed by changing the material properties 
of the object,
//                      so changing the corresponding rendering state in the 
parent matrix transform of the node.

// The scene graph shown in the window is made by these nodes:
//
//                        MRT                             MRT = main root node
//                         |                              TMn = tranformation 
matrix n
//        +-----------+----+----------+----+----+         GPn = group n
//       TM1         GP1             TM6  TM7  TM8        GEn = geode n
//        |   +----+--+--+----+       |    |    |         LSn = light source n
//        |  TM2  TM3   TM4  TM5      |    |    |
//        |   +----+--+--+----+       |    |    |
//       GE1         GE2             LS1  LS2  GE3
//
// Specifically, in this graph we have:
// GE1 = a rectangle
// GE2 = a sphere
// GE3 = a cube to show the position of the spot light source (LS2)
// LS1 = a directional light (fixed in the scene)
// LS2 = a localized spot light (moving with the scene)
/////////////////////////////////////////////////////////////////////////////////////////

#include <osg/ref_ptr>   // include the class osg::ref_ptr, to manage the smart 
osg ref_ptr
                         // (a smart pointer to Referenced objects in OSG)
#include <osg/Geometry>  // include the class osg::Geometry to manage the 
geometry of a drawable
                         // (vertices, colors, normals)
#include <osg/Geode>     // include the class osg::geode (geode stands for 
GEOmetry noDE),
                         // that is to say the node which stores the geometry 
of an object
#include <osg/Material>  // for material properties, when an object is lit by a 
light source
#include <osg/ShapeDrawable> // for the generic shape drawable used to 
implement spheres, cylinders, etc...
#include <osg/LightSource> // to store a source of light in the scene graph, in 
order to lit the scene
#include <osg/MatrixTransform> // to deal with transformation matrices
#include <osg/Group> // to store a group node, that is to say a node that can 
have child nodes
#include <osg/ShadeModel> // to store the shade model of an object (FLAT or 
SMOOTH)

#include <osgViewer/Viewer> // to include the viewer, which creates a window 
and a rendering
                            // context, to make it current for OpenGL drawing 
commands

#include <osg/NodeCallback>              // for node callback, that allows a 
dynamic modification of the graph
#include <osgUtil/UpdateVisitor> // (during the update traversal)

#include <osgGA/GUIEventHandler> // the base class to handle events from the 
user
#include <osgGA/GUIEventAdapter> 
#include <osgGA/GUIActionAdapter>

#include <osgUtil/PolytopeIntersector> // to check intersection against a 
polytope and objects
#include <osgUtil/IntersectionVisitor> // in the scene

#include <osg/Notify>
#include <iostream>
using std::endl;

///////////////////////////////////////////////////////////////////////////////////////////
// A class derived from NodeCallback to allow dynamic modification of a 
transformation
// matrix (that is to say, the material properties associated with that matrix)
class ChangeColorCB : public osg::NodeCallback
{
public:
        ChangeColorCB(osg::Vec4 &newColor) : _color( newColor ) {} // 
constructor takes the color
                                                                                
                                           // to change material properties into

        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
        {
                // Normally, check to make sure we have an update visitor
                osgUtil::UpdateVisitor* uv = 
dynamic_cast<osgUtil::UpdateVisitor*>(nv);
                if (!uv) return;

                // Check that the node to update is a matrix transform (since 
we are changing material
                // properties only in those kind of nodes)
                osg::MatrixTransform* mt = 
dynamic_cast<osg::MatrixTransform*>(node);
                if (!mt) return;

                // Change material properties for diffuse and ambient light, 
but preserves original
                // properties for specular light and shininess
                osg::StateSet *matrixTransformState = mt->getOrCreateStateSet();
                osg::ref_ptr<osg::Material> materialProp = new osg::Material;

                osg::StateAttribute *originalStateAttr = 
matrixTransformState->getAttribute(osg::StateAttribute::MATERIAL);
                osg::Material *originalMatProps = 
dynamic_cast<osg::Material*>(originalStateAttr);
                if (originalMatProps)
                {
                        // assign original specular and shininess to the 
material properties that are being assigned to the matrix transf.
                        materialProp->setSpecular ( osg::Material::FRONT, 
originalMatProps->getSpecular(osg::Material::FRONT) );
                        materialProp->setShininess( osg::Material::FRONT, 
originalMatProps->getShininess(osg::Material::FRONT) );
                }
                // and change the ambient and diffuse color properties with 
that stored in the class            
                materialProp->setDiffuse(osg::Material::FRONT, _color);
                materialProp->setAmbient(osg::Material::FRONT, _color);

                matrixTransformState->setAttribute(materialProp.get());

                // Continue traversing so that OSG can process
                // any other nodes with callbacks (really this is useless in 
our case, since just one object
                // at a time can be selected).
                traverse( node, nv );
        }

protected:
        osg::Vec4 _color; // color for ambient and diffuse light reflection to 
assign to the node 
};

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::Node> createRectangle()
{
        // Create the object to store geometry in.
        osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

        // Create an array of nine vertices (to define the rectangle as a 
triangle fan):
        //
        //          3
        //   4 *----*----* 2
        //     |\   |   /|
        //     | \  |  / |
        //     |  \ | /  |
        //     |   \|/   |
        //   5 *----*0---* 1
        //     |   /|\   |
        //     |  / | \  |
        //     | /  |  \ |
        //     |/   |   \|
        //   6 *----*----* 8
        //          7
        //
        osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
        geom->setVertexArray( v.get() );
        v->push_back( osg::Vec3(  0.0f,  0.0f,  0.0f ) ); // 0
        v->push_back( osg::Vec3( +1.0f,  0.0f,  0.0f ) ); // 1
        v->push_back( osg::Vec3( +1.0f,  0.0f, +1.0f ) ); // 2
        v->push_back( osg::Vec3(  0.0f,  0.0f, +1.0f ) ); // 3
        v->push_back( osg::Vec3( -1.0f,  0.0f, +1.0f ) ); // 4
        v->push_back( osg::Vec3( -1.0f,  0.0f,  0.0f ) ); // 5
        v->push_back( osg::Vec3( -1.0f,  0.0f, -1.0f ) ); // 6
        v->push_back( osg::Vec3(  0.0f,  0.0f, -1.0f ) ); // 7
        v->push_back( osg::Vec3( +1.0f,  0.0f, -1.0f ) ); // 8

        // Create an array of normals for the 9 vertices (to simulate some 
curvature for
        // the rectangle, that is to say, not flat!).
        osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
        geom->setNormalArray( n.get() );
        geom->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
        osg::Vec3 n_0(  0.0f, -1.0f,   0.0f); n->push_back(n_0); // already 
normalized!
        osg::Vec3 n_1(+0.15f, -0.9f,   0.0f); n_1.normalize(); 
n->push_back(n_1);
        osg::Vec3 n_2(+0.15f, -0.9f, +0.15f); n_2.normalize(); 
n->push_back(n_2);
        osg::Vec3 n_3(  0.0f, -0.9f, +0.15f); n_3.normalize(); 
n->push_back(n_3);
        osg::Vec3 n_4(-0.15f, -0.9f, +0.15f); n_4.normalize(); 
n->push_back(n_4);
        osg::Vec3 n_5(-0.15f, -0.9f,   0.0f); n_5.normalize(); 
n->push_back(n_5);
        osg::Vec3 n_6(-0.15f, -0.9f, -0.15f); n_6.normalize(); 
n->push_back(n_6);
        osg::Vec3 n_7(  0.0f, -0.9f, -0.15f); n_7.normalize(); 
n->push_back(n_7);
        osg::Vec3 n_8(+0.15f, -0.9f, -0.15f); n_8.normalize(); 
n->push_back(n_8);

        // No need to assign the color to the object, since it will just 
reflects the lights
        // that come from the light sources. Its material properties will be 
assigned in the matrix
        // transform it is attached to

        // Draw a triangle fan (representing the quad) from the stored data.
        GLuint tri_fan[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 1};
        geom->addPrimitiveSet(new 
osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_FAN, 10, tri_fan));

        // Add the Geometry (Drawable) to a Geode and
        // return the Geode.
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->addDrawable( geom.get() );
        return osg::ref_ptr<osg::Node>(geode.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::Node> createSphere(float radius=0.25f)
{
        // Create the sphere directly by the ShapeDrawable class
        osg::ref_ptr<osg::Shape> sphere = new osg::Sphere(osg::Vec3(0.0f, 0.0f, 
0.0f), radius);
        osg::ref_ptr<osg::ShapeDrawable> sphereShape = new 
osg::ShapeDrawable(sphere.get(), 0);

        // No need to assign the ambient and diffuse color to the object here, 
since it will just
        // reflects the lights that come from the light sources. Its material 
properties will be
        // assigned directly to the rendering state of the parent of this shape 

        // Add the shape drawable to a Geode and return the Geode.
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->addDrawable( sphereShape.get() );
        return osg::ref_ptr<osg::Node>(geode.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::Node> createBox(float width=0.15f, float height=0.05f, float 
depth=0.05f)
{
        // Create the box (to simulate the position of the spot light) directly 
by the
        // ShapeDrawable class
        osg::ref_ptr<osg::Shape> box = new osg::Box(osg::Vec3(0.0f, 0.0f, 
0.0f), width, height, depth);
        osg::ref_ptr<osg::ShapeDrawable> boxShape = new 
osg::ShapeDrawable(box.get(), 0);

        // No need to assign the ambient and diffuse color to the object here, 
since it will just
        // reflects the lights that come from the light source 1. Its material 
properties will be
        // assigned directly to the rendering state of the parent of this shape 

        // Add the shape drawable to a Geode and return the Geode.
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->addDrawable( boxShape.get() );
        return osg::ref_ptr<osg::Node>(geode.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::LightSource> createDirectionalLightSource()
{
        // Create a white directional light, used as LIGHT 0 in the scene
        osg::ref_ptr<osg::Light> light = new osg::Light;

        light->setLightNum(0); // so this light source is seen as GL_LIGHT0

        // Light color component
        light->setAmbient (osg::Vec4(0.1f,   0.1f,  0.1f, 1.0f)); // ambient 
component (it should be almost dark)
        light->setDiffuse (osg::Vec4(0.8f,   0.8f,  0.8f, 1.0f)); // diffuse 
component (it should be quite brilliant)
        light->setSpecular(osg::Vec4(0.95f, 0.95f, 0.95f, 1.0f)); // specular 
component (it should be the brightest component)

        // Light position and direction (no spot => directional light)
        light->setPosition (osg::Vec4(-1.5f, -1.0f, +1.5f, 0.0f)); // in the 
upper left corner of the screen (last value,
                                                                                
                                           // 0.0, means directional light)
        light->setDirection(osg::Vec3(+0.5f, +1.0f, -0.5f)); // looking towards 
the upper left corner of the rectangle

        // Add the light to a Light source and return that light source.
        osg::ref_ptr<osg::LightSource> lightsource = new osg::LightSource;
        lightsource->setLight( light.get() );
        return osg::ref_ptr<osg::LightSource>(lightsource.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::LightSource> createSpotLightSource()
{
        // Create a white spot light, used as LIGHT 1 in the scene
        osg::ref_ptr<osg::Light> light = new osg::Light;

        light->setLightNum(1); // so this light source is seen as GL_LIGHT1

        // Light color component
        light->setAmbient (osg::Vec4(0.1f,   0.1f,  0.1f, 1.0f)); // ambient 
component (it should be almost dark)
        light->setDiffuse (osg::Vec4(0.8f,   0.8f,  0.8f, 1.0f)); // diffuse 
component (it should be quite brilliant)
        light->setSpecular(osg::Vec4(0.95f, 0.95f, 0.95f, 1.0f)); // specular 
component (it should be the brightest component)

        // Light position, direction and spot cutoff (spot light)
        light->setPosition (osg::Vec4(+1.5f, -1.0f, -1.5f, 1.0f)); // in the 
lower right corner of the screen (last value,
                                                                                
                                           // not 0.0, means spot light)
        light->setDirection(osg::Vec3(-0.5f, +1.0f, +0.5f)); // looking towards 
the lower right corner of the rectangle
        light->setSpotCutoff(60.0f); // spot in degrees

        // Add the light to a Light source and return that light source.
        osg::ref_ptr<osg::LightSource> lightsource = new osg::LightSource;
        lightsource->setLight( light.get() );
        return osg::ref_ptr<osg::LightSource>(lightsource.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::Node> CreateSceneGraph()
{
        // Build the scene graph, and return it in a node

        // Create the root node, and enables lighting for the whole graph
        osg::ref_ptr<osg::Group> root = new osg::Group;
        if (!root.valid())
                osg::notify(osg::FATAL) << "Failed in creating root." << endl;
        root->setName("root node");
        root->setDataVariance(osg::Object::STATIC); // root node won't be 
changed at all!
        osg::StateSet *rootState = root->getOrCreateStateSet();
        rootState->setMode(GL_LIGHTING, osg::StateAttribute::ON); // enable 
lighting
        rootState->setMode(GL_LIGHT0, osg::StateAttribute::ON); // turn ON 
light 0
        rootState->setMode(GL_LIGHT1, osg::StateAttribute::ON); // turn ON 
light 1

        osg::Matrix m; // a matrix will be used later for transforming the nodes

        // 1) Create transformation matrix 1, which affects background rectangle
        osg::ref_ptr<osg::MatrixTransform> mt1 = new osg::MatrixTransform;
        if (!mt1.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 1." << endl;
        mt1->setName("transformation matrix 1");
        mt1->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 1 might be changed
                                                                                
                // (in its associated state set) during update traversal
        m.makeTranslate(0.f, 0.f, 0.f); // no transformation at all!!!
        mt1->setMatrix(m);
        osg::StateSet *bg_state = mt1->getOrCreateStateSet();
        osg::ref_ptr<osg::Material> bg_mat = new osg::Material;
        bg_mat->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.40f, 0.30f, 
0.0f, 1.0f) ); // dark-orange
        bg_mat->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.35f, 0.25f, 
0.0f, 1.0f) ); // dark-orange
        bg_mat->setSpecular ( osg::Material::FRONT, osg::Vec4(1.00f, 1.00f, 
1.0f, 1.0f) ); // bright-white
        bg_mat->setShininess( osg::Material::FRONT, 56.f );
        bg_state->setAttribute(bg_mat.get());
        root->addChild(mt1.get()); // now transformation matrix 1 is attached 
to the root

        // 1.1) Create the geode representing the background rectangle, and 
attach it to the
        //      transformation matrix 1
        osg::ref_ptr<osg::Node> back_rect = createRectangle();
        if (!back_rect.valid())
                osg::notify(osg::FATAL) << "Failed in creating the background 
rectangle." << endl;
        back_rect->setName("background rectangle");
        back_rect->setDataVariance(osg::Object::STATIC); // background 
rectangle node won't be changed at all
                                                                                
                         // (in fact its material properties are changed only
                                                                                
                         // in the transformation matrix that it is attached to!
        mt1->addChild(back_rect.get()); // now the geode (background rectangle) 
is attached to the transformation matrix 1

        // 2) Create the sphere group, enabling color material for it 
        osg::ref_ptr<osg::Group> sphere_group = new osg::Group;
        if (!sphere_group.valid())
                osg::notify(osg::FATAL) << "Failed in creating sphere group." 
<< endl;
        sphere_group->setName("sphere group");
        sphere_group->setDataVariance(osg::Object::STATIC); // sphere group 
node won't be changed at all!
        osg::StateSet *sphereGroupState = sphere_group->getOrCreateStateSet();
        osg::ref_ptr<osg::Material> sphere_mat = new osg::Material;
        sphere_mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
        sphereGroupState->setAttribute(sphere_mat.get()); // enable color 
material: HOW DO WE CHANGE THE PRIMARY COLOR FROM OSG?
        root->addChild(sphere_group.get()); // now sphere group is attached to 
the root

        // 2.1) Create transformation matrix 2, to place one sphere in the 
upper left angle of the rectangle
        //      (also specify the ambient and diffuse color reflected by that 
sphere)
        osg::ref_ptr<osg::MatrixTransform> mt2 = new osg::MatrixTransform;
        if (!mt2.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 2." << endl;
        mt2->setName("transformation matrix 2");
        mt2->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 2 might be changed
                                                                                
                // (in its associated state set) during update traversal
        m.makeTranslate(-0.5f, -0.15f, +0.5f); // upper-left corner of the 
rectangle
        mt2->setMatrix(m);
        osg::StateSet *sphereState1 = mt2->getOrCreateStateSet();
        osg::ref_ptr<osg::ShadeModel> shade_model = new 
osg::ShadeModel(osg::ShadeModel::FLAT);
        sphereState1->setAttribute(shade_model.get());
        // glColor3f(0.8f, 0.7f, 0.2f); WHAT IS THE COMMAND TO DO THAT FROM OSG 
(IF THERE IS)?
        osg::ref_ptr<osg::Material> spheremat1 = new osg::Material;
        spheremat1->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.9f, 0.1f, 
0.1f, 1.0f) ); // light-red
        spheremat1->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.9f, 0.1f, 
0.1f, 1.0f) ); // light-red
        spheremat1->setSpecular ( osg::Material::FRONT, osg::Vec4(0.9f, 0.9f, 
0.9f, 1.0f) ); // light-white
        spheremat1->setShininess( osg::Material::FRONT, 16.f );
        sphereState1->setAttribute(spheremat1.get());
        sphere_group->addChild(mt2.get()); // now transformation matrix 2 is 
attached to the sphere group

        // 2.2) Create transformation matrix 3, to place one sphere in the 
upper right angle of the rectangle
        //      (also specify the ambient and diffuse color reflected by that 
sphere)
        osg::ref_ptr<osg::MatrixTransform> mt3 = new osg::MatrixTransform;
        if (!mt3.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 3." << endl;
        mt3->setName("transformation matrix 3");
        mt3->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 3 might be changed
                                                                                
                // (in its associated state set) during update traversal
        m.makeTranslate(+0.5f, -0.15f, +0.5f); // upper-right corner of the 
rectangle
        mt3->setMatrix(m);
        osg::StateSet *sphereState2 = mt3->getOrCreateStateSet();
        osg::ref_ptr<osg::ShadeModel> shade_model2 = new 
osg::ShadeModel(osg::ShadeModel::SMOOTH);
        sphereState2->setAttribute(shade_model2.get());
        // glColor3f(0.8f, 0.7f, 0.2f); WHAT IS THE COMMAND TO DO THAT FROM OSG 
(IF THERE IS)?
        osg::ref_ptr<osg::Material> spheremat2 = new osg::Material;
        spheremat2->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.1f, 0.9f, 
0.1f, 1.0f) ); // light-green
        spheremat2->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.1f, 0.9f, 
0.1f, 1.0f) ); // light-green
        spheremat2->setSpecular ( osg::Material::FRONT, osg::Vec4(0.9f, 0.9f, 
0.9f, 1.0f) ); // light-white
        spheremat2->setShininess( osg::Material::FRONT, 8.f );
        sphereState2->setAttribute(spheremat2.get());
        sphere_group->addChild(mt3.get()); // now transformation matrix 3 is 
attached to the sphere group

        // 2.3) Create transformation matrix 4, to place one sphere in the 
lower left angle of the rectangle
        //      (also specify the ambient and diffuse color reflected by that 
sphere)
        osg::ref_ptr<osg::MatrixTransform> mt4 = new osg::MatrixTransform;
        if (!mt4.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 4." << endl;
        mt4->setName("transformation matrix 4");
        mt4->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 4 might be changed
                                                                                
                // (in its associated state set) during update traversal
        m.makeTranslate(-0.5f, -0.15f, -0.5f); // lower-left corner of the 
rectangle
        mt4->setMatrix(m);
        
        osg::StateSet *sphereState3 = mt4->getOrCreateStateSet();
        // glColor3f(0.8f, 0.7f, 0.2f); WHAT IS THE COMMAND TO DO THAT FROM OSG 
(IF THERE IS)?
        osg::ref_ptr<osg::Material> spheremat3 = new osg::Material;
        spheremat3->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.1f, 0.7f, 
0.9f, 1.0f) ); // light-blue
        spheremat3->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.1f, 0.7f, 
0.9f, 1.0f) ); // light-blue
        spheremat3->setSpecular ( osg::Material::FRONT, osg::Vec4(0.9f, 0.9f, 
0.9f, 1.0f) ); // light-white
        spheremat3->setShininess( osg::Material::FRONT, 28.f );
        sphereState3->setAttribute(spheremat3.get());
        sphere_group->addChild(mt4.get()); // now transformation matrix 4 is 
attached to the sphere group

        // 2.4) Create transformation matrix 5, to place one sphere in the 
lower right angle of the rectangle
        //      (also specify the ambient and diffuse color reflected by that 
sphere)
        osg::ref_ptr<osg::MatrixTransform> mt5 = new osg::MatrixTransform;
        if (!mt5.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 5." << endl;
        mt5->setName("transformation matrix 5");
        mt5->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 5 might be changed
                                                                                
                // (in its associated state set) during update traversal
        m.makeTranslate(+0.5f, -0.15f, -0.5f); // lower-right corner of the 
rectangle
        mt5->setMatrix(m);
        osg::StateSet *sphereState4 = mt5->getOrCreateStateSet();
        // glColor3f(0.8f, 0.7f, 0.2f); WHAT IS THE COMMAND TO DO THAT FROM OSG 
(IF THERE IS)?
        osg::ref_ptr<osg::Material> spheremat4 = new osg::Material;
        spheremat4->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.8f, 0.1f, 
0.9f, 1.0f) ); // light-magenta
        spheremat4->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.8f, 0.1f, 
0.9f, 1.0f) ); // light-magenta
        spheremat4->setSpecular ( osg::Material::FRONT, osg::Vec4(0.9f, 0.9f, 
0.9f, 1.0f) ); // light-white
        spheremat4->setShininess( osg::Material::FRONT, 64.f );
        sphereState4->setAttribute(spheremat4.get());
        sphere_group->addChild(mt5.get()); // now transformation matrix 5 is 
attached to the sphere group

        // 2.5) Finally create the geode to represent the sphere being drawn in 
the 4 different angles of
        //      the background rectangle, and add it as a child to the 4 
transformation matrices just attached to the sphere group
        osg::ref_ptr<osg::Node> sphere = createSphere();
        if (!sphere.valid())
                osg::notify(osg::FATAL) << "Failed in creating sphere." << endl;
        sphere->setName("sphere");
        sphere->setDataVariance(osg::Object::STATIC); // sphere node won't be 
changed at all!
        mt2->addChild(sphere.get()); // now the sphere is attached to the 
transformation matrix 2
        mt3->addChild(sphere.get()); // now the sphere is attached to the 
transformation matrix 3
        mt4->addChild(sphere.get()); // now the sphere is attached to the 
transformation matrix 4
        mt5->addChild(sphere.get()); // now the sphere is attached to the 
transformation matrix 5

        // 3) Create transformation matrix 6, to transform the light source 1
        osg::ref_ptr<osg::MatrixTransform> mt6 = new osg::MatrixTransform;
        if (!mt6.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 6." << endl;
        mt6->setName("transformation matrix 6");
        mt6->setDataVariance(osg::Object::STATIC); // transformation matrix 6 
node won't be changed at all!
        m.makeTranslate(0.f, 0.f, 0.f); // no transformation at all, since the 
light already has a position and direction!!!
        mt6->setMatrix(m);
        mt6->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // the light is 
fixed in the scene
        root->addChild(mt6.get()); // now transformation matrix 6 is attached 
to the root

        // 3.1) Create the light source, and attach it to the transformation 
matrix 6
        osg::ref_ptr<osg::LightSource> lightsrc1 = 
createDirectionalLightSource();
        if (!lightsrc1.valid())
                osg::notify(osg::FATAL) << "Failed in creating light source 1." 
<< endl;
        lightsrc1->setName("light source 1");
        lightsrc1->setDataVariance(osg::Object::STATIC); // light source 1 node 
won't be changed at all!
        mt6->addChild(lightsrc1.get()); // now the light source 1 is attached 
to the transformation matrix 6

        // 4) Create transformation matrix 7, to transform the light source 2
        osg::ref_ptr<osg::MatrixTransform> mt7 = new osg::MatrixTransform;
        if (!mt7.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 7." << endl;
        mt7->setName("transformation matrix 7");
        mt7->setDataVariance(osg::Object::STATIC); // transformation matrix 7 
node won't be changed at all!
        m.makeTranslate(0.f, 0.f, 0.f); // no transformation at all, since the 
light already has a position and direction!!!
        mt7->setMatrix(m);
        root->addChild(mt7.get()); // now transformation matrix 7 is attached 
to the root

        // 4.1) Create the light source, and attach it to the transformation 
matrix 7
        osg::ref_ptr<osg::LightSource> lightsrc2 = createSpotLightSource();
        if (!lightsrc2.valid())
                osg::notify(osg::FATAL) << "Failed in creating light source 2." 
<< endl;
        lightsrc2->setName("light source 2");
        lightsrc2->setDataVariance(osg::Object::STATIC); // light source 2 node 
won't be changed at all!
        mt7->addChild(lightsrc2.get()); // now the light source 2 is attached 
to the transformation matrix 7

        // 5) Create transformation matrix 8, to place the box representing the 
spot light source
        osg::ref_ptr<osg::MatrixTransform> mt8 = new osg::MatrixTransform;
        if (!mt8.valid())
                osg::notify(osg::FATAL) << "Failed in creating transformation 
matrix 8." << endl;
        mt8->setName("transformation matrix 8");
        mt8->setDataVariance(osg::Object::DYNAMIC); // Actually transformation 
matrix 8 might be changed
                                                                                
                // (in its associated state set) during update traversal
        osg::Matrix rot; // a matrix to rotate the box along its direction
        rot.makeRotate(osg::Vec3(+1.0, 0.0, 0.0), osg::Vec3(-0.5f, +1.0f, 
+0.5f));
        m.makeTranslate(osg::Vec3(+1.5f, -1.0f, -1.5f)); // position of the 
light source
        mt8->setMatrix(rot*m);
        osg::StateSet *boxState = mt8->getOrCreateStateSet();
        // glColor3f(0.8f, 0.7f, 0.2f); WHAT IS THE COMMAND TO DO THAT FROM OSG 
(IF THERE IS)?
        osg::ref_ptr<osg::Material> box_mat = new osg::Material;
        box_mat->setDiffuse  ( osg::Material::FRONT, osg::Vec4(0.8f, 0.5f, 
0.1f, 1.0f) ); // light-orange
        box_mat->setAmbient  ( osg::Material::FRONT, osg::Vec4(0.8f, 0.5f, 
0.1f, 1.0f) ); // light-orange
        box_mat->setSpecular ( osg::Material::FRONT, osg::Vec4(0.9f, 0.9f, 
0.9f, 1.0f) ); // light-white
        box_mat->setShininess( osg::Material::FRONT, 12.f );
        boxState->setAttribute(box_mat.get());
        root->addChild(mt8.get()); // now transformation matrix 8 is attached 
to the root

        // 5.1) Finally create the geode to represent the box being drawn to 
show the position of the
        //      spot light source
        osg::ref_ptr<osg::Node> box = createBox();
        if (!box.valid())
                osg::notify(osg::FATAL) << "Failed in creating light box." << 
endl;
        box->setName("box");
        box->setDataVariance(osg::Object::STATIC); // box node won't be changed 
at all!
        mt8->addChild(box.get()); // now the box is attached to the 
transformation matrix 8

        // Finally return the whole scene graph
        return osg::ref_ptr<osg::Node>(root.get());
}

///////////////////////////////////////////////////////////////////////////////////////////
// PickHandler -- A GUIEventHandler that implements picking.
class PickHandler : public osgGA::GUIEventHandler
{
public:
        PickHandler() : _mX( 0. ),_mY( 0. ), _selectedNode(0) {}
        
        bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& 
aa )
        {
                osgViewer::Viewer* viewer =
                dynamic_cast<osgViewer::Viewer*>( &aa );
                if (!viewer)
                        return false;
                switch( ea.getEventType() )
                {
                        case osgGA::GUIEventAdapter::PUSH:
                        case osgGA::GUIEventAdapter::MOVE:
                        {
                                // Record mouse location for the button press
                                // and move events.
                                _mX = ea.getX();
                                _mY = ea.getY();
                                return false;
                        }

                        case osgGA::GUIEventAdapter::RELEASE:
                        {
                                // If the mouse hasn't moved since the last 
button press or move event, perform a
                                // pick. (Otherwise, the trackball manipulator 
will handle it.)
                                if (_mX == ea.getX() && _mY == ea.getY())
                                {
                                        if (pick( ea.getXnormalized(), 
ea.getYnormalized(), viewer ))
                                                return true;
                                }
                                return false;
                        }
                        default:
                                return false;
                }
        }

protected:
        // Store mouse xy location for button press & move events.
        float _mX,_mY;
        osg::Node *_selectedNode;

        // Perform a pick operation.
        bool pick( const double x, const double y, osgViewer::Viewer* viewer )
        {
                if (!viewer->getSceneData()) // Nothing to pick.
                        return false;
                double w( .05 ), h( .05 );
                osgUtil::PolytopeIntersector* picker = 
                        new 
osgUtil::PolytopeIntersector(osgUtil::Intersector::PROJECTION,
                                                                                
         x-w, y-h, x+w, y+h);
                osgUtil::IntersectionVisitor iv( picker );
                viewer->getCamera()->accept( iv );
                if (picker->containsIntersections())
                {
                        osgUtil::PolytopeIntersector::Intersections 
intersections = picker->getIntersections();
                        osgUtil::PolytopeIntersector::Intersections::iterator 
intersection_iter = intersections.begin();
                        osgUtil::PolytopeIntersector::Intersection 
closestIntersection = *intersection_iter;
                        for (;intersection_iter != intersections.end(); 
intersection_iter++)
                                if (*intersection_iter < closestIntersection)
                                        closestIntersection = 
*intersection_iter;

                        osg::NodePath& nodePath = 
/*picker->getFirstIntersection()*/closestIntersection.nodePath;
                        unsigned int idx = nodePath.size();
                        while (idx--)
                        {
                                // Find the LAST MatrixTransform in the node
                                // path; this will be the MatrixTransform
                                // to attach our callback to.
                                osg::MatrixTransform* mt =
                                dynamic_cast<osg::MatrixTransform*>(nodePath[ 
idx ] );
                                if (mt == NULL)
                                        continue;
                
                                // If we get here, we just found a
                                // MatrixTransform in the nodePath.
                                if (_selectedNode)
                                // Clear the previous selected node's
                                // callback to make it stop spinning.
                                        _selectedNode->setUpdateCallback( NULL 
);
                                _selectedNode = mt;
                                _selectedNode->setUpdateCallback( new 
ChangeColorCB(osg::Vec4(1.0, 1.0, 0.0, 1.0)) );
                                break;
                        }
                        if (!_selectedNode)
                                osg::notify() << "Pick failed." << std::endl;
                }
                else if (_selectedNode)
                {
                        _selectedNode->setUpdateCallback( NULL );
                        _selectedNode = NULL;
                }
                return (_selectedNode != 0);
        }
};

/////////////////////////////////////////////////////////////////////////////////////////
int main( int argc, char **argv )
{
        osgViewer::Viewer viewer;
        
        // Set the background color
        viewer.getCamera()->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0)); // 
black background

        // Set the scene graph to draw in each frame
        osg::ref_ptr<osg::Node> root = CreateSceneGraph();
        viewer.setSceneData(root.get());

        // Set projection 
        viewer.getCamera()->setProjectionMatrixAsPerspective(40., 1., 1., 100.);

        // Create a matrix to specify a distance from the viewpoint.
        osg::Matrix trans;
        trans.makeTranslate( 0., 0., -6. );

        const float DEG_TO_RAD = 3.1415926535897932384626433832795f / 180.0f; 
// so that rad = DEG_TO_RAD * deg
        // Rotation angle (in radians)
        double angle( -90.0f * DEG_TO_RAD ); // WHY -90.0? Because we want to 
show the whole rectangle object (GE1),
                                                                                
 //            at startup, with its normal directed towards the user.
                                                                                
 //            But the default OpenGL camera position is in (0,0,0),
                                                                                
 //                        and directed this way:
                                             //
                                             //                 y |             
       z |  
                                             //                   |             
-90      | / y
                                             //                   |            
=====>    |/
                                             //                   *------- x    
         *------- x
                                             //                  /
                                             //                 /
                                             //              z /
                                             //
                                             //            Instead the main 
rectangle (GE1) is defined in the plane x-z.
                                             //            So, a 
counterclockwise rotation around x-axis by -90 degrees
                                             //            will show the front 
face of the rectangle GE1 at startup!

        // Add the pick handler to the viewer
        viewer.addEventHandler( new PickHandler );

        // Perform the main loop, until the user press 'Esc' to exit the program
        while (!viewer.done())
        {
                // Create the rotation matrix.
                osg::Matrix rot;
                rot.makeRotate( angle, osg::Vec3( 1., 0., 0. ) ); // 
counterclockwise rotation
                angle += 0.01;
                // Set the view matrix (the concatenation of the rotation and
                // translation matrices).
                viewer.getCamera()->setViewMatrix( rot * trans );
                // Draw the next frame.
                viewer.frame();
        }       
        return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to