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(2), 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
45 & ~CullSettings::CULL_MASK);
47 for (CameraList::iterator iter = cameras.begin();
48 iter != cameras.end();
50 Camera* camera = new Camera;
51 camera->setReferenceFrame(Transform::RELATIVE_RF);
52 camera->setInheritanceMask(inheritanceMask);
53 camera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
54 camera->setCullingMode(CullSettings::VIEW_FRUSTUM_CULLING);
55 camera->setRenderOrder(Camera::POST_RENDER, i);
59 cameras[NEAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
60 // Background camera will have cleared the buffers and doesn't
61 // touch the depth buffer
62 cameras[FAR_CAMERA]->setClearMask(GL_DEPTH_BUFFER_BIT);
63 // near camera shouldn't render the background.
64 cameras[NEAR_CAMERA]->setCullMask(cameras[NEAR_CAMERA]->getCullMask()
65 & ~simgear::BACKGROUND_BIT);
68 ViewPartitionNode::ViewPartitionNode(const ViewPartitionNode& rhs,
69 const CopyOp& copyop):
70 cameras(2), visibility(rhs.visibility)
72 for (int i = 0; i < 2; i++)
73 cameras[i] = static_cast<Camera*>(copyop(rhs.cameras[i].get()));
76 void ViewPartitionNode::traverse(NodeVisitor& nv)
78 osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
83 RefMatrix& modelview = *(cv->getModelViewMatrix());
84 RefMatrix& projection = *(cv->getProjectionMatrix());
85 // Get the frustum of the enclosing camera. The ViewPartitionNode
86 // will divide up the frustum between that camera's near and far
87 // planes i.e., parentNear and ParentFar.
88 double left, right, bottom, top, parentNear, parentFar;
89 projection.getFrustum(left, right, bottom, top, parentNear, parentFar);
90 double nearPlanes[2], farPlanes[2];
91 nearPlanes[0] = nearCameraFar;
92 farPlanes[0] = parentFar;
93 nearPlanes[1] = parentNear;
94 farPlanes[1] = nearCameraFar;
96 for (int i = 0; i < 2; ++i) {
97 if (farPlanes[i] >0.0) {
98 ref_ptr<RefMatrix> newProj = new RefMatrix();
99 makeNewProjMat(projection, nearPlanes[i], farPlanes[i],
101 cv->pushProjectionMatrix(newProj.get());
102 cameras[i]->accept(nv);
103 cv->popProjectionMatrix();
108 bool ViewPartitionNode::addChild(osg::Node *child)
110 return insertChild(_children.size(), child);
113 bool ViewPartitionNode::insertChild(unsigned int index, osg::Node *child)
115 if(!Group::insertChild(index, child))
117 // Insert child into each Camera
119 for (CameraList::iterator iter = cameras.begin();
120 iter != cameras.end();
122 (*iter)->insertChild(index, child);
127 bool ViewPartitionNode::removeChildren(unsigned int pos, unsigned int numRemove)
129 if (!Group::removeChildren(pos, numRemove))
132 // Remove child from each Camera
134 for (CameraList::iterator iter = cameras.begin();
135 iter != cameras.end();
137 (*iter)->removeChildren(pos, numRemove);
142 bool ViewPartitionNode::setChild(unsigned int i, osg::Node *node)
144 if(!Group::setChild(i, node)) return false; // Set child
146 // Set child for each Camera
147 for (CameraList::iterator iter = cameras.begin();
148 iter != cameras.end();
150 (*iter)->setChild(i, node);
155 // Given a projection matrix, return a new one with the same frustum
156 // sides and new near / far values.
158 void ViewPartitionNode::makeNewProjMat(Matrixd& oldProj, double znear,
159 double zfar, Matrixd& projection)
161 projection = oldProj;
162 // Slightly inflate the near & far planes to avoid objects at the
163 // extremes being clipped out.
167 // Clamp the projection matrix z values to the range (near, far)
168 double epsilon = 1.0e-6;
169 if (fabs(projection(0,3)) < epsilon &&
170 fabs(projection(1,3)) < epsilon &&
171 fabs(projection(2,3)) < epsilon) {
172 // Projection is Orthographic
173 epsilon = -1.0/(zfar - znear); // Used as a temp variable
174 projection(2,2) = 2.0*epsilon;
175 projection(3,2) = (zfar + znear)*epsilon;
177 // Projection is Perspective
178 double trans_near = (-znear*projection(2,2) + projection(3,2)) /
179 (-znear*projection(2,3) + projection(3,3));
180 double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
181 (-zfar*projection(2,3) + projection(3,3));
182 double ratio = fabs(2.0/(trans_near - trans_far));
183 double center = -0.5*(trans_near + trans_far);
185 projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
187 0.0, 0.0, ratio, 0.0,
188 0.0, 0.0, center*ratio, 1.0));
195 bool ViewPartitionNode_readLocalData(osg::Object& obj, osgDB::Input& fr)
197 ViewPartitionNode& node = static_cast<ViewPartitionNode&>(obj);
198 if (fr[0].matchWord("visibility")) {
201 if (fr[0].getFloat(visibility))
205 node.setVisibility(visibility);
210 bool ViewPartitionNode_writeLocalData(const Object& obj, osgDB::Output& fw)
212 const ViewPartitionNode& node = static_cast<const ViewPartitionNode&>(obj);
213 fw.indent() << "visibility " << node.getVisibility() << std::endl;
217 osgDB::RegisterDotOsgWrapperProxy viewPartitionNodeProxy
219 new ViewPartitionNode,
221 "Object Node ViewPartitionNode Group",
222 &ViewPartitionNode_readLocalData,
223 &ViewPartitionNode_writeLocalData