Now, a conclusion on this thread: here is how I solved that issue: I'm
"registering" all the cameras where I have contain to intersect with, and
then I take them one by one to perform an intersection test, but you need to
modify the view amtrix, projection matrix and viewport (using those from the
main camera), and then I use a modified IntersectionVisitor to "correct" the
projection matrix before entering a camera. So here it the most important
code parts if someone is interested in introducing that in the core OSG libs
one day (sorry I'm really late on my job, so I don't have time for a
submission right now :-( ).
main function to do some intersection tests:
bool Tools::handleViewIntersections(osgViewer::View * view, double x, double
y)
{
// Bouml preserved body begin 00043B04
if(!view) {
vLog::logError("invalid view object in
tools::handleViewIntersections()");
return false;
}
osgUtil::LineSegmentIntersector::Intersections hits;
float local_x, local_y = 0.0;
view->getCameraContainingPosition(x, y, local_x, local_y);
osg::Camera* camera = view->getCamera();
osg::Matrixd pm,vm;
osg::ref_ptr<osg::Viewport> vp;
osgUtil::LineSegmentIntersector::CoordinateFrame cf =
camera->getViewport() ? osgUtil::Intersector::WINDOW :
osgUtil::Intersector::PROJECTION;
osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new
osgUtil::LineSegmentIntersector(cf, local_x, local_y);
vDisplay::DisplayManager::CameraDeq& cams =
vDisplay::DisplayManager::getRegisteredCameras(view);
for(vDisplay::DisplayManager::CameraDeq::iterator it = cams.begin(); it
!= cams.end(); ++it) {
//osgUtil::IntersectionVisitor iv(picker.get());
vOGL::ExtendedIntersectionVisitor iv(picker.get());
iv.setFrameStamp(vDisplay::DisplayManager::getViewer()->getFrameStamp());
iv.setTraversalMask(vOGL::PICKABLE);
vm = (*it)->getViewMatrix();
pm = (*it)->getProjectionMatrix();
vp = (*it)->getViewport();
(*it)->setViewMatrix(camera->getViewMatrix());
(*it)->setProjectionMatrix(camera->getProjectionMatrix());
(*it)->setViewport(camera->getViewport());
(*it)->accept(iv);
(*it)->setViewMatrix(vm);
(*it)->setProjectionMatrix(pm);
(*it)->setViewport(vp.get());
if (picker->containsIntersections())
{
hits = picker->getIntersections();
vLog::logInfo("Got %d intersections",hits.size());
return true;
}
}
vLog::logInfo("Got 0 intersections");
return false;
// Bouml preserved body end 00043B04
}
the modified function in my ExtendedIntersectionVisitor:
void ExtendedIntersectionVisitor::apply(osg::Camera & camera) {
// Bouml preserved body begin 00043C84
// Use a simplified cull traversal here to correct the projection:
osg::RenderInfo _renderInfo;
_renderInfo.setState(new osg::State);
_renderInfo.setView(camera.getView());
osg::ref_ptr<osgUtil::CullVisitor> cv = osgUtil::CullVisitor::create();
cv->setTraversalMask(getTraversalMask()); // Use the same mask to
retrieve the good extend of the pickable objects.
osg::ref_ptr<osgUtil::RenderStage> renderStage = new
osgUtil::RenderStage();
osg::ref_ptr<osgUtil::StateGraph> rendergraph = new
osgUtil::StateGraph();
cv->setStateGraph(rendergraph.get());
cv->setRenderStage(renderStage.get());
cv->reset();
cv->setFrameStamp(const_cast<osg::FrameStamp*>(getFrameStamp()));
if (getFrameStamp())
{
cv->setTraversalNumber(getFrameStamp()->getFrameNumber());
}
//cv->inheritCullSettings(*this);
cv->setClearNode(NULL); // reset earth sky on each frame.
cv->setStateGraph(rendergraph.get());
cv->setRenderStage(renderStage.get());
cv->setRenderInfo( _renderInfo );
renderStage->reset();
rendergraph->clean();
renderStage->setViewport(camera.getViewport());
renderStage->setClearColor(camera.getClearColor());
renderStage->setClearMask(camera.getClearMask());
renderStage->setCamera(&camera);
cv->pushViewport(camera.getViewport());
cv->pushProjectionMatrix(new
osg::RefMatrix(camera.getProjectionMatrix()));
cv->pushModelViewMatrix(new
osg::RefMatrix(camera.getViewMatrix()),osg::Transform::ABSOLUTE_RF);
for(unsigned int childNo=0;
childNo<camera.getNumChildren();
++childNo)
{
camera.getChild(childNo)->accept(*cv);
}
cv->popModelViewMatrix();
cv->popProjectionMatrix();
cv->popViewport();
renderStage->sort();
rendergraph->prune();
// Projection correction:
osg::Matrixd proj = camera.getProjectionMatrix();
osgUtil::CullVisitor::value_type zNear = cv->getCalculatedNearPlane();
osgUtil::CullVisitor::value_type zFar = cv->getCalculatedFarPlane();
cv->clampProjectionMatrix(proj,zNear,zFar);
// Normal process:
if (camera.getViewport()) pushWindowMatrix( camera.getViewport() );
pushProjectionMatrix( new osg::RefMatrix(proj) );
pushViewMatrix( new osg::RefMatrix(camera.getViewMatrix()) );
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();
// Bouml preserved body end 00043C84
}
... I'm not sure we need to setup the CullVisitor so much : but I just took
most of the implementation from SceneView::cullstate(...) and it's working
like that... and as I said, I'm in an hurry now :-)
regards,
Manu.
2008/9/23 Emmanuel Roche <[EMAIL PROTECTED]>
> Hi everyone,
>
> I have an interesting issue here:
>
> I'm building a scene this way (the following is a lua script using
> osgIntrospection to manipulate OSG stuff) :
>
> local root = osg.Group()
> root:setName("Universe")
>
> -- we want to add this root object as a scene in the current project
> (otherwise it will never be found)
> -- this root object will be assigned as the scenedata for the master
> camera.
> local proj = vProj.ProjectManager.instance():getCurrent()
> proj:add_Scene(root)
>
> local view = vDisplay.DisplayManager.getViewer():getView(0) -- here,
> getViewer() returns our osgViewer::CompositeViewer object
> local manip =
> reflection.cast(view:getCameraManipulator(),"vGA::ArcBallManipulator")
>
> -- now create the LTS project:
> require('LTS')
>
> local cam = view:getCamera() -- this is the "main" camera, the scene data
> for this camera is the previously declared "root" object
> local subcam = osg.Camera() -- we create a sub camera than we will add to
> the main scene (so an inderect child for the main camera...)
> subcam:setGraphicsContext(cam:getGraphicsContext())
> subcam:setViewport(cam:getViewport())
> subcam:setRenderOrder(osg.Camera.RenderOrder.POST_RENDER,3) -- We post
> render this subcamera with an arbitrary order.
> subcam:setClearMask(GL.Mode.GL_DEPTH_BUFFER_BIT) -- We want to render
> Universe scale scenes that's why we introduced this multi pass system.
> root:addChild(subcam)
>
> local st = vOGL.SceneTools;
> local pat = osg.PositionAttitudeTransform()
> pat:addChild(LTS.createDoubleCraft("K1")) -- Here we create a satellit
> object
> subcam:addChild(pat) -- And we add the object to the sub camera...
>
>
> ... this scene is rendered perfectly... but now I'm trying to "pick" items
> in the scene using the implementation found in
> osgViewer::View::computeIntersections(...) : If I put my "K1" object
> directly "in" the "main" camera everything is perfect, and I can pick
> intersections correctly. But when using this "subcam" as parent then I get
> incorrect results :-( (intersections found when clicking on nothing, or no
> intersections found when cliking on sub parts of the object...)
>
> I gave a look at the osgUtil::IntersectionVisitor implementation... and I
> think everything is happening in this function:
>
> 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;
>
> if (camera.getViewport()) pushWindowMatrix( camera.getViewport() );
> pushProjectionMatrix( new osg::RefMatrix(camera.getProjectionMatrix())
> );
> pushViewMatrix( new osg::RefMatrix(camera.getViewMatrix()) );
> 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();
> }
>
> I created my own "ExtendedIntersectorVisitor" (derived from this class) to
> override this function and I made multiple tests to handle the "main" camera
> and the "sub" cameras differently:
>
> void ExtendedIntersectionVisitor::apply(osg::Camera & camera) {
> if(!cameraInitialized) {
> cameraInitialized = true;
> // The first time we get a camera object we use it to setup the
> camera details normaly:
>
> if (camera.getViewport()) pushWindowMatrix( camera.getViewport() );
> pushProjectionMatrix( new
> osg::RefMatrix(camera.getProjectionMatrix()) );
> pushViewMatrix( new osg::RefMatrix(camera.getViewMatrix()) );
> 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();
> }
> else {
> // here I did multiple tests (one by one):
>
> // Test 1: treat the camera as a transform (took implementation
> from IntersectionVisitor::apply(osg::Transform&) )
> if (!enter(*(camera.asTransform()))) return;
>
> osg::ref_ptr<osg::RefMatrix> matrix = _modelStack.empty() ? new
> osg::RefMatrix() : new osg::RefMatrix(*_modelStack.back());
> camera.computeLocalToWorldMatrix(*matrix,this);
>
> pushModelMatrix(matrix.get());
>
> // now push an new intersector clone transform to the new local
> coordinates
> push_clone();
>
> traverse(camera);
>
> // pop the clone.
> pop_clone();
>
> popModelMatrix();
>
> // tidy up an cached cull variables in the current intersector.
> leave();
> // End of Test 1
>
> // Test 2: treat the camera as a osg::Group only!
> if (!enter(*(camera.asGroup()))) return;
>
> traverse(*(camera.asGroup()));
>
> leave();
> // End of test 2
>
> // Test 3: just try not to push the model matrix, view matrix,
> projection or viewport, one by one:
>
> if (camera.getViewport()) pushWindowMatrix( camera.getViewport() );
> pushProjectionMatrix( new
> osg::RefMatrix(camera.getProjectionMatrix()) );
> pushViewMatrix( new osg::RefMatrix(camera.getViewMatrix()) );
> //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();
> // End of Test 3
> }
> }
>
>
> .. But none of this tests gave interesting result :-(... I really don't
> know where this problem may comes from then, and I really need to be able to
> pick objects in a Camera containing other sub cameras :-S. Do you have any
> clue about all that ? What am I doing wrong ?
>
> regards,
> Manu.
>
>
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org