Hi Robert,

For my usage of computeIntersections, as I said, I put the test scene into the osgpick example. From there it is quite clear that the picking results do not return what I believe most people will expect for that scene. I was aware that the computeIntersections method is a wrapper for the IntersectionVisitor class, but this class shows the same symptoms when used directly. My intention was to give the most condensed example of the problem in the hope the people would clearly understand the scenario that I think is misbehaving. Ho hum. ;-)

So, I decided to put my miners helmet on and deleve into the subterranean depths of the osg machine. I think I have discovered that something is missing from 'IntersectionVisitor::accept(Camera&)' because is makes the assumption that all cameras have an absolute coordinate frame. This is an assumption that neither PickVisitor::appy(Camera&) or CullVisitor::apply(Camera&) makes. So I have merged the relevant code from CullVistor into IntersectionVisitor and this now seems to function correctly.

Please can you check the attached file with changes appied to IntersectionVisitor.cpp (from osg 2.6).
[Also posted to submissions list]

Chris.


Date: Sun, 26 Oct 2008 15:53:19 +0000
From: "Robert Osfield" <[EMAIL PROTECTED]>
Subject: Re: [osg-users] Problem with computeIntersections for nodes
below post render camera.
To: "OpenSceneGraph Users" <[EMAIL PROTECTED]>
Message-ID:
<[EMAIL PROTECTED]>
Content-Type: text/plain; charset=ISO-8859-1

Hi Chris,

There isn't enough info about how you are calling computeIntersections
to really know what is going on - there are several
computeIntersections methods, so I can't say whether it's a bug, or
code misuse.

As a general note, the computeIntersections methods are just
convenience methods for the most common needs, but they are just
implemented on top the general purpose
IntersectionVisitor/*Intersector classes.  These classes aren't
difficult to use so you just implement your work on these.

Robert.

On Sun, Oct 26, 2008 at 10:28 AM, Chris Denham <[EMAIL PROTECTED]> wrote:
I have a problem with Viewer:computeIntersections for nodes below a subgraph rendering camera that doesn't have the ABSOLUTE_RF reference frame. In fact, computeIntersections results are exactly as though an ABSOLUTE_RF has been set on the camera, even though it has not. The code below creates a simple scene the exhibits the problem. I used this in the osgpick example to show
computed intersections.
Is this a bug, or is this to be expected? If it is to be expected, how can I
get picking to work for nodes below my post render camera?
Chris.

 osg::Group* group = new osg::Group();

 osg::Geode* sphere = new osg::Geode();
 sphere->setName("Sphere");
 sphere->addDrawable(new osg::ShapeDrawable(new osg::Sphere()));

 osg::Geode* cube = new osg::Geode();
 cube->setName("Cube");
 cube->addDrawable(new osg::ShapeDrawable(new osg::Box()));

 osg::Camera* camera = new osg::Camera();
 camera->setRenderOrder(osg::Camera::POST_RENDER);
 camera->setClearMask(GL_DEPTH_BUFFER_BIT);
 //camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);

 group->addChild(sphere);
 group->addChild(camera);
 camera->addChild(cube);
_______________________________________________
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
* * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details.
*/


#include <osgUtil/IntersectionVisitor>

#include <osg/PagedLOD>
#include <osg/Transform>
#include <osg/Projection>
#include <osg/Camera>
#include <osg/Geode>
#include <osg/Billboard>
#include <osg/Geometry>
#include <osg/Notify>
#include <osg/io_utils>

using namespace osgUtil;


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  IntersectorGroup
//

IntersectorGroup::IntersectorGroup()
{
}

void IntersectorGroup::addIntersector(Intersector* intersector)
{
   _intersectors.push_back(intersector);
}

void IntersectorGroup::clear()
{
   _intersectors.clear();
}

Intersector* IntersectorGroup::clone(osgUtil::IntersectionVisitor& iv)
{
   IntersectorGroup* ig = new IntersectorGroup;
// now copy across all intersectors that arn't disabled.
   for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       if (!(*itr)->disabled())
       {
           ig->addIntersector( (*itr)->clone(iv) );
       }
   }

   return ig;
}

bool IntersectorGroup::enter(const osg::Node& node)
{
   if (disabled()) return false;
bool foundIntersections = false; for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       if ((*itr)->disabled()) (*itr)->incrementDisabledCount();
       else if ((*itr)->enter(node)) foundIntersections = true;
       else (*itr)->incrementDisabledCount();
   }
if (!foundIntersections) {
       // need to call leave to clean up the DisabledCount's.
       leave();
       return false;
   }
// we have found at least one suitable intersector, so return true
   return true;
}

void IntersectorGroup::leave()
{
   for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       if ((*itr)->disabled()) (*itr)->decrementDisabledCount();
   }
}

void IntersectorGroup::intersect(osgUtil::IntersectionVisitor& iv, 
osg::Drawable* drawable)
{
   if (disabled()) return;

   unsigned int numTested = 0;
   for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       if (!(*itr)->disabled())
       {
           (*itr)->intersect(iv, drawable);
++numTested;
       }
   }
// osg::notify(osg::NOTICE)<<"Number testing "<<numTested<<std::endl;

}

void IntersectorGroup::reset()
{
   Intersector::reset();
for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       (*itr)->reset();
   }
}

bool IntersectorGroup::containsIntersections()
{
   for(Intersectors::iterator itr = _intersectors.begin();
       itr != _intersectors.end();
       ++itr)
   {
       if ((*itr)->containsIntersections()) return true;
   }
   return false;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  IntersectionVisitor
//

IntersectionVisitor::IntersectionVisitor(Intersector* intersector, 
ReadCallback* readCallback)
{
   // override the default node visitor mode.
   setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
_useKdTreesWhenAvailable = true;
   _dummyTraversal = false;

   setIntersector(intersector);
setReadCallback(readCallback);
}

void IntersectionVisitor::setIntersector(Intersector* intersector)
{
   // keep reference around just in case intersector is already in the 
_intersectorStack, otherwise the clear could delete it.
   osg::ref_ptr<Intersector> temp = intersector;

   _intersectorStack.clear();

   if (intersector) _intersectorStack.push_back(intersector);
}

void IntersectionVisitor::reset()
{
   if (!_intersectorStack.empty())
   {
       osg::ref_ptr<Intersector> intersector = _intersectorStack.front();
       intersector->reset();
_intersectorStack.clear();
       _intersectorStack.push_back(intersector);
   }
}

void IntersectionVisitor::apply(osg::Node& node)
{
   // osg::notify(osg::NOTICE)<<"apply(Node&)"<<std::endl;

   if (!enter(node)) return;

   // osg::notify(osg::NOTICE)<<"inside apply(Node&)"<<std::endl;

   traverse(node);

   leave();
}

void IntersectionVisitor::apply(osg::Group& group)
{
   if (!enter(group)) return;

   traverse(group);

   leave();
}

void IntersectionVisitor::apply(osg::Geode& geode)
{
   // osg::notify(osg::NOTICE)<<"apply(Geode&)"<<std::endl;

   if (!enter(geode)) return;

   // osg::notify(osg::NOTICE)<<"inside apply(Geode&)"<<std::endl;

   for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
   {
       intersect( geode.getDrawable(i) );
   }

   leave();
}

void IntersectionVisitor::apply(osg::Billboard& billboard)
{
   if (!enter(billboard)) return;

   for(unsigned int i=0; i<billboard.getNumDrawables(); ++i)
   {
       intersect( billboard.getDrawable(i) );
   }

   leave();
}

void IntersectionVisitor::apply(osg::LOD& lod)
{
   if (!enter(lod)) return;

   traverse(lod);

   leave();
}


void IntersectionVisitor::apply(osg::PagedLOD& plod)
{
   if (!enter(plod)) return;

   if (plod.getNumFileNames()>0)
   {
#if 1
       // Identify the range value for the highest res child
       float targetRangeValue;
       if( plod.getRangeMode() == osg::LOD::DISTANCE_FROM_EYE_POINT )
           targetRangeValue = 1e6; // Init high to find min value
       else
           targetRangeValue = 0; // Init low to find max value
const osg::LOD::RangeList rl = plod.getRangeList();
       osg::LOD::RangeList::const_iterator rit;
       for( rit = rl.begin();
            rit != rl.end();
            rit++ )
       {
           if( plod.getRangeMode() == osg::LOD::DISTANCE_FROM_EYE_POINT )
           {
               if( rit->first < targetRangeValue )
                   targetRangeValue = rit->first;
           }
           else
           {
               if( rit->first > targetRangeValue )
                   targetRangeValue = rit->first;
           }
       }

       // Perform an intersection test only on children that display
       // at the maximum resolution.
       unsigned int childIndex;
       for( rit = rl.begin(), childIndex = 0;
            rit != rl.end();
            rit++, childIndex++ )
       {
           if( rit->first != targetRangeValue )
               // This is not one of the highest res children
               continue;

           osg::ref_ptr<osg::Node> child( NULL );
           if( plod.getNumChildren() > childIndex )
               child = plod.getChild( childIndex );

           if( (!child.valid()) && (_readCallback.valid()) )
           {
               // Child is NULL; attempt to load it, if we have a 
readCallback...
               unsigned int validIndex( childIndex );
               if (plod.getNumFileNames() <= childIndex)
                   validIndex = plod.getNumFileNames()-1;

               child = _readCallback->readNodeFile( plod.getDatabasePath() + 
plod.getFileName( validIndex ) );
           }

           if ( !child.valid() && plod.getNumChildren()>0)
           {
               // Child is still NULL, so just use the one at the end of the 
list.
               child = plod.getChild( plod.getNumChildren()-1 );
           }

           if (child.valid())
           {
               child->accept(*this);
           }
       }
#else // older code than above block, that assumes that the PagedLOD is ordered correctly
       // i.e. low res children first, no duplicate ranges.
osg::ref_ptr<osg::Node> highestResChild;

       if (plod.getNumFileNames() != plod.getNumChildren() && 
_readCallback.valid())
       {
           highestResChild = _readCallback->readNodeFile( 
plod.getDatabasePath() + plod.getFileName(plod.getNumFileNames()-1) );
       }
if ( !highestResChild.valid() && plod.getNumChildren()>0)
       {
           highestResChild = plod.getChild( plod.getNumChildren()-1 );
       }

       if (highestResChild.valid())
       {
           highestResChild->accept(*this);
       }
#endif
   }

   leave();
}


void IntersectionVisitor::apply(osg::Transform& transform)
{
   if (!enter(transform)) return;

   osg::ref_ptr<osg::RefMatrix> matrix = _modelStack.empty() ? new 
osg::RefMatrix() : new osg::RefMatrix(*_modelStack.back());
   transform.computeLocalToWorldMatrix(*matrix,this);

   pushModelMatrix(matrix.get());

   // now push an new intersector clone transform to the new local coordinates
   push_clone();

   traverse(transform);
// pop the clone.
   pop_clone();
popModelMatrix();

   // tidy up an cached cull variables in the current intersector.
   leave();
}


void IntersectionVisitor::apply(osg::Projection& projection)
{
   if (!enter(projection)) return;

   pushProjectionMatrix(new osg::RefMatrix(projection.getMatrix()) );

   // now push an new intersector clone transform to the new local coordinates
   push_clone();

   traverse(projection);
// pop the clone.
   pop_clone();
popProjectionMatrix();

   leave();
}


void IntersectionVisitor::apply(osg::Camera& camera)
{
   // osg::notify(osg::NOTICE)<<"apply(Camera&)"<<std::endl;

   // note, commenting out right now because default Camera setup is with the 
culling active.  Should this be changed?
   // if (!enter(camera)) return;
// osg::notify(osg::NOTICE)<<"inside apply(Camera&)"<<std::endl;

   osg::RefMatrix* projection = NULL;
   osg::RefMatrix* view = NULL;

   if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF && getProjectionMatrix() 
&& getViewMatrix())
   {
       if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY)
       {
           projection = new 
osg::RefMatrix(*getProjectionMatrix()*camera.getProjectionMatrix());
           view = new osg::RefMatrix(*getViewMatrix()*camera.getViewMatrix());
       }
else // pre multiply {
           projection = new 
osg::RefMatrix(camera.getProjectionMatrix()*(*getProjectionMatrix()));
           view = new osg::RefMatrix(camera.getViewMatrix()*(*getViewMatrix()));
       }
   } else {
       // an absolute reference frame
       projection = new osg::RefMatrix(camera.getProjectionMatrix());
       view = new osg::RefMatrix(camera.getViewMatrix());
   }

   if (camera.getViewport()) pushWindowMatrix( camera.getViewport() );
   pushProjectionMatrix(projection);
   pushViewMatrix(view);
   pushModelMatrix( new osg::RefMatrix() );

   // now push an new intersector clone transform to the new local coordinates
   push_clone();

   traverse(camera);
// pop the clone.
   pop_clone();
popModelMatrix();
   popViewMatrix();
   popProjectionMatrix();
   if (camera.getViewport()) popWindowMatrix();

   // leave();
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to