From Farshid Lashkari, "I noticed some problems when setting up CameraNodes that inherit

viewport settings in stereo mode. It seems that the SceneView::cull()
method will pass the full size viewport to the left/right
cullvisitors, instead of the modified stereo viewport. I made quite a
few changes to SceneView to fix the issue. The SceneView::cullStage()
method will now receive the viewport as an argument, instead of using
the global viewport. The SceneView::cull() method will pass the
modifed viewport to cullStage when rendering in stereo.

There are 2 new private methods computeLeftEyeViewport() and
computeRightEyeViewport() that will compute the stereo viewports. I
also modified the draw() function so it applies the correct viewport
to the prerender stages. These changes are only necessary for
horizontal/vertical split stereo."
This commit is contained in:
Robert Osfield 2008-06-19 14:29:38 +00:00
parent c3c727b822
commit dd13893861
2 changed files with 137 additions and 61 deletions

View File

@ -475,7 +475,10 @@ class OSGUTIL_EXPORT SceneView : public osg::Object, public osg::CullSettings
virtual ~SceneView();
/** Do cull traversal of attached scene graph using Cull NodeVisitor. Return true if computeNearFar has been done during the cull traversal.*/
virtual bool cullStage(const osg::Matrixd& projection,const osg::Matrixd& modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::StateGraph* rendergraph, osgUtil::RenderStage* renderStage);
virtual bool cullStage(const osg::Matrixd& projection,const osg::Matrixd& modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::StateGraph* rendergraph, osgUtil::RenderStage* renderStage, osg::Viewport *viewport);
void computeLeftEyeViewport(const osg::Viewport *viewport);
void computeRightEyeViewport(const osg::Viewport *viewport);
const osg::Matrix computeMVPW() const;
@ -496,10 +499,12 @@ class OSGUTIL_EXPORT SceneView : public osg::Object, public osg::CullSettings
osg::ref_ptr<osgUtil::CullVisitor> _cullVisitorLeft;
osg::ref_ptr<osgUtil::StateGraph> _stateGraphLeft;
osg::ref_ptr<osgUtil::RenderStage> _renderStageLeft;
osg::ref_ptr<osg::Viewport> _viewportLeft;
osg::ref_ptr<osgUtil::CullVisitor> _cullVisitorRight;
osg::ref_ptr<osgUtil::StateGraph> _stateGraphRight;
osg::ref_ptr<osgUtil::RenderStage> _renderStageRight;
osg::ref_ptr<osg::Viewport> _viewportRight;
osg::ref_ptr<osg::CollectOccludersVisitor> _collectOccludersVisitor;

View File

@ -542,6 +542,107 @@ osg::Matrixd SceneView::computeRightEyeViewImplementation(const osg::Matrixd& vi
-es,0.0,0.0,1.0);
}
void SceneView::computeLeftEyeViewport(const osg::Viewport *viewport)
{
if(!viewport) return;
if(!_viewportLeft.valid()) _viewportLeft = new osg::Viewport;
switch(_displaySettings->getStereoMode())
{
case(osg::DisplaySettings::HORIZONTAL_SPLIT):
{
Viewport::value_type separation = _displaySettings->getSplitStereoHorizontalSeparation();
if (_displaySettings->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT)
{
Viewport::value_type left_half_width = (viewport->width()-separation)/2;
_viewportLeft->setViewport(viewport->x(),viewport->y(),left_half_width,viewport->height());
}
else
{
Viewport::value_type right_half_begin = (viewport->width()+separation)/2;
Viewport::value_type right_half_width = viewport->width()-right_half_begin;
_viewportLeft->setViewport(viewport->x()+right_half_begin,viewport->y(),right_half_width,viewport->height());
}
}
break;
case(osg::DisplaySettings::VERTICAL_SPLIT):
{
Viewport::value_type separation = _displaySettings->getSplitStereoHorizontalSeparation();
if (_displaySettings->getSplitStereoVerticalEyeMapping()==osg::DisplaySettings::LEFT_EYE_TOP_VIEWPORT)
{
Viewport::value_type top_half_begin = (viewport->height()+separation)/2;
Viewport::value_type top_half_height = viewport->height()-top_half_begin;
_viewportLeft->setViewport(viewport->x(),viewport->y()+top_half_begin,viewport->width(),top_half_height);
}
else
{
Viewport::value_type bottom_half_height = (viewport->height()-separation)/2;
_viewportLeft->setViewport(viewport->x(),viewport->y(),viewport->width(),bottom_half_height);
}
}
break;
default:
_viewportLeft->setViewport(viewport->x(),viewport->y(),viewport->width(),viewport->height());
break;
}
}
void SceneView::computeRightEyeViewport(const osg::Viewport *viewport)
{
if(!viewport) return;
if(!_viewportRight.valid()) _viewportRight = new osg::Viewport;
switch(_displaySettings->getStereoMode())
{
case(osg::DisplaySettings::HORIZONTAL_SPLIT):
{
Viewport::value_type separation = _displaySettings->getSplitStereoHorizontalSeparation();
if (_displaySettings->getSplitStereoHorizontalEyeMapping()!=osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT)
{
Viewport::value_type left_half_width = (viewport->width()-separation)/2;
_viewportRight->setViewport(viewport->x(),viewport->y(),left_half_width,viewport->height());
}
else
{
Viewport::value_type right_half_begin = (viewport->width()+separation)/2;
Viewport::value_type right_half_width = viewport->width()-right_half_begin;
_viewportRight->setViewport(viewport->x()+right_half_begin,viewport->y(),right_half_width,viewport->height());
}
}
break;
case(osg::DisplaySettings::VERTICAL_SPLIT):
{
Viewport::value_type separation = _displaySettings->getSplitStereoHorizontalSeparation();
if (_displaySettings->getSplitStereoVerticalEyeMapping()!=osg::DisplaySettings::LEFT_EYE_TOP_VIEWPORT)
{
Viewport::value_type top_half_begin = (viewport->height()+separation)/2;
Viewport::value_type top_half_height = viewport->height()-top_half_begin;
_viewportRight->setViewport(viewport->x(),viewport->y()+top_half_begin,viewport->width(),top_half_height);
}
else
{
Viewport::value_type bottom_half_height = (viewport->height()-separation)/2;
_viewportRight->setViewport(viewport->x(),viewport->y(),viewport->width(),bottom_half_height);
}
}
break;
default:
_viewportRight->setViewport(viewport->x(),viewport->y(),viewport->width(),viewport->height());
break;
}
}
void SceneView::inheritCullSettings(const osg::CullSettings& settings, unsigned int inheritanceMask)
{
if (_camera.valid() && _camera->getView())
@ -623,7 +724,8 @@ void SceneView::cull()
{
// set up the left eye.
_cullVisitor->setTraversalMask(_cullMaskLeft);
bool computeNearFar = cullStage(computeLeftEyeProjection(getProjectionMatrix()),computeLeftEyeView(getViewMatrix()),_cullVisitor.get(),_stateGraph.get(),_renderStage.get());
computeLeftEyeViewport(getViewport());
bool computeNearFar = cullStage(computeLeftEyeProjection(getProjectionMatrix()),computeLeftEyeView(getViewMatrix()),_cullVisitor.get(),_stateGraph.get(),_renderStage.get(),_viewportLeft.get());
if (computeNearFar)
{
@ -637,7 +739,8 @@ void SceneView::cull()
{
// set up the right eye.
_cullVisitor->setTraversalMask(_cullMaskRight);
bool computeNearFar = cullStage(computeRightEyeProjection(getProjectionMatrix()),computeRightEyeView(getViewMatrix()),_cullVisitor.get(),_stateGraph.get(),_renderStage.get());
computeRightEyeViewport(getViewport());
bool computeNearFar = cullStage(computeRightEyeProjection(getProjectionMatrix()),computeRightEyeView(getViewMatrix()),_cullVisitor.get(),_stateGraph.get(),_renderStage.get(),_viewportRight.get());
if (computeNearFar)
{
@ -661,14 +764,16 @@ void SceneView::cull()
_cullVisitorLeft->setDatabaseRequestHandler(_cullVisitor->getDatabaseRequestHandler());
_cullVisitorLeft->setClampProjectionMatrixCallback(_cullVisitor->getClampProjectionMatrixCallback());
_cullVisitorLeft->setTraversalMask(_cullMaskLeft);
bool computeNearFar = cullStage(computeLeftEyeProjection(getProjectionMatrix()),computeLeftEyeView(getViewMatrix()),_cullVisitorLeft.get(),_stateGraphLeft.get(),_renderStageLeft.get());
computeLeftEyeViewport(getViewport());
bool computeNearFar = cullStage(computeLeftEyeProjection(getProjectionMatrix()),computeLeftEyeView(getViewMatrix()),_cullVisitorLeft.get(),_stateGraphLeft.get(),_renderStageLeft.get(),_viewportLeft.get());
// set up the right eye.
_cullVisitorRight->setDatabaseRequestHandler(_cullVisitor->getDatabaseRequestHandler());
_cullVisitorRight->setClampProjectionMatrixCallback(_cullVisitor->getClampProjectionMatrixCallback());
_cullVisitorRight->setTraversalMask(_cullMaskRight);
computeNearFar = cullStage(computeRightEyeProjection(getProjectionMatrix()),computeRightEyeView(getViewMatrix()),_cullVisitorRight.get(),_stateGraphRight.get(),_renderStageRight.get());
computeRightEyeViewport(getViewport());
computeNearFar = cullStage(computeRightEyeProjection(getProjectionMatrix()),computeRightEyeView(getViewMatrix()),_cullVisitorRight.get(),_stateGraphRight.get(),_renderStageRight.get(),_viewportRight.get());
if (computeNearFar)
{
@ -684,7 +789,7 @@ void SceneView::cull()
{
_cullVisitor->setTraversalMask(_cullMask);
bool computeNearFar = cullStage(getProjectionMatrix(),getViewMatrix(),_cullVisitor.get(),_stateGraph.get(),_renderStage.get());
bool computeNearFar = cullStage(getProjectionMatrix(),getViewMatrix(),_cullVisitor.get(),_stateGraph.get(),_renderStage.get(),getViewport());
if (computeNearFar)
{
@ -697,10 +802,10 @@ void SceneView::cull()
}
bool SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::StateGraph* rendergraph, osgUtil::RenderStage* renderStage)
bool SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::StateGraph* rendergraph, osgUtil::RenderStage* renderStage, osg::Viewport *viewport)
{
if (!_camera || !getViewport()) return false;
if (!_camera || !viewport) return false;
osg::ref_ptr<RefMatrix> proj = new osg::RefMatrix(projection);
osg::ref_ptr<RefMatrix> mv = new osg::RefMatrix(modelview);
@ -726,7 +831,7 @@ bool SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& mod
_collectOccludersVisitor->setTraversalNumber(_frameStamp->getFrameNumber());
}
_collectOccludersVisitor->pushViewport(getViewport());
_collectOccludersVisitor->pushViewport(viewport);
_collectOccludersVisitor->pushProjectionMatrix(proj.get());
_collectOccludersVisitor->pushModelViewMatrix(mv.get(),osg::Transform::ABSOLUTE_RF);
@ -779,7 +884,7 @@ bool SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& mod
// achieves a certain amount of frame cohereancy of memory allocation.
rendergraph->clean();
renderStage->setViewport(getViewport());
renderStage->setViewport(viewport);
renderStage->setClearColor(_camera->getClearColor());
renderStage->setClearDepth(_camera->getClearDepth());
renderStage->setClearAccum(_camera->getClearAccum());
@ -808,7 +913,7 @@ bool SceneView::cullStage(const osg::Matrixd& projection,const osg::Matrixd& mod
if (_localStateSet.valid()) cullVisitor->pushStateSet(_localStateSet.get());
cullVisitor->pushViewport(getViewport());
cullVisitor->pushViewport(viewport);
cullVisitor->pushProjectionMatrix(proj.get());
cullVisitor->pushModelViewMatrix(mv.get(),osg::Transform::ABSOLUTE_RF);
@ -1025,7 +1130,10 @@ void SceneView::draw()
_renderStageLeft->setColorMask(cmask);
_renderStageRight->setColorMask(cmask);
_localStateSet->setAttribute(_viewportLeft.get());
_renderStageLeft->drawPreRenderStages(_renderInfo,previous);
_localStateSet->setAttribute(_viewportRight.get());
_renderStageRight->drawPreRenderStages(_renderInfo,previous);
double separation = _displaySettings->getSplitStereoHorizontalSeparation();
@ -1034,37 +1142,17 @@ void SceneView::draw()
double right_half_begin = (getViewport()->width()+separation)/2.0;
double right_half_width = getViewport()->width()-right_half_begin;
osg::ref_ptr<osg::Viewport> viewportLeft = new osg::Viewport;
viewportLeft->setViewport(getViewport()->x(),getViewport()->y(),left_half_width,getViewport()->height());
osg::ref_ptr<osg::Viewport> viewportRight = new osg::Viewport;
viewportRight->setViewport(getViewport()->x()+right_half_begin,getViewport()->y(),right_half_width,getViewport()->height());
clearArea(static_cast<int>(getViewport()->x()+left_half_width),
static_cast<int>(getViewport()->y()),
static_cast<int>(separation),
static_cast<int>(getViewport()->height()),_renderStageLeft->getClearColor());
if (_displaySettings->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT)
{
_localStateSet->setAttribute(viewportLeft.get());
_renderStageLeft->setViewport(viewportLeft.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(_viewportLeft.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(viewportRight.get());
_renderStageRight->setViewport(viewportRight.get());
_renderStageRight->draw(_renderInfo,previous);
}
else
{
_localStateSet->setAttribute(viewportRight.get());
_renderStageLeft->setViewport(viewportRight.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(viewportLeft.get());
_renderStageRight->setViewport(viewportLeft.get());
_renderStageRight->draw(_renderInfo,previous);
}
_localStateSet->setAttribute(_viewportRight.get());
_renderStageRight->draw(_renderInfo,previous);
}
break;
@ -1093,7 +1181,11 @@ void SceneView::draw()
_renderStageLeft->setColorMask(cmask);
_renderStageRight->setColorMask(cmask);
_localStateSet->setAttribute(_viewportLeft.get());
_renderStageLeft->drawPreRenderStages(_renderInfo,previous);
_localStateSet->setAttribute(_viewportRight.get());
_renderStageRight->drawPreRenderStages(_renderInfo,previous);
double separation = _displaySettings->getSplitStereoVerticalSeparation();
@ -1102,38 +1194,17 @@ void SceneView::draw()
double top_half_begin = (getViewport()->height()+separation)/2.0;
double top_half_height = getViewport()->height()-top_half_begin;
osg::ref_ptr<osg::Viewport> viewportTop = new osg::Viewport;
viewportTop->setViewport(getViewport()->x(),getViewport()->y()+top_half_begin,getViewport()->width(),top_half_height);
osg::ref_ptr<osg::Viewport> viewportBottom = new osg::Viewport;
viewportBottom->setViewport(getViewport()->x(),getViewport()->y(),getViewport()->width(),bottom_half_height);
clearArea(static_cast<int>(getViewport()->x()),
static_cast<int>(getViewport()->y()+bottom_half_height),
static_cast<int>(getViewport()->width()),
static_cast<int>(separation),
_renderStageLeft->getClearColor());
if (_displaySettings->getSplitStereoVerticalEyeMapping()==osg::DisplaySettings::LEFT_EYE_TOP_VIEWPORT)
{
_localStateSet->setAttribute(viewportTop.get());
_renderStageLeft->setViewport(viewportTop.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(_viewportLeft.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(viewportBottom.get());
_renderStageRight->setViewport(viewportBottom.get());
_renderStageRight->draw(_renderInfo,previous);
}
else
{
_localStateSet->setAttribute(viewportBottom.get());
_renderStageLeft->setViewport(viewportBottom.get());
_renderStageLeft->draw(_renderInfo,previous);
_localStateSet->setAttribute(viewportTop.get());
_renderStageRight->setViewport(viewportTop.get());
_renderStageRight->draw(_renderInfo,previous);
}
_localStateSet->setAttribute(_viewportRight.get());
_renderStageRight->draw(_renderInfo,previous);
}
break;
case(osg::DisplaySettings::RIGHT_EYE):