1 // Copyright (C) 2008 Tim Moore
3 // Much of this file was copied directly from the osgdepthpartition
4 // example in the OpenSceneGraph distribution, so I feel it is right
5 // to preserve the license in that code:
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 #include <osg/CullSettings>
25 #include <osg/StateSet>
26 #include <osgUtil/CullVisitor>
27 // For DotOsgWrapperProxy
28 #include <osgDB/Registry>
29 #include <osgDB/Input>
30 #include <osgDB/Output>
32 #include <simgear/scene/util/RenderConstants.hxx>
33 #include "ViewPartitionNode.hxx"
37 const double ViewPartitionNode::nearCameraFar = 100.0;
38 ViewPartitionNode::ViewPartitionNode():
39 cameras(3), visibility(40000.0)
41 const GLbitfield inheritanceMask = (CullSettings::ALL_VARIABLES
42 & ~CullSettings::COMPUTE_NEAR_FAR_MODE
43 & ~CullSettings::NEAR_FAR_RATIO
44 & ~CullSettings::CULLING_MODE);
46 for (CameraList::iterator iter = cameras.begin();
47 iter != cameras.end();
49 Camera* camera = new Camera;
50 camera->setReferenceFrame(Transform::RELATIVE_RF);
51 camera->setInheritanceMask(inheritanceMask);
52 camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
53 camera->setCullingMode(CullSettings::VIEW_FRUSTUM_CULLING);
54 camera->setRenderOrder(Camera::POST_RENDER, i);
57 Camera* backgroundCamera = cameras[BACKGROUND_CAMERA].get();
58 backgroundCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
59 // Turn off depth test for the background
60 Depth* depth = new Depth(Depth::LESS, 0.0, 1.0, false);
61 StateSet* backgroundSS = new StateSet;
62 backgroundSS->setAttribute(depth);
63 backgroundSS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
64 backgroundCamera->setStateSet(backgroundSS);
65 backgroundCamera->setInheritanceMask(backgroundCamera->getInheritanceMask()
66 & ~CullSettings::CULL_MASK);
67 backgroundCamera->setCullMask(simgear::BACKGROUND_BIT);
68 cameras[NEAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
69 // Background camera will have cleared the buffers and doesn't
70 // touch the depth buffer
71 cameras[FAR_CAMERA]->setClearMask(0);
74 ViewPartitionNode::ViewPartitionNode(const ViewPartitionNode& rhs,
75 const CopyOp& copyop):
76 cameras(3), visibility(rhs.visibility)
78 for (int i = 0; i < 3; i++)
79 cameras[i] = static_cast<Camera*>(copyop(rhs.cameras[i].get()));
82 void ViewPartitionNode::traverse(NodeVisitor& nv)
84 osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
89 RefMatrix& modelview = *(cv->getModelViewMatrix());
90 RefMatrix& projection = *(cv->getProjectionMatrix());
91 double left, right, bottom, top, parentNear, parentFar;
92 projection.getFrustum(left, right, bottom, top, parentNear, parentFar);
93 double farCameraFar = visibility + 1000.0;
94 double nearPlanes[3], farPlanes[3];
95 nearPlanes[0] = farCameraFar; farPlanes[0] = parentFar;
96 nearPlanes[2] = parentNear;
97 // If visibility is low, only use two cameras
98 if (farCameraFar < nearCameraFar) {
99 nearPlanes[1] = farPlanes[1] = 0.0;
100 farPlanes[2] = farCameraFar;
102 nearPlanes[1] = farPlanes[2] = nearCameraFar;
103 farPlanes[1] = farCameraFar;
104 farPlanes[2] = nearCameraFar;
107 for (int i = 0; i < 3; ++i) {
108 if (farPlanes[i] >0.0) {
109 ref_ptr<RefMatrix> newProj = new RefMatrix();
110 makeNewProjMat(projection, nearPlanes[i], farPlanes[i],
112 cv->pushProjectionMatrix(newProj.get());
113 cameras[i]->accept(nv);
114 cv->popProjectionMatrix();
119 bool ViewPartitionNode::addChild(osg::Node *child)
121 return insertChild(_children.size(), child);
124 bool ViewPartitionNode::insertChild(unsigned int index, osg::Node *child)
126 if(!Group::insertChild(index, child))
128 // Insert child into each Camera
130 for (CameraList::iterator iter = cameras.begin();
131 iter != cameras.end();
133 (*iter)->insertChild(index, child);
138 bool ViewPartitionNode::removeChildren(unsigned int pos, unsigned int numRemove)
140 if (!Group::removeChildren(pos, numRemove))
143 // Remove child from each Camera
145 for (CameraList::iterator iter = cameras.begin();
146 iter != cameras.end();
148 (*iter)->removeChildren(pos, numRemove);
153 bool ViewPartitionNode::setChild(unsigned int i, osg::Node *node)
155 if(!Group::setChild(i, node)) return false; // Set child
157 // Set child for each Camera
158 for (CameraList::iterator iter = cameras.begin();
159 iter != cameras.end();
161 (*iter)->setChild(i, node);
166 // Given a projection matrix, return a new one with the same frustum
167 // sides and new near / far values.
169 void ViewPartitionNode::makeNewProjMat(Matrixd& oldProj, double znear,
170 double zfar, Matrixd& projection)
172 projection = oldProj;
173 // Slightly inflate the near & far planes to avoid objects at the
174 // extremes being clipped out.
178 // Clamp the projection matrix z values to the range (near, far)
179 double epsilon = 1.0e-6;
180 if (fabs(projection(0,3)) < epsilon &&
181 fabs(projection(1,3)) < epsilon &&
182 fabs(projection(2,3)) < epsilon) {
183 // Projection is Orthographic
184 epsilon = -1.0/(zfar - znear); // Used as a temp variable
185 projection(2,2) = 2.0*epsilon;
186 projection(3,2) = (zfar + znear)*epsilon;
188 // Projection is Perspective
189 double trans_near = (-znear*projection(2,2) + projection(3,2)) /
190 (-znear*projection(2,3) + projection(3,3));
191 double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
192 (-zfar*projection(2,3) + projection(3,3));
193 double ratio = fabs(2.0/(trans_near - trans_far));
194 double center = -0.5*(trans_near + trans_far);
196 projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
198 0.0, 0.0, ratio, 0.0,
199 0.0, 0.0, center*ratio, 1.0));
206 bool ViewPartitionNode_readLocalData(osg::Object& obj, osgDB::Input& fr)
208 ViewPartitionNode& node = static_cast<ViewPartitionNode&>(obj);
209 if (fr[0].matchWord("visibility")) {
212 if (fr[0].getFloat(visibility))
216 node.setVisibility(visibility);
221 bool ViewPartitionNode_writeLocalData(const Object& obj, osgDB::Output& fw)
223 const ViewPartitionNode& node = static_cast<const ViewPartitionNode&>(obj);
224 fw.indent() << "visibility " << node.getVisibility() << std::endl;
228 osgDB::RegisterDotOsgWrapperProxy viewPartitionNodeProxy
230 new ViewPartitionNode,
232 "Object Node ViewPartitionNode Group",
233 &ViewPartitionNode_readLocalData,
234 &ViewPartitionNode_writeLocalData