OpenSceneGraph/examples/osgdepthpartition/DepthPartitionNode.cpp

273 lines
8.5 KiB
C++
Raw Normal View History

/* OpenSceneGraph example, osgdepthpartion.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "DepthPartitionNode.h"
#include <osgUtil/CullVisitor>
2005-12-05 18:24:02 +08:00
using namespace osg;
#define CURRENT_CLASS DepthPartitionNode
2005-12-05 18:24:02 +08:00
CURRENT_CLASS::CURRENT_CLASS()
{
2005-11-18 04:22:55 +08:00
_distAccumulator = new DistanceAccumulator;
init();
}
CURRENT_CLASS::CURRENT_CLASS(const CURRENT_CLASS& dpn, const osg::CopyOp& copyop)
2005-12-05 18:24:02 +08:00
: osg::Group(dpn, copyop),
2005-11-09 18:37:10 +08:00
_active(dpn._active),
2005-11-18 04:22:55 +08:00
_renderOrder(dpn._renderOrder),
_clearColorBuffer(dpn._clearColorBuffer)
{
2005-11-18 04:22:55 +08:00
_distAccumulator = new DistanceAccumulator;
_numCameras = 0;
}
CURRENT_CLASS::~CURRENT_CLASS() {}
void CURRENT_CLASS::init()
{
2005-11-18 04:22:55 +08:00
_active = true;
_numCameras = 0;
setCullingActive(false);
_renderOrder = osg::Camera::POST_RENDER;
2005-11-18 04:22:55 +08:00
_clearColorBuffer = true;
}
void CURRENT_CLASS::setActive(bool active)
{
2005-11-18 04:22:55 +08:00
if(_active == active) return;
_active = active;
}
void CURRENT_CLASS::setClearColorBuffer(bool clear)
{
2005-11-18 04:22:55 +08:00
_clearColorBuffer = clear;
// Update the render order for the first Camera if it exists
2005-11-18 04:22:55 +08:00
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::Camera::RenderOrder order)
{
2005-11-18 04:22:55 +08:00
_renderOrder = order;
// Update the render order for existing Cameras
2005-11-18 04:22:55 +08:00
unsigned int numCameras = _cameraList.size();
for(unsigned int i = 0; i < numCameras; i++)
{
_cameraList[i]->setRenderOrder(_renderOrder);
}
}
void CURRENT_CLASS::traverse(osg::NodeVisitor &nv)
{
2005-11-18 04:22:55 +08:00
// 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());
2005-11-18 04:22:55 +08:00
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 Camera that
2005-11-18 04:22:55 +08:00
// should be used to render the scene.
_distAccumulator->computeCameraPairs();
// Step 3: Create the Cameras, and add them as children.
2005-11-18 04:22:55 +08:00
DistanceAccumulator::PairList& camPairs = _distAccumulator->getCameraPairs();
_numCameras = camPairs.size(); // Get the number of cameras
// Create the Cameras, and add them as children.
2005-11-18 04:22:55 +08:00
if(_numCameras > 0)
{
osg::Camera *currCam;
2005-11-18 04:22:55 +08:00
DistanceAccumulator::DistancePair currPair;
for(i = 0; i < _numCameras; i++)
{
// Create the camera, and clamp it's projection matrix
currPair = camPairs[i]; // (near,far) pair for current camera
currCam = createOrReuseCamera(projection, currPair.first,
currPair.second, i);
// Set the modelview matrix and viewport of the camera
currCam->setViewMatrix(modelview);
currCam->setViewport(viewport);
// 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)
{
2005-11-18 04:22:55 +08:00
return insertChild(_children.size(), child);
}
bool CURRENT_CLASS::insertChild(unsigned int index, osg::Node *child)
{
2005-11-18 04:22:55 +08:00
if(!Group::insertChild(index, child)) return false; // Insert child
// Insert child into each Camera
2005-11-18 04:22:55 +08:00
unsigned int totalCameras = _cameraList.size();
for(unsigned int i = 0; i < totalCameras; i++)
{
_cameraList[i]->insertChild(index, child);
}
return true;
}
bool CURRENT_CLASS::removeChildren(unsigned int pos, unsigned int numRemove)
{
if(!Group::removeChildren(pos, numRemove)) return false; // Remove child
2005-11-18 04:22:55 +08:00
// Remove child from each Camera
2005-11-18 04:22:55 +08:00
unsigned int totalCameras = _cameraList.size();
for(unsigned int i = 0; i < totalCameras; i++)
{
_cameraList[i]->removeChildren(pos, numRemove);
2005-11-18 04:22:55 +08:00
}
return true;
}
bool CURRENT_CLASS::setChild(unsigned int i, osg::Node *node)
{
2005-11-18 04:22:55 +08:00
if(!Group::setChild(i, node)) return false; // Set child
// Set child for each Camera
2005-11-18 04:22:55 +08:00
unsigned int totalCameras = _cameraList.size();
for(unsigned int j = 0; j < totalCameras; j++)
{
_cameraList[j]->setChild(i, node);
}
return true;
}
osg::Camera* CURRENT_CLASS::createOrReuseCamera(const osg::Matrix& proj,
2005-11-11 03:16:01 +08:00
double znear, double zfar,
const unsigned int &camNum)
{
2005-11-18 04:22:55 +08:00
if(_cameraList.size() <= camNum) _cameraList.resize(camNum+1);
osg::Camera *camera = _cameraList[camNum].get();
2005-11-18 04:22:55 +08:00
if(!camera) // Create a new Camera
2005-11-18 04:22:55 +08:00
{
camera = new osg::Camera;
2005-11-18 04:22:55 +08:00
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 Camera's children
2005-11-18 04:22:55 +08:00
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.
znear *= 0.999;
zfar *= 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/(zfar - znear); // Used as a temp variable
projection(2,2) = 2.0*epsilon;
projection(3,2) = (zfar + znear)*epsilon;
}
else // Projection is Perspective
{
double trans_near = (-znear*projection(2,2) + projection(3,2)) /
(-znear*projection(2,3) + projection(3,3));
double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
(-zfar*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