--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// Much of this file was copied directly from the osgdepthpartition
+// example in the OpenSceneGraph distribution, so I feel it is right
+// to preserve the license in that code:
+/*
+* 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 <osg/CullSettings>
+#include <osg/Depth>
+#include <osg/StateSet>
+#include <osgUtil/CullVisitor>
+// For DotOsgWrapperProxy
+#include <osgDB/Registry>
+#include <osgDB/Input>
+#include <osgDB/Output>
+
+#include <simgear/scene/util/RenderConstants.hxx>
+#include "ViewPartitionNode.hxx"
+
+using namespace osg;
+
+const double ViewPartitionNode::nearCameraFar = 100.0;
+ViewPartitionNode::ViewPartitionNode():
+ cameras(3), visibility(40000.0)
+{
+ const GLbitfield inheritanceMask = (CullSettings::ALL_VARIABLES
+ & ~CullSettings::COMPUTE_NEAR_FAR_MODE
+ & ~CullSettings::NEAR_FAR_RATIO
+ & ~CullSettings::CULLING_MODE);
+ int i = 1;
+ for (CameraList::iterator iter = cameras.begin();
+ iter != cameras.end();
+ ++iter, ++i) {
+ Camera* camera = new Camera;
+ camera->setReferenceFrame(Transform::RELATIVE_RF);
+ camera->setInheritanceMask(inheritanceMask);
+ camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+ camera->setCullingMode(CullSettings::VIEW_FRUSTUM_CULLING);
+ camera->setRenderOrder(Camera::POST_RENDER, i);
+ *iter = camera;
+ }
+ Camera* backgroundCamera = cameras[BACKGROUND_CAMERA].get();
+ backgroundCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
+ // Turn off depth test for the background
+ Depth* depth = new Depth(Depth::LESS, 0.0, 1.0, false);
+ StateSet* backgroundSS = new StateSet;
+ backgroundSS->setAttribute(depth);
+ backgroundSS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
+ backgroundCamera->setStateSet(backgroundSS);
+ backgroundCamera->setInheritanceMask(backgroundCamera->getInheritanceMask()
+ & ~CullSettings::CULL_MASK);
+ backgroundCamera->setCullMask(simgear::BACKGROUND_BIT);
+ cameras[NEAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
+ // Background camera will have cleared the buffers and doesn't
+ // touch the depth buffer
+ cameras[FAR_CAMERA]->setClearMask(0);
+}
+
+ViewPartitionNode::ViewPartitionNode(const ViewPartitionNode& rhs,
+ const CopyOp& copyop):
+cameras(3), visibility(rhs.visibility)
+{
+ for (int i = 0; i < 3; i++)
+ cameras[i] = static_cast<Camera*>(copyop(rhs.cameras[i].get()));
+}
+
+void ViewPartitionNode::traverse(NodeVisitor& nv)
+{
+ osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
+ if(!cv) {
+ Group::traverse(nv);
+ return;
+ }
+ RefMatrix& modelview = *(cv->getModelViewMatrix());
+ RefMatrix& projection = *(cv->getProjectionMatrix());
+ double left, right, bottom, top, parentNear, parentFar;
+ projection.getFrustum(left, right, bottom, top, parentNear, parentFar);
+ double farCameraFar = visibility + 1000.0;
+ double nearPlanes[3], farPlanes[3];
+ nearPlanes[0] = farCameraFar; farPlanes[0] = parentFar;
+ nearPlanes[2] = parentNear;
+ // If visibility is low, only use two cameras
+ if (farCameraFar < nearCameraFar) {
+ nearPlanes[1] = farPlanes[1] = 0.0;
+ farPlanes[2] = farCameraFar;
+ } else {
+ nearPlanes[1] = farPlanes[2] = nearCameraFar;
+ farPlanes[1] = farCameraFar;
+ farPlanes[2] = nearCameraFar;
+
+ }
+ for (int i = 0; i < 3; ++i) {
+ if (farPlanes[i] >0.0) {
+ ref_ptr<RefMatrix> newProj = new RefMatrix();
+ makeNewProjMat(projection, nearPlanes[i], farPlanes[i],
+ *newProj.get());
+ cv->pushProjectionMatrix(newProj.get());
+ cameras[i]->accept(nv);
+ cv->popProjectionMatrix();
+ }
+ }
+}
+
+bool ViewPartitionNode::addChild(osg::Node *child)
+{
+ return insertChild(_children.size(), child);
+}
+
+bool ViewPartitionNode::insertChild(unsigned int index, osg::Node *child)
+{
+ if(!Group::insertChild(index, child))
+ return false;
+ // Insert child into each Camera
+
+ for (CameraList::iterator iter = cameras.begin();
+ iter != cameras.end();
+ ++iter) {
+ (*iter)->insertChild(index, child);
+ }
+ return true;
+}
+
+bool ViewPartitionNode::removeChildren(unsigned int pos, unsigned int numRemove)
+{
+ if (!Group::removeChildren(pos, numRemove))
+ return false;
+
+ // Remove child from each Camera
+
+ for (CameraList::iterator iter = cameras.begin();
+ iter != cameras.end();
+ ++iter) {
+ (*iter)->removeChildren(pos, numRemove);
+ }
+ return true;
+}
+
+bool ViewPartitionNode::setChild(unsigned int i, osg::Node *node)
+{
+ if(!Group::setChild(i, node)) return false; // Set child
+
+ // Set child for each Camera
+ for (CameraList::iterator iter = cameras.begin();
+ iter != cameras.end();
+ ++iter) {
+ (*iter)->setChild(i, node);
+ }
+ return true;
+}
+
+// Given a projection matrix, return a new one with the same frustum
+// sides and new near / far values.
+
+void ViewPartitionNode::makeNewProjMat(Matrixd& oldProj, double znear,
+ double zfar, Matrixd& projection)
+{
+ projection = oldProj;
+ // 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));
+ }
+
+}
+
+namespace
+{
+bool ViewPartitionNode_readLocalData(osg::Object& obj, osgDB::Input& fr)
+{
+ ViewPartitionNode& node = static_cast<ViewPartitionNode&>(obj);
+ if (fr[0].matchWord("visibility")) {
+ ++fr;
+ double visibility;
+ if (fr[0].getFloat(visibility))
+ ++fr;
+ else
+ return false;
+ node.setVisibility(visibility);
+ }
+ return true;
+}
+
+bool ViewPartitionNode_writeLocalData(const Object& obj, osgDB::Output& fw)
+{
+ const ViewPartitionNode& node = static_cast<const ViewPartitionNode&>(obj);
+ fw.indent() << "visibility " << node.getVisibility() << std::endl;
+ return true;
+}
+
+osgDB::RegisterDotOsgWrapperProxy viewPartitionNodeProxy
+(
+ new ViewPartitionNode,
+ "ViewPartitionNode",
+ "Object Node ViewPartitionNode Group",
+ &ViewPartitionNode_readLocalData,
+ &ViewPartitionNode_writeLocalData
+ );
+}
--- /dev/null
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef VIEWPARTITIONNODE_HXX
+#define VIEWPARTITIONNODE_HXX 1
+// The ViewPartitionNode splits the viewing frustum inherited from a
+// camera higher in the scene graph (usually the Viewer master or
+// slave camera) into 3 parts: from the parent near plane to a
+// intermediate far plane (100m), then out to the current visibility,
+// and then beyond where background stuff is rendered. The depth
+// buffer and depth testing are disabled for the background.
+
+#include <osg/Camera>
+#include <osg/Group>
+#include <osg/Matrix>
+
+class ViewPartitionNode : public osg::Group
+{
+public:
+ ViewPartitionNode();
+ ViewPartitionNode(const ViewPartitionNode& rhs,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ META_Node(flightgear, ViewPartitionNode);
+
+ /** Catch child management functions so the Cameras can be informed
+ of added or removed children. */
+ virtual bool addChild(osg::Node *child);
+ virtual bool insertChild(unsigned int index, osg::Node *child);
+ virtual bool removeChildren(unsigned int pos, unsigned int numRemove = 1);
+ virtual bool setChild(unsigned int i, osg::Node *node);
+ virtual void traverse(osg::NodeVisitor &nv);
+ void setVisibility(double vis) { visibility = vis; }
+ double getVisibility() const { return visibility; }
+protected:
+ void makeNewProjMat(osg::Matrixd& oldProj, double znear, double zfar,
+ osg::Matrixd& projection);
+ typedef std::vector< osg::ref_ptr<osg::Camera> > CameraList;
+ CameraList cameras;
+ enum CameraNum {
+ BACKGROUND_CAMERA = 0,
+ FAR_CAMERA = 1,
+ NEAR_CAMERA = 2
+ };
+ double visibility;
+ static const double nearCameraFar;
+};
+#endif
#include "splash.hxx"
#include "renderer.hxx"
#include "main.hxx"
+#include "ViewPartitionNode.hxx"
// XXX Make this go away when OSG 2.2 is released.
#if (FG_OSG_VERSION >= 21004)
static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
-static osg::ref_ptr<osg::Camera> mBackGroundCamera = new osg::Camera;
+static osg::ref_ptr<ViewPartitionNode> viewPartition = new ViewPartitionNode;
FGRenderer::FGRenderer()
{
stateSet->setAttribute(hint);
// this is the topmost scenegraph node for osg
+#if 0
mBackGroundCamera->addChild(thesky->getPreRoot());
mBackGroundCamera->setClearMask(0);
stateSet = mBackGroundCamera->getOrCreateStateSet();
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-
+#endif
osg::Group* sceneGroup = new osg::Group;
sceneGroup->addChild(globals->get_scenery()->get_scene_graph());
- sceneGroup->addChild(thesky->getCloudRoot());
+ sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
+
+ //sceneGroup->addChild(thesky->getCloudRoot());
stateSet = sceneGroup->getOrCreateStateSet();
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
// relative because of CameraView being just a clever transform node
lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
- mRoot->addChild(lightSource);
-
- lightSource->addChild(mBackGroundCamera.get());
+
lightSource->addChild(sceneGroup);
-
+ lightSource->addChild(thesky->getPreRoot());
+ mRoot->addChild(lightSource);
stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
osg::Camera* guiCamera = new osg::Camera;
guiCamera->setRenderOrder(osg::Camera::POST_RENDER, 100);
guiCamera->setClearMask(0);
- inheritanceMask = osg::CullSettings::ALL_VARIABLES;
+ GLbitfield inheritanceMask = osg::CullSettings::ALL_VARIABLES;
inheritanceMask &= ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE;
inheritanceMask &= ~osg::CullSettings::CULLING_MODE;
guiCamera->setInheritanceMask(inheritanceMask);
osg::Switch* sw = new osg::Switch;
sw->setUpdateCallback(new FGScenerySwitchCallback);
sw->addChild(mRoot.get());
+ viewPartition->addChild(sw);
+ viewPartition->addChild(thesky->getCloudRoot());
- mRealRoot->addChild(sw);
+ mRealRoot->addChild(viewPartition.get());
mRealRoot->addChild(FGCreateRedoutNode());
mRealRoot->addChild(guiCamera);
}
l->adj_fog_color(),
l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
mUpdateVisitor->setVisibility(actual_visibility);
+ viewPartition->setVisibility(actual_visibility);
simgear::GroundLightManager::instance()->update(mUpdateVisitor.get());
bool hotspots = fgGetBool("/sim/panel-hotspots");
- osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
+ osg::Node::NodeMask cullMask = (~simgear::LIGHTS_BITS & ~simgear::PICK_BIT
+ & ~simgear::BACKGROUND_BIT);
cullMask |= simgear::GroundLightManager::instance()
->getLightNodeMask(mUpdateVisitor.get());
if (hotspots)
cullMask |= simgear::PICK_BIT;
camera->setCullMask(cullMask);
+ // XXX
for (int i = 0; i < viewer->getNumSlaves(); ++i)
viewer->getSlave(i)._camera->setCullMask(cullMask);
}