Hi,

When using the OSG occlusion system some abnormal effects were detected:

1. When camera is moved into a corner of an occlusion box, sometime the 
geometry is occluded. 

2. First time an occlusion node is rendered, the geometry is always treated as 
if occluded last frame. This can be seen as blinking when change of LOD’s.

3. Occlusion nodes left with the status occluded, then moving camera to another 
LOD before moving camera back to first LOD again. The geometry will then blink 
when the first LOD was accessed.


I looked into the code to fix these problems. My proposal is as follow:

1. Change the parameter list for OcclusionQueryNode::getPassed(..)
bool getPassed(const osg::Camera* camera, osg::NodeVisitor& nv)

2. Extend the getPassed method with two testes. This will fix problems 2 and 3.

3. Change the getPassed method distance test to use the distance from BS center 
to occlusion box corner. This will fix problem 1.

4. Change the CullVisitor::apply(osg::OcclusionQueryNode& node) with the new 
parameter for getPassed(..) (osg::NodeVisitor)


An alternative solution could be to make the OcclusionQueryNode virtual. Then 
we can implement the getPassed(..) method in our project code. Still we need 
the parameter extension of the OcclusionQueryNode::getPassed method.

In the future we can foresee extended use of the OcclusionQueryNode object. 
Same examples:
• Detect number of visible pixels 
  - Nicer sun-beams than today deferred render.
  - ‘God-rays’ from car lights and from other intensive light sources.
• Get information about number of pixels with intensive light.
• Simplify our code for a tracker camera.

If the OcclusionQueryNode class is virtual, it will be possible for the 
applications to perform such operations independent of the osg core system.


Modified code:

bool
OcclusionQueryNode::getPassed( const osg::Camera* camera, osg::NodeVisitor& nv )
{
    if ( !_enabled )
        // Queries are not enabled. The caller should be osgUtil::CullVisitor,
        //   return true to traverse the subgraphs.
        return true;

    // If first time the occlusion node is rendered for current camera, then 
traverse as usual (Avoid blinking).
    const int& lastQueryFrame = _frameCountMap[ camera ];
    if (lastQueryFrame == 0)
    {
        return true;
    }
    // If for some reason (LOD switching) the occlusion node is not rendered 
for a while, then traverse as usual (Avoid blinking).
    if ( (nv.getTraversalNumber() - lastQueryFrame) >  (_queryFrameCount + 1) )
    {
        return true;
    }

    // In the future, we could hold a reference directly to the QueryDrawable
    //   to avoid the dynamic_cast.
    QueryGeometry* qg = dynamic_cast< QueryGeometry* >( 
_queryGeode->getDrawable( 0 ) );
    if (qg == NULL)
    {
        osg::notify( osg::FATAL ) <<
            "osgOQ: OcclusionQueryNode: No QueryGeometry." << std::endl;
        // Something's broke. Return true so we at least render correctly.
        return true;
    }

    // If the distance to the bounding sphere shell is positive, retrieve
    //   the results. Others (we're inside the BS shell) we are considered
    //   to have passed and don't need to retrieve the query.
    const osg::BoundingSphere& bs = getBound();
    float distanceToEyePoint = nv.getDistanceToEyePoint( bs._center, false );
    float distance = distanceToEyePoint - bs._radius*1.45f;     // Because the 
occlusion box is represented as a cuboid geometry
    _passed = ( distance <= 0.f );
    if (!_passed)
    {
        int result = qg->getNumPixels( camera );
        _passed = ( (unsigned int)(result) > _visThreshold );
    }
    return _passed;
}

void CullVisitor::apply(osg::OcclusionQueryNode& node)
{
    if (isCulled(node)) return;

    // push the culling mode.
    pushCurrentMask();

    // push the node's state.
    StateSet* node_state = node.getStateSet();
    if (node_state) pushStateSet(node_state);

    osg::Camera* camera = getCurrentCamera();
   
    // If previous query indicates visible, then traverse as usual.
    if (node.getPassed( camera, *this ))
        handle_cull_callbacks_and_traverse(node);

    // Traverse the query subtree if OcclusionQueryNode needs to issue another 
query.
    node.traverseQuery( camera, *this );

    // Traverse the debug bounding geometry, if enabled.
    node.traverseDebug( *this );


    // pop the node's state off the render graph stack.    
    if (node_state) popStateSet();

    // pop the culling mode.
    popCurrentMask();
}



Thank you!

Cheers,
Magne
Code:




------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=23841#23841





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

Reply via email to