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