[osg-users] multi camera rendering and pick issues

Emmanuel Roche roche.emmanuel at gmail.com
Wed Sep 24 08:19:37 PDT 2008


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 <roche.emmanuel at gmail.com>

> 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.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20080924/6094ae22/attachment-0003.htm>


More information about the osg-users mailing list