From Ravi Mathur, osgdepthpartition example program.

This commit is contained in:
Robert Osfield 2005-10-10 10:10:44 +00:00
parent 290e0b6eed
commit b7fd3bfdc4
10 changed files with 1114 additions and 0 deletions

View File

@ -183,6 +183,7 @@ EXAMPLE_DIRS = \
osgcopy\
osgcubemap\
osgdepthshadow\
osgdepthpartition\
osgdistortion\
osgfbo\
osgforest\

View File

@ -627,6 +627,33 @@ Package=<4>
###############################################################################
Project: "Example osgdepthpartition"=.\examples\osgdepthpartition\osgdepthpartition.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name Core osg
End Project Dependency
Begin Project Dependency
Project_Dep_Name Core osgDB
End Project Dependency
Begin Project Dependency
Project_Dep_Name Core osgGA
End Project Dependency
Begin Project Dependency
Project_Dep_Name Core osgProducer
End Project Dependency
Begin Project Dependency
Project_Dep_Name Core osgUtil
End Project Dependency
}}}
###############################################################################
Project: "Example osgdepthshadow"=.\examples\osgdepthshadow\osgdepthshadow.dsp - Package Owner=<4>
Package=<5>

View File

@ -0,0 +1,125 @@
# Microsoft Developer Studio Project File - Name="Example osgdepthpartition" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=Example osgdepthpartition - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "osgdepthpartition.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "osgdepthpartition.mak" CFG="Example osgdepthpartition - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Example osgdepthpartition - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Example osgdepthpartition - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Example osgdepthpartition - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../../include" /I "../../../../OpenThreads/include" /I "../../../../Producer/include" /I "../../../../3rdParty/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /Zm200 /c
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 OpenThreadsWin32.lib opengl32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../../../bin/osgdepthpartition.exe" /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib"
!ELSEIF "$(CFG)" == "Example osgdepthpartition - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "../../../include" /I "../../../../OpenThreads/include" /I "../../../../Producer/include" /I "../../../../3rdParty/include" /D "_CONSOLE" /D "_MBCS" /D "FL_DLL" /D "WIN32" /D "_DEBUG" /YX /FD /Zm200 /c
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 OpenThreadsWin32d.lib opengl32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /out:"../../../bin/osgdepthpartitiond.exe" /pdbtype:sept /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib"
# SUBTRACT LINK32 /incremental:no
!ENDIF
# Begin Target
# Name "Example osgdepthpartition - Win32 Release"
# Name "Example osgdepthpartition - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\..\examples\osgdepthpartition\DepthPartitionNode.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\examples\osgdepthpartition\DistanceAccumulator.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\examples\osgdepthpartition\osgdepthpartition.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter ";h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\..\..\examples\osgdepthpartition\DepthPartitionNode.h
# End Source File
# Begin Source File
SOURCE=..\..\..\examples\osgdepthpartition\DistanceAccumulator.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\icons\osg_icon.rc
# End Source File
# End Group
# End Target
# End Project

View File

@ -0,0 +1,263 @@
#include "DepthPartitionNode.h"
#include <osgUtil/CullVisitor>
#include <iostream>
#define CURRENT_CLASS DepthPartitionNode
CURRENT_CLASS::CURRENT_CLASS()
{
_distAccumulator = new DistanceAccumulator;
init();
}
CURRENT_CLASS::CURRENT_CLASS(const CURRENT_CLASS& dpn, const osg::CopyOp& copyop)
: _active(dpn._active),
_renderOrder(dpn._renderOrder),
_clearColorBuffer(dpn._clearColorBuffer)
{
_distAccumulator = new DistanceAccumulator;
_numCameras = 0;
}
CURRENT_CLASS::~CURRENT_CLASS() {}
void CURRENT_CLASS::init()
{
_active = true;
_numCameras = 0;
setCullingActive(false);
_renderOrder = osg::CameraNode::POST_RENDER;
_clearColorBuffer = true;
}
void CURRENT_CLASS::setActive(bool active)
{
if(_active == active) return;
_active = active;
}
void CURRENT_CLASS::setClearColorBuffer(bool clear)
{
_clearColorBuffer = clear;
// Update the render order for the first CameraNode if it exists
if(!_cameraList.empty())
{
if(clear)
_cameraList[0]->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
_cameraList[0]->setClearMask(GL_DEPTH_BUFFER_BIT);
}
}
void CURRENT_CLASS::setRenderOrder(osg::CameraNode::RenderOrder order)
{
_renderOrder = order;
// Update the render order for existing CameraNodes
unsigned int numCameras = _cameraList.size();
for(unsigned int i = 0; i < numCameras; i++)
{
_cameraList[i]->setRenderOrder(_renderOrder);
}
}
void CURRENT_CLASS::traverse(osg::NodeVisitor &nv)
{
// If the scene hasn't been defined then don't do anything
unsigned int numChildren = _children.size();
if(numChildren == 0) return;
// If the node is not active then don't analyze it
if(!_active)
{
// Traverse the graph as usual
Group::traverse(nv);
return;
}
// If the visitor is not a cull visitor, pass it directly onto the scene.
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
if(!cv)
{
Group::traverse(nv);
return;
}
// We are in the cull traversal, so first collect information on the
// current modelview and projection matrices and viewport.
osg::RefMatrix& modelview = cv->getModelViewMatrix();
osg::RefMatrix& projection = cv->getProjectionMatrix();
osg::Viewport* viewport = cv->getViewport();
// Prepare for scene traversal.
_distAccumulator->setMatrices(modelview, projection);
_distAccumulator->setNearFarRatio(cv->getNearFarRatio());
_distAccumulator->reset();
// Step 1: Traverse the children, collecting the near/far distances.
unsigned int i;
for(i = 0; i < numChildren; i++)
{
_children[i]->accept(*(_distAccumulator.get()));
}
// Step 2: Compute the near and far distances for every CameraNode that
// should be used to render the scene.
_distAccumulator->computeCameraPairs();
// Step 3: Create the CameraNodes, and add them as children.
DistanceAccumulator::PairList& camPairs = _distAccumulator->getCameraPairs();
_numCameras = camPairs.size(); // Get the number of cameras
// Create the CameraNodes, and add them as children.
if(_numCameras > 0)
{
osg::CameraNode *currCam;
DistanceAccumulator::DistancePair currPair;
for(unsigned int j = 0; j < _numCameras; j++)
{
// Create the camera, and clamp it's projection matrix
currPair = camPairs[j]; // (near,far) pair for current camera
currCam = createOrReuseCamera(projection, currPair.first,
currPair.second, j);
// Set the modelview matrix and viewport of the camera
currCam->setViewMatrix(modelview);
currCam->setViewport(viewport);
/*
// Set our children as the camera's children
currCam->removeChild(0, currCam->getNumChildren());
for(i = 0; i < numChildren; i++)
{
currCam->addChild(_children[i].get());
}
*/
// Redirect the CullVisitor to the current camera
currCam->accept(nv);
}
// Set the clear color for the first camera
_cameraList[0]->setClearColor(cv->getRenderStage()->getClearColor());
}
}
bool CURRENT_CLASS::addChild(osg::Node *child)
{
return insertChild(_children.size(), child);
}
bool CURRENT_CLASS::insertChild(unsigned int index, osg::Node *child)
{
if(!Group::insertChild(index, child)) return false; // Insert child
// Insert child into each CameraNode
unsigned int totalCameras = _cameraList.size();
for(unsigned int i = 0; i < totalCameras; i++)
{
_cameraList[i]->insertChild(index, child);
}
return true;
}
bool CURRENT_CLASS::removeChild(osg::Node *child)
{
return Group::removeChild(child);
}
bool CURRENT_CLASS::removeChild(unsigned int pos, unsigned int numRemove)
{
if(!Group::removeChild(pos, numRemove)) return false; // Remove child
// Remove child from each CameraNode
unsigned int totalCameras = _cameraList.size();
for(unsigned int i = 0; i < totalCameras; i++)
{
_cameraList[i]->removeChild(pos, numRemove);
}
return true;
}
bool CURRENT_CLASS::setChild(unsigned int i, osg::Node *node)
{
if(!Group::setChild(i, node)) return false; // Set child
// Set child for each CameraNode
unsigned int totalCameras = _cameraList.size();
for(unsigned int i = 0; i < totalCameras; i++)
{
_cameraList[i]->setChild(i, node);
}
return true;
}
osg::CameraNode* CURRENT_CLASS::createOrReuseCamera(const osg::Matrix& proj,
double near, double far, const unsigned int &camNum)
{
if(_cameraList.size() <= camNum) _cameraList.resize(camNum+1);
osg::CameraNode *camera = _cameraList[camNum].get();
if(!camera) // Create a new CameraNode
{
camera = new osg::CameraNode;
camera->setCullingActive(false);
camera->setRenderOrder(_renderOrder);
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
// We will compute the near/far planes ourselves
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::CullSettings::ENABLE_ALL_CULLING);
if(camNum == 0 && _clearColorBuffer)
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
// Add our children to the new CameraNode's children
unsigned int numChildren = _children.size();
for(unsigned int i = 0; i < numChildren; i++)
{
camera->addChild(_children[i].get());
}
_cameraList[camNum] = camera;
}
osg::Matrixd &projection = camera->getProjectionMatrix();
projection = proj;
// Slightly inflate the near & far planes to avoid objects at the
// extremes being clipped out.
near *= 0.999;
far *= 1.001;
// Clamp the projection matrix z values to the range (near, far)
double epsilon = 1.0e-6;
if(fabs(projection(0,3)) < epsilon &&
fabs(projection(1,3)) < epsilon &&
fabs(projection(2,3)) < epsilon ) // Projection is Orthographic
{
epsilon = -1.0/(far - near); // Used as a temp variable
projection(2,2) = 2.0*epsilon;
projection(3,2) = (far + near)*epsilon;
}
else // Projection is Perspective
{
double trans_near = (-near*projection(2,2) + projection(3,2)) /
(-near*projection(2,3) + projection(3,3));
double trans_far = (-far*projection(2,2) + projection(3,2)) /
(-far*projection(2,3) + projection(3,3));
double ratio = fabs(2.0/(trans_near - trans_far));
double center = -0.5*(trans_near + trans_far);
projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, ratio, 0.0,
0.0, 0.0, center*ratio, 1.0));
}
return camera;
}
#undef CURRENT_CLASS

View File

@ -0,0 +1,77 @@
#ifndef _OF_DEPTHPARTITIONNODE_
#define _OF_DEPTHPARTITIONNODE_
#include "DistanceAccumulator.h"
#include <osg/CameraNode>
#define CURRENT_CLASS DepthPartitionNode
/**********************************************************
* Ravi Mathur
* OpenFrames API, class DepthPartitionNode
* A type of osg::Group that analyzes a scene, then partitions it into
* several segments that can be rendered separately. Each segment
* is small enough in the z-direction to avoid depth buffer problems
* for very large scenes.
**********************************************************/
class CURRENT_CLASS : public osg::Group
{
public:
CURRENT_CLASS();
CURRENT_CLASS(const CURRENT_CLASS& dpn,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Node( OpenFrames, CURRENT_CLASS ); // Common Node functions
/** Set the active state. If not active, this node will simply add the
specified scene as it's child, without analyzing it at all. */
void setActive(bool active);
inline bool getActive() const { return _active; }
/** Specify whether the color buffer should be cleared before the first
CameraNode draws it's scene. */
void setClearColorBuffer(bool clear);
inline bool getClearColorBuffer() const { return _clearColorBuffer; }
/** Specify the render order for each CameraNode */
void setRenderOrder(osg::CameraNode::RenderOrder order);
inline osg::CameraNode::RenderOrder getRenderOrder() const
{ return _renderOrder; }
/** Override update and cull traversals */
virtual void traverse(osg::NodeVisitor &nv);
/** Catch child management functions so the CameraNodes can be informed
of new/removed children */
virtual bool addChild(osg::Node *child);
virtual bool insertChild(unsigned int index, osg::Node *child);
virtual bool removeChild(osg::Node *child);
virtual bool removeChild(unsigned int pos, unsigned int numRemove = 1);
virtual bool setChild(unsigned int i, osg::Node *node);
protected:
typedef std::vector< osg::ref_ptr<osg::CameraNode> > CameraList;
~CURRENT_CLASS();
void init();
// Creates a new CameraNode object with default settings
osg::CameraNode* createOrReuseCamera(const osg::Matrix& proj, double near,
double far, const unsigned int &camNum);
bool _active; // Whether partitioning is active on the scene
// The NodeVisitor that computes cameras for the scene
osg::ref_ptr<DistanceAccumulator> _distAccumulator;
osg::CameraNode::RenderOrder _renderOrder;
bool _clearColorBuffer;
// Cameras that should be used to draw the scene. These cameras
// will be reused on every frame in order to save time and memory.
CameraList _cameraList;
unsigned int _numCameras; // Number of CameraNodes actually being used
};
#undef CURRENT_CLASS
#endif

View File

@ -0,0 +1,282 @@
#include "DistanceAccumulator.h"
#include <osg/Geode>
#include <osg/Transform>
#include <osg/Projection>
#include <algorithm>
#include <math.h>
/** Function that sees whether one DistancePair should come before another in
an sorted list. Used to sort the vector of DistancePairs. */
bool precedes(const DistanceAccumulator::DistancePair &a,
const DistanceAccumulator::DistancePair &b)
{
// This results in sorting in order of descending far distances
if(a.second > b.second) return true;
else return false;
}
/** Computes distance betwen a point and the viewpoint of a matrix */
double distance(const osg::Vec3 &coord, const osg::Matrix& matrix)
{
return -( coord[0]*matrix(0,2) + coord[1]*matrix(1,2) +
coord[2]*matrix(2,2) + matrix(3,2) );
}
#define CURRENT_CLASS DistanceAccumulator
CURRENT_CLASS::CURRENT_CLASS()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _nearFarRatio(0.0)
{
setMatrices(osg::Matrix::identity(), osg::Matrix::identity());
reset();
setNearFarRatio(0.0005);
}
CURRENT_CLASS::~CURRENT_CLASS() {}
void CURRENT_CLASS::pushLocalFrustum()
{
osg::Matrix& currMatrix = _viewMatrices.back();
// Compute the frustum in local space
osg::Polytope localFrustum;
localFrustum.setToUnitFrustum(false, false);
localFrustum.transformProvidingInverse(currMatrix*_projectionMatrices.back());
_localFrusta.push_back(localFrustum);
// Compute new bounding box corners
osg::Vec3d lookVector(-currMatrix(0,2), -currMatrix(1,2), -currMatrix(2,2));
bbCornerPair corner;
corner.second = (lookVector.x()>=0?1:0) |
(lookVector.y()>=0?2:0) |
(lookVector.z()>=0?4:0);
corner.first = (~corner.second)&7;
_bbCorners.push_back(corner);
}
void CURRENT_CLASS::apply(osg::CameraNode &camera)
{
// We don't support scenes with CameraNodes in them
return;
}
void CURRENT_CLASS::apply(osg::Projection &proj)
{
// Push the new projection matrix view frustum
_projectionMatrices.push_back(proj.getMatrix());
pushLocalFrustum();
traverse(proj); // Traverse the rest of the scene graph
// Reload original matrix and frustum
_localFrusta.pop_back();
_bbCorners.pop_back();
_projectionMatrices.pop_back();
}
void CURRENT_CLASS::apply(osg::Transform &transform)
{
// Compute transform for current node
osg::Matrix currMatrix = _viewMatrices.back();
bool pushMatrix = transform.computeLocalToWorldMatrix(currMatrix, this);
if(pushMatrix)
{
// Store the new modelview matrix and view frustum
_viewMatrices.push_back(currMatrix);
pushLocalFrustum();
}
traverse(transform); // Traverse the rest of the scene graph
if(pushMatrix)
{
// Restore the old modelview matrix and view frustum
_localFrusta.pop_back();
_bbCorners.pop_back();
_viewMatrices.pop_back();
}
}
void CURRENT_CLASS::apply(osg::Geode &geode)
{
osg::Drawable *drawable;
double zNear, zFar;
// Handle each drawable in this geode
for(unsigned int i = 0; i < geode.getNumDrawables(); i++)
{
drawable = geode.getDrawable(i);
const osg::BoundingBox &bb = drawable->getBound();
if(bb.valid())
{
// Make sure drawable will be visible in the scene
if(!_localFrusta.back().contains(bb)) continue;
// Compute near/far distances for current drawable
zNear = distance(bb.corner(_bbCorners.back().first),
_viewMatrices.back());
zFar = distance(bb.corner(_bbCorners.back().second),
_viewMatrices.back());
if(zNear > zFar) std::swap(zNear, zFar);
if(zFar > 0.0) // Make sure some of drawable is visible
{
// Make sure near plane is in front of viewpoint.
if(zNear <= 0.0)
{
zNear = zFar*_nearFarRatio;
if(zNear >= 1.0) zNear = 1.0; // 1.0 limit chosen arbitrarily!
}
// Add distance pair for current drawable and current rendering mode
_distancePairs.push_back(DistancePair(zNear, zFar));
// Override the current nearest/farthest planes if necessary
if(zNear < _limits.first) _limits.first = zNear;
if(zFar > _limits.second) _limits.second = zFar;
}
}
}
}
void CURRENT_CLASS::setMatrices(const osg::Matrix &modelview,
const osg::Matrix &projection)
{
_modelview = modelview;
_projection = projection;
}
void CURRENT_CLASS::reset()
{
// Clear vectors & values
_distancePairs.clear();
_cameraPairs.clear();
_limits.first = DBL_MAX;
_limits.second = 0.0;
// Initial transform matrix is the modelview matrix
_viewMatrices.clear();
_viewMatrices.push_back(_modelview);
// Set the initial projection matrix
_projectionMatrices.clear();
_projectionMatrices.push_back(_projection);
// Create a frustum without near/far planes, for cull computations
_localFrusta.clear();
_bbCorners.clear();
pushLocalFrustum();
}
void CURRENT_CLASS::computeCameraPairs()
{
// Nothing in the scene, so no cameras needed
if(_distancePairs.empty()) return;
// Entire scene can be handled by just one camera
if(_limits.first >= _limits.second*_nearFarRatio)
{
_cameraPairs.push_back(_limits);
return;
}
PairList::iterator i,j;
// Sort the list of distance pairs by descending far distance
std::sort(_distancePairs.begin(), _distancePairs.end(), precedes);
// Combine overlapping distance pairs. The resulting set of distance
// pairs (called combined pairs) will not overlap.
PairList combinedPairs;
DistancePair currPair = _distancePairs.front();
for(i = _distancePairs.begin(); i != _distancePairs.end(); i++)
{
// Current distance pair does not overlap current combined pair, so
// save the current combined pair and start a new one.
if(i->second < 0.99*currPair.first)
{
combinedPairs.push_back(currPair);
currPair = *i;
}
// Current distance pair overlaps current combined pair, so expand
// current combined pair to encompass distance pair.
else
currPair.first = std::min(i->first, currPair.first);
}
combinedPairs.push_back(currPair); // Add last pair
// Compute the (near,far) distance pairs for each camera.
// Each of these distance pairs is called a "view segment".
double currNearLimit, numSegs, new_ratio;
double ratio_invlog = 1.0/log(_nearFarRatio);
unsigned int temp;
for(i = combinedPairs.begin(); i != combinedPairs.end(); i++)
{
currPair = *i; // Save current view segment
// Compute the fractional number of view segments needed to span
// the current combined distance pair.
currNearLimit = currPair.second*_nearFarRatio;
if(currPair.first >= currNearLimit) numSegs = 1.0;
else
{
numSegs = log(currPair.first/currPair.second)*ratio_invlog;
// Compute the near plane of the last view segment
//currNearLimit *= pow(_nearFarRatio, -floor(-numSegs) - 1);
for(temp = (unsigned int)(-floor(-numSegs)); temp > 1; temp--)
{
currNearLimit *= _nearFarRatio;
}
}
// See if the closest view segment can absorb other combined pairs
for(j = i+1; j != combinedPairs.end(); j++)
{
// No other distance pairs can be included
if(j->first < currNearLimit) break;
}
// If we did absorb another combined distance pair, recompute the
// number of required view segments.
if(i != j-1)
{
i = j-1;
currPair.first = i->first;
if(currPair.first >= currPair.second*_nearFarRatio) numSegs = 1.0;
else numSegs = log(currPair.first/currPair.second)*ratio_invlog;
}
/* Compute an integer number of segments by rounding the fractional
number of segments according to how many segments there are.
In general, the more segments there are, the more likely that the
integer number of segments will be rounded down.
The purpose of this is to try to minimize the number of view segments
that are used to render any section of the scene without violating
the specified _nearFarRatio by too much. */
if(numSegs < 10.0) numSegs = floor(numSegs + 1.0 - 0.1*floor(numSegs));
else numSegs = floor(numSegs);
// Compute the near/far ratio that will be used for each view segment
// in this section of the scene.
new_ratio = pow(currPair.first/currPair.second, 1.0/numSegs);
// Add numSegs new view segments to the camera pairs list
for(temp = (unsigned int)numSegs; temp > 0; temp--)
{
currPair.first = currPair.second*new_ratio;
_cameraPairs.push_back(currPair);
currPair.second = currPair.first;
}
}
}
void CURRENT_CLASS::setNearFarRatio(double ratio)
{
if(_nearFarRatio == ratio || ratio <= 0.0 || ratio >= 1.0) return;
_nearFarRatio = ratio;
}
#undef CURRENT_CLASS

View File

@ -0,0 +1,87 @@
#ifndef _OF_DISTANCEACCUMULATOR_
#define _OF_DISTANCEACCUMULATOR_
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/Polytope>
#include <osg/fast_back_stack>
#define CURRENT_CLASS DistanceAccumulator
/**********************************************************
* Ravi Mathur
* OpenFrames API, class DistanceAccumulator
* Class that traverses the scene and computes the distance to each
* visible drawable, and splits up the scene if the drawables are
* too far away (in the z direction) from each other.
**********************************************************/
class CURRENT_CLASS : public osg::NodeVisitor
{
public:
typedef std::pair<double, double> DistancePair;
typedef std::vector<DistancePair> PairList;
CURRENT_CLASS();
virtual void apply(osg::CameraNode &camera);
virtual void apply(osg::Projection &proj);
virtual void apply(osg::Transform &transform);
virtual void apply(osg::Geode &geode);
// Specify the modelview & projection matrices
void setMatrices(const osg::Matrix &modelview,
const osg::Matrix &projection);
// Reset visitor before a new traversal
virtual void reset();
// Create a (near,far) distance pair for each camera of the specified
// distance pair list and distance limits.
void computeCameraPairs();
// Get info on the cameras that should be used for scene rendering
PairList& getCameraPairs() { return _cameraPairs; }
// Get info on the computed distance pairs
PairList& getDistancePairs() { return _distancePairs; }
// Get info on the computed nearest/farthest distances
DistancePair& getLimits() { return _limits; }
// Set/get the desired near/far ratio
void setNearFarRatio(double ratio);
inline double getNearFarRatio() const { return _nearFarRatio; }
protected:
virtual ~CURRENT_CLASS();
void pushLocalFrustum();
// Stack of matrices accumulated during traversal
osg::fast_back_stack<osg::Matrix> _viewMatrices;
osg::fast_back_stack<osg::Matrix> _projectionMatrices;
// Main modelview/projection matrices
osg::Matrix _modelview, _projection;
// The view frusta in local coordinate space
osg::fast_back_stack<osg::Polytope> _localFrusta;
// Bounding box corners that should be used for cull computation
typedef std::pair<unsigned int, unsigned int> bbCornerPair;
osg::fast_back_stack<bbCornerPair> _bbCorners;
// Nar/far planes that should be used for each camera
PairList _cameraPairs;
// Accumulated pairs of min/max distances
PairList _distancePairs;
// The closest & farthest distances found while traversing
DistancePair _limits;
// Ratio of nearest/farthest clip plane for each section of the scene
double _nearFarRatio;
};
#undef CURRENT_CLASS
#endif

View File

@ -0,0 +1,20 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osgdepthpartition.cpp\
DepthPartitionNode.cpp\
DistanceAccumulator.cpp\
LIBS += -losgProducer -lProducer -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
INSTFILES = \
$(CXXFILES)\
GNUmakefile.inst=GNUmakefile
EXEC = osgdepthpartion
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,15 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osgdepthpartition.cpp\
DepthPartitionNode.cpp\
DistanceAccumulator.cpp\
LIBS += -losgProducer -lProducer -losgDB -losgText -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
EXEC = osgdepthpartion
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,217 @@
//C++ source file - Open Producer - Copyright (C) 2002 Don Burns
//Distributed under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE (LGPL)
//as published by the Free Software Foundation.
// Simple example of use of Producer::RenderSurface
// The myGraphics class is a simple sample of how one would implement
// graphics drawing with Producer::RenderSurface
#include <stdio.h>
#include <Producer/Camera>
#include <Producer/CameraConfig>
#include <Producer/InputArea>
#include <Producer/KeyboardMouse>
#include <Producer/Trackball>
#include <osg/Timer>
#include <osgUtil/UpdateVisitor>
#include <osgDB/ReadFile>
#include <osg/ShapeDrawable>
#include <osg/PositionAttitudeTransform>
#include <osgProducer/OsgCameraGroup>
#include <osgProducer/OsgSceneHandler>
#include "DepthPartitionNode.h"
class MyKeyboardMouseCallback : public Producer::KeyboardMouseCallback
{
public:
MyKeyboardMouseCallback() :
Producer::KeyboardMouseCallback(),
_mx(0.0f),_my(0.0f),_mbutton(0),
_done(false)
{}
virtual void specialKeyPress( Producer::KeyCharacter key )
{
if (key==Producer::KeyChar_Escape)
shutdown();
}
virtual void shutdown()
{
_done = true;
}
virtual void keyPress( Producer::KeyCharacter )
{
}
virtual void mouseMotion( float mx, float my )
{
_mx = mx;
_my = my;
}
virtual void buttonPress( float mx, float my, unsigned int mbutton )
{
_mx = mx;
_my = my;
_mbutton |= (1<<(mbutton-1));
}
virtual void buttonRelease( float mx, float my, unsigned int mbutton )
{
_mx = mx;
_my = my;
_mbutton &= ~(1<<(mbutton-1));
}
bool done() { return _done; }
float mx() { return _mx; }
float my() { return _my; }
unsigned int mbutton() { return _mbutton; }
private:
float _mx, _my;
unsigned int _mbutton;
bool _done;
};
const double r_earth = 6378.137;
const double r_sun = 695990.0;
const double AU = 149697900.0;
osg::Node* createScene()
{
// Create the Earth, in blue
osg::ShapeDrawable *earth_sd = new osg::ShapeDrawable;
osg::Sphere* earth_sphere = new osg::Sphere;
earth_sphere->setRadius(r_earth);
earth_sd->setShape(earth_sphere);
earth_sd->setColor(osg::Vec4(0, 0, 1.0, 1.0));
osg::Geode* earth = new osg::Geode;
earth->setName("earth");
earth->addDrawable(earth_sd);
// Create the Sun, in yellow
osg::ShapeDrawable *sun_sd = new osg::ShapeDrawable;
osg::Sphere* sun_sphere = new osg::Sphere;
sun_sphere->setRadius(r_sun);
sun_sd->setShape(sun_sphere);
sun_sd->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));
osg::Geode* sun = new osg::Geode;
sun->setName("sun");
sun->addDrawable(sun_sd);
// Move the sun behind the earth
osg::PositionAttitudeTransform *pat = new osg::PositionAttitudeTransform;
pat->setPosition(osg::Vec3d(0.0, AU, 0.0));
osg::Group* scene = new osg::Group;
scene->addChild(earth);
scene->addChild(pat);
pat->addChild(sun);
return scene;
}
int main( int argc, char **argv )
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
// set up the usage document, in case we need to print out how to use this program.
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard example of using osgProducer::CameraGroup.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] ...");
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
// create the camera group.
osgProducer::OsgCameraGroup cg(arguments);
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
arguments.getApplicationUsage()->write(std::cout);
return 1;
}
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occured when parsing the program aguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// set up the keyboard and mouse handling.
Producer::InputArea *ia = cg.getCameraConfig()->getInputArea();
Producer::KeyboardMouse *kbm = ia ?
(new Producer::KeyboardMouse(ia)) :
(new Producer::KeyboardMouse(cg.getCamera(0)->getRenderSurface()));
osg::ref_ptr<MyKeyboardMouseCallback> kbmcb = new MyKeyboardMouseCallback;
// register the callback with the keyboard mouse manger.
kbm->setCallback( kbmcb.get() );
kbm->startThread();
// Create a DepthPartitionNode to manage partitioning of the scene
DepthPartitionNode *dpn = new DepthPartitionNode;
osg::Node* scene = createScene();
dpn->addChild(scene);
dpn->setActive(true); // Control whether the node analyzes the scene
// set the scene to render
cg.setSceneData(dpn);
// Set the view to be looking at the earth
osg::BoundingSphere bs;
bs._radius = r_earth;
osg::ref_ptr<Producer::Trackball> tb = new Producer::Trackball;
tb->setOrientation( Producer::Trackball::Z_UP );
tb->setDistance(bs.radius()*10.0f);
tb->translate(-bs.center().x(),-bs.center().y(),-bs.center().z());
// create the windows and run the threads.
cg.realize();
osgUtil::UpdateVisitor update;
while( !kbmcb->done() )
{
// syncronize to the when cull and draw threads have completed.
cg.sync();
// update the scene by traversing it with the the update visitor which will
// call all node update callbacks and animations.
cg.getSceneData()->accept(update);
tb->input( kbmcb->mx(), kbmcb->my(), kbmcb->mbutton() );
// update the main producer camera
cg.setViewByMatrix(tb->getMatrix());
// fire off the cull and draw traversals of the scene.
cg.frame();
}
// syncronize to the when cull and draw threads have completed.
cg.sync();
return 0;
}