Moved intial cut of depth partition support into osgViewer::View via two new methods:

/** Convenience method for setting up multiple slave cameras that depth partition the specified camera.*/
        bool setUpDepthPartitionForCamera(osg::Camera* cameraToPartition, DepthPartitionSettings* dps=0);

        /** Convenience method for setting up multiple slave cameras that depth partition each of the view's active cameras.*/
        bool setUpDepthPartition(DepthPartitionSettings* dsp=0);
This commit is contained in:
Robert Osfield 2011-03-03 15:52:19 +00:00
parent be31cdb328
commit afecdbb46b
3 changed files with 325 additions and 299 deletions

View File

@ -569,297 +569,6 @@ osg::Node* createTestModel(osg::ArgumentParser& arguments)
}
struct DepthPartitionSettings : public osg::Referenced
{
DepthPartitionSettings() {}
enum DepthMode
{
FIXED_RANGE,
BOUNDING_VOLUME
};
bool getDepthRange(osg::View& view, unsigned int partition, double& zNear, double& zFar)
{
switch(_mode)
{
case(FIXED_RANGE):
{
if (partition==0)
{
zNear = _zNear;
zFar = _zMid;
return true;
}
else if (partition==1)
{
zNear = _zMid;
zFar = _zFar;
return true;
}
return false;
}
case(BOUNDING_VOLUME):
{
osgViewer::View* view_withSceneData = dynamic_cast<osgViewer::View*>(&view);
const osg::Node* node = view_withSceneData ? view_withSceneData->getSceneData() : 0;
if (!node) return false;
const osg::Camera* masterCamera = view.getCamera();
if (!masterCamera) return false;
osg::BoundingSphere bs = node->getBound();
const osg::Matrixd& viewMatrix = masterCamera->getViewMatrix();
//osg::Matrixd& projectionMatrix = masterCamera->getProjectionMatrix();
osg::Vec3d lookVectorInWorldCoords = osg::Matrixd::transform3x3(viewMatrix,osg::Vec3d(0.0,0.0,-1.0));
lookVectorInWorldCoords.normalize();
osg::Vec3d nearPointInWorldCoords = bs.center() - lookVectorInWorldCoords*bs.radius();
osg::Vec3d farPointInWorldCoords = bs.center() + lookVectorInWorldCoords*bs.radius();
osg::Vec3d nearPointInEyeCoords = nearPointInWorldCoords * viewMatrix;
osg::Vec3d farPointInEyeCoords = farPointInWorldCoords * viewMatrix;
#if 0
OSG_NOTICE<<std::endl;
OSG_NOTICE<<"viewMatrix = "<<viewMatrix<<std::endl;
OSG_NOTICE<<"lookVectorInWorldCoords = "<<lookVectorInWorldCoords<<std::endl;
OSG_NOTICE<<"nearPointInWorldCoords = "<<nearPointInWorldCoords<<std::endl;
OSG_NOTICE<<"farPointInWorldCoords = "<<farPointInWorldCoords<<std::endl;
OSG_NOTICE<<"nearPointInEyeCoords = "<<nearPointInEyeCoords<<std::endl;
OSG_NOTICE<<"farPointInEyeCoords = "<<farPointInEyeCoords<<std::endl;
#endif
double minZNearRatio = 0.001;
if (masterCamera->getDisplaySettings())
{
OSG_NOTICE<<"Has display settings"<<std::endl;
}
double scene_zNear = -nearPointInEyeCoords.z();
double scene_zFar = -farPointInEyeCoords.z();
if (scene_zNear<=0.0) scene_zNear = minZNearRatio * scene_zFar;
double scene_zMid = sqrt(scene_zFar*scene_zNear);
#if 0
OSG_NOTICE<<"scene_zNear = "<<scene_zNear<<std::endl;
OSG_NOTICE<<"scene_zMid = "<<scene_zMid<<std::endl;
OSG_NOTICE<<"scene_zFar = "<<scene_zFar<<std::endl;
#endif
if (partition==0)
{
zNear = scene_zNear;
zFar = scene_zMid;
return true;
}
else if (partition==1)
{
zNear = scene_zMid;
zFar = scene_zFar;
return true;
}
return false;
}
}
}
DepthMode _mode;
double _zNear;
double _zMid;
double _zFar;
};
struct MyUpdateSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
{
MyUpdateSlaveCallback(DepthPartitionSettings* dps, unsigned int partition):_dps(dps), _partition(partition) {}
virtual void updateSlave(osg::View& view, osg::View::Slave& slave)
{
slave.updateSlaveImplementation(view);
if (!_dps) return;
osg::Camera* camera = slave._camera.get();
double computed_zNear;
double computed_zFar;
if (!_dps->getDepthRange(view, _partition, computed_zNear, computed_zFar))
{
OSG_NOTICE<<"Switching off Camera "<<camera<<std::endl;
camera->setNodeMask(0x0);
return;
}
else
{
camera->setNodeMask(0xffffff);
}
if (camera->getProjectionMatrix()(0,3)==0.0 &&
camera->getProjectionMatrix()(1,3)==0.0 &&
camera->getProjectionMatrix()(2,3)==0.0)
{
double left, right, bottom, top, zNear, zFar;
camera->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
camera->setProjectionMatrixAsOrtho(left, right, bottom, top, computed_zNear, computed_zFar);
}
else
{
double left, right, bottom, top, zNear, zFar;
camera->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
double nr = computed_zNear / zNear;
camera->setProjectionMatrixAsFrustum(left * nr, right * nr, bottom * nr, top * nr, computed_zNear, computed_zFar);
}
}
osg::ref_ptr<DepthPartitionSettings> _dps;
unsigned int _partition;
};
bool setUpDepthPartitionForCamera(osg::View& view, osg::Camera* cameraToPartition, DepthPartitionSettings* dps)
{
osg::ref_ptr<osg::GraphicsContext> context = cameraToPartition->getGraphicsContext();
if (!context) return false;
osg::ref_ptr<osg::Viewport> viewport = cameraToPartition->getViewport();
if (!viewport) return false;
cameraToPartition->setGraphicsContext(0);
cameraToPartition->setViewport(0);
bool useMastersSceneData = true;
osg::Matrixd projectionOffset;
osg::Matrixd viewOffset;
if (view.getCamera()==cameraToPartition)
{
// replace main camera with depth partition cameras
OSG_NOTICE<<"Replacing main Camera"<<std::endl;
}
else
{
unsigned int i = view.findSlaveIndexForCamera(cameraToPartition);
if (i>=view.getNumSlaves()) return false;
osg::View::Slave& slave = view.getSlave(i);
useMastersSceneData = slave._useMastersSceneData;
projectionOffset = slave._projectionOffset;
viewOffset = slave._viewOffset;
OSG_NOTICE<<"Replacing slave Camera"<<i<<std::endl;
view.removeSlave(i);
}
// far camera
{
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(context.get());
camera->setViewport(viewport.get());
camera->setDrawBuffer(cameraToPartition->getDrawBuffer());
camera->setReadBuffer(cameraToPartition->getReadBuffer());
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING);
view.addSlave(camera.get());
osg::View::Slave& slave = view.getSlave(view.getNumSlaves()-1);
slave._useMastersSceneData = useMastersSceneData;
slave._projectionOffset = projectionOffset;
slave._viewOffset = viewOffset;
slave._updateSlaveCallback = new MyUpdateSlaveCallback(dps, 1);
}
// near camera
{
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(context.get());
camera->setViewport(viewport.get());
camera->setDrawBuffer(cameraToPartition->getDrawBuffer());
camera->setReadBuffer(cameraToPartition->getReadBuffer());
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING);
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
view.addSlave(camera.get());
osg::View::Slave& slave = view.getSlave(view.getNumSlaves()-1);
slave._useMastersSceneData = useMastersSceneData;
slave._projectionOffset = projectionOffset;
slave._viewOffset = viewOffset;
slave._updateSlaveCallback = new MyUpdateSlaveCallback(dps, 0);
}
return true;
}
typedef std::list< osg::ref_ptr<osg::Camera> > Cameras;
Cameras getActiveCameras(osg::View& view)
{
Cameras activeCameras;
if (view.getCamera() && view.getCamera()->getGraphicsContext())
{
activeCameras.push_back(view.getCamera());
}
for(unsigned int i=0; i<view.getNumSlaves(); ++i)
{
osg::View::Slave& slave = view.getSlave(i);
if (slave._camera.valid() && slave._camera->getGraphicsContext())
{
activeCameras.push_back(slave._camera.get());
}
}
return activeCameras;
}
bool setUpDepthPartition(osgViewer::View& view, DepthPartitionSettings* dsp)
{
OSG_NOTICE<<"setUpDepthPartition(View,..)"<<std::endl;
Cameras originalCameras = getActiveCameras(view);
if (originalCameras.empty())
{
OSG_NOTICE<<"setUpDepthPartition(View,..) doing view.setUpViewAcrossAllScreens()"<<std::endl;
view.setUpViewAcrossAllScreens();
originalCameras = getActiveCameras(view);
if (originalCameras.empty())
{
OSG_NOTICE<<"setUpDepthPartition(View,..) Unable to set up windows for viewer."<<std::endl;
return false;
}
}
bool threadsWereRunning = view.getViewerBase()->areThreadsRunning();
if (threadsWereRunning) view.getViewerBase()->stopThreading();
for(Cameras::iterator itr = originalCameras.begin();
itr != originalCameras.end();
++itr)
{
setUpDepthPartitionForCamera(view, itr->get(), dsp);
}
if (threadsWereRunning) view.getViewerBase()->startThreading();
return true;
}
int main(int argc, char** argv)
{
@ -919,16 +628,22 @@ int main(int argc, char** argv)
return 1;
}
double partitionPosition = 5.0;
if (arguments.read("--depth-partition",partitionPosition) || arguments.read("--dp"))
double zNear=1.0, zMid=10.0, zFar=1000.0;
if (arguments.read("--depth-partition",zNear, zMid, zFar))
{
// set up depth partitioning
osg::ref_ptr<DepthPartitionSettings> dps = new DepthPartitionSettings;
dps->_mode = DepthPartitionSettings::BOUNDING_VOLUME;
dps->_zNear = 0.5;
dps->_zMid = partitionPosition;
dps->_zFar = 1000.0;
setUpDepthPartition(viewer, dps.get());
osg::ref_ptr<osgViewer::DepthPartitionSettings> dps = new osgViewer::DepthPartitionSettings;
dps->_mode = osgViewer::DepthPartitionSettings::FIXED_RANGE;
dps->_zNear = zNear;
dps->_zMid = zMid;
dps->_zFar = zFar;
viewer.setUpDepthPartition(dps.get());
}
if (arguments.read("--dp"))
{
// set up depth partitioning
viewer.setUpDepthPartition();
}
float fov = 0.0;

View File

@ -30,6 +30,26 @@
namespace osgViewer {
struct OSGVIEWER_EXPORT DepthPartitionSettings : public osg::Referenced
{
enum DepthMode
{
FIXED_RANGE,
BOUNDING_VOLUME
};
DepthPartitionSettings(DepthMode mode=BOUNDING_VOLUME);
virtual bool getDepthRange(osg::View& view, unsigned int partition, double& zNear, double& zFar);
DepthMode _mode;
double _zNear;
double _zMid;
double _zFar;
};
/** View holds a single view on a scene, this view may be composed of one or more slave cameras.*/
class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter
{
@ -183,6 +203,13 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter
void setUpViewForWoWVxDisplay(unsigned int screenNum, unsigned char wow_content, unsigned char wow_factor, unsigned char wow_offset, float wow_disparity_Zd, float wow_disparity_vz, float wow_disparity_M, float wow_disparity_C);
/** Convenience method for setting up multiple slave cameras that depth partition the specified camera.*/
bool setUpDepthPartitionForCamera(osg::Camera* cameraToPartition, DepthPartitionSettings* dps=0);
/** Convenience method for setting up multiple slave cameras that depth partition each of the view's active cameras.*/
bool setUpDepthPartition(DepthPartitionSettings* dsp=0);
/** Return true if this view contains a specified camera.*/
bool containsCamera(const osg::Camera* camera) const;

View File

@ -1595,6 +1595,290 @@ void View::setUpViewForWoWVxDisplay(unsigned int screenNum, unsigned char wow_co
}
}
DepthPartitionSettings::DepthPartitionSettings(DepthMode mode):
_mode(mode),
_zNear(1.0), _zMid(5.0), _zFar(1000.0)
{}
bool DepthPartitionSettings::getDepthRange(osg::View& view, unsigned int partition, double& zNear, double& zFar)
{
switch(_mode)
{
case(FIXED_RANGE):
{
if (partition==0)
{
zNear = _zNear;
zFar = _zMid;
return true;
}
else if (partition==1)
{
zNear = _zMid;
zFar = _zFar;
return true;
}
return false;
}
case(BOUNDING_VOLUME):
{
osgViewer::View* view_withSceneData = dynamic_cast<osgViewer::View*>(&view);
const osg::Node* node = view_withSceneData ? view_withSceneData->getSceneData() : 0;
if (!node) return false;
const osg::Camera* masterCamera = view.getCamera();
if (!masterCamera) return false;
osg::BoundingSphere bs = node->getBound();
const osg::Matrixd& viewMatrix = masterCamera->getViewMatrix();
//osg::Matrixd& projectionMatrix = masterCamera->getProjectionMatrix();
osg::Vec3d lookVectorInWorldCoords = osg::Matrixd::transform3x3(viewMatrix,osg::Vec3d(0.0,0.0,-1.0));
lookVectorInWorldCoords.normalize();
osg::Vec3d nearPointInWorldCoords = bs.center() - lookVectorInWorldCoords*bs.radius();
osg::Vec3d farPointInWorldCoords = bs.center() + lookVectorInWorldCoords*bs.radius();
osg::Vec3d nearPointInEyeCoords = nearPointInWorldCoords * viewMatrix;
osg::Vec3d farPointInEyeCoords = farPointInWorldCoords * viewMatrix;
#if 0
OSG_NOTICE<<std::endl;
OSG_NOTICE<<"viewMatrix = "<<viewMatrix<<std::endl;
OSG_NOTICE<<"lookVectorInWorldCoords = "<<lookVectorInWorldCoords<<std::endl;
OSG_NOTICE<<"nearPointInWorldCoords = "<<nearPointInWorldCoords<<std::endl;
OSG_NOTICE<<"farPointInWorldCoords = "<<farPointInWorldCoords<<std::endl;
OSG_NOTICE<<"nearPointInEyeCoords = "<<nearPointInEyeCoords<<std::endl;
OSG_NOTICE<<"farPointInEyeCoords = "<<farPointInEyeCoords<<std::endl;
#endif
double minZNearRatio = 0.001;
if (masterCamera->getDisplaySettings())
{
OSG_NOTICE<<"Has display settings"<<std::endl;
}
double scene_zNear = -nearPointInEyeCoords.z();
double scene_zFar = -farPointInEyeCoords.z();
if (scene_zNear<=0.0) scene_zNear = minZNearRatio * scene_zFar;
double scene_zMid = sqrt(scene_zFar*scene_zNear);
#if 0
OSG_NOTICE<<"scene_zNear = "<<scene_zNear<<std::endl;
OSG_NOTICE<<"scene_zMid = "<<scene_zMid<<std::endl;
OSG_NOTICE<<"scene_zFar = "<<scene_zFar<<std::endl;
#endif
if (partition==0)
{
zNear = scene_zNear;
zFar = scene_zMid;
return true;
}
else if (partition==1)
{
zNear = scene_zMid;
zFar = scene_zFar;
return true;
}
return false;
}
}
}
namespace osgDepthPartition {
struct MyUpdateSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
{
MyUpdateSlaveCallback(DepthPartitionSettings* dps, unsigned int partition):_dps(dps), _partition(partition) {}
virtual void updateSlave(osg::View& view, osg::View::Slave& slave)
{
slave.updateSlaveImplementation(view);
if (!_dps) return;
osg::Camera* camera = slave._camera.get();
double computed_zNear;
double computed_zFar;
if (!_dps->getDepthRange(view, _partition, computed_zNear, computed_zFar))
{
OSG_NOTICE<<"Switching off Camera "<<camera<<std::endl;
camera->setNodeMask(0x0);
return;
}
else
{
camera->setNodeMask(0xffffff);
}
if (camera->getProjectionMatrix()(0,3)==0.0 &&
camera->getProjectionMatrix()(1,3)==0.0 &&
camera->getProjectionMatrix()(2,3)==0.0)
{
double left, right, bottom, top, zNear, zFar;
camera->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
camera->setProjectionMatrixAsOrtho(left, right, bottom, top, computed_zNear, computed_zFar);
}
else
{
double left, right, bottom, top, zNear, zFar;
camera->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
double nr = computed_zNear / zNear;
camera->setProjectionMatrixAsFrustum(left * nr, right * nr, bottom * nr, top * nr, computed_zNear, computed_zFar);
}
}
osg::ref_ptr<DepthPartitionSettings> _dps;
unsigned int _partition;
};
typedef std::list< osg::ref_ptr<osg::Camera> > Cameras;
Cameras getActiveCameras(osg::View& view)
{
Cameras activeCameras;
if (view.getCamera() && view.getCamera()->getGraphicsContext())
{
activeCameras.push_back(view.getCamera());
}
for(unsigned int i=0; i<view.getNumSlaves(); ++i)
{
osg::View::Slave& slave = view.getSlave(i);
if (slave._camera.valid() && slave._camera->getGraphicsContext())
{
activeCameras.push_back(slave._camera.get());
}
}
return activeCameras;
}
}
bool View::setUpDepthPartitionForCamera(osg::Camera* cameraToPartition, DepthPartitionSettings* incomming_dps)
{
osg::ref_ptr<osg::GraphicsContext> context = cameraToPartition->getGraphicsContext();
if (!context) return false;
osg::ref_ptr<osg::Viewport> viewport = cameraToPartition->getViewport();
if (!viewport) return false;
osg::ref_ptr<DepthPartitionSettings> dps = incomming_dps;
if (!dps) dps = new DepthPartitionSettings;
bool useMastersSceneData = true;
osg::Matrixd projectionOffset;
osg::Matrixd viewOffset;
if (getCamera()==cameraToPartition)
{
// replace main camera with depth partition cameras
OSG_INFO<<"View::setUpDepthPartitionForCamera(..) Replacing main Camera"<<std::endl;
}
else
{
unsigned int i = findSlaveIndexForCamera(cameraToPartition);
if (i>=getNumSlaves()) return false;
osg::View::Slave& slave = getSlave(i);
useMastersSceneData = slave._useMastersSceneData;
projectionOffset = slave._projectionOffset;
viewOffset = slave._viewOffset;
OSG_NOTICE<<"View::setUpDepthPartitionForCamera(..) Replacing slave Camera"<<i<<std::endl;
removeSlave(i);
}
cameraToPartition->setGraphicsContext(0);
cameraToPartition->setViewport(0);
// far camera
{
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(context.get());
camera->setViewport(viewport.get());
camera->setDrawBuffer(cameraToPartition->getDrawBuffer());
camera->setReadBuffer(cameraToPartition->getReadBuffer());
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING);
addSlave(camera.get());
osg::View::Slave& slave = getSlave(getNumSlaves()-1);
slave._useMastersSceneData = useMastersSceneData;
slave._projectionOffset = projectionOffset;
slave._viewOffset = viewOffset;
slave._updateSlaveCallback = new osgDepthPartition::MyUpdateSlaveCallback(dps.get(), 1);
}
// near camera
{
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(context.get());
camera->setViewport(viewport.get());
camera->setDrawBuffer(cameraToPartition->getDrawBuffer());
camera->setReadBuffer(cameraToPartition->getReadBuffer());
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::Camera::ENABLE_ALL_CULLING);
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
addSlave(camera.get());
osg::View::Slave& slave = getSlave(getNumSlaves()-1);
slave._useMastersSceneData = useMastersSceneData;
slave._projectionOffset = projectionOffset;
slave._viewOffset = viewOffset;
slave._updateSlaveCallback = new osgDepthPartition::MyUpdateSlaveCallback(dps.get(), 0);
}
return true;
}
bool View::setUpDepthPartition(DepthPartitionSettings* dsp)
{
osgDepthPartition::Cameras originalCameras = osgDepthPartition::getActiveCameras(*this);
if (originalCameras.empty())
{
OSG_INFO<<"osgView::View::setUpDepthPartition(,..), no windows assigned, doing view.setUpViewAcrossAllScreens()"<<std::endl;
setUpViewAcrossAllScreens();
originalCameras = osgDepthPartition::getActiveCameras(*this);
if (originalCameras.empty())
{
OSG_NOTICE<<"osgView::View::setUpDepthPartition(View,..) Unable to set up windows for viewer."<<std::endl;
return false;
}
}
bool threadsWereRunning = getViewerBase()->areThreadsRunning();
if (threadsWereRunning) getViewerBase()->stopThreading();
for(osgDepthPartition::Cameras::iterator itr = originalCameras.begin();
itr != originalCameras.end();
++itr)
{
setUpDepthPartitionForCamera(itr->get(), dsp);
}
if (threadsWereRunning) getViewerBase()->startThreading();
return true;
}
void View::assignSceneDataToCameras()