root/OpenSceneGraph/trunk/examples/osgdepthpartition/DepthPartitionNode.cpp @ 6941

Revision 6941, 8.5 kB (checked in by robert, 8 years ago)

From Martin Lavery and Robert Osfield, Updated examples to use a variation of the MIT License

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgdepthpartion.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include "DepthPartitionNode.h"
20#include <osgUtil/CullVisitor>
21
22using namespace osg;
23
24#define CURRENT_CLASS DepthPartitionNode
25
26CURRENT_CLASS::CURRENT_CLASS()
27{
28    _distAccumulator = new DistanceAccumulator;
29    init();
30}
31
32CURRENT_CLASS::CURRENT_CLASS(const CURRENT_CLASS& dpn, const osg::CopyOp& copyop)
33    : osg::Group(dpn, copyop),
34          _active(dpn._active),
35          _renderOrder(dpn._renderOrder),
36          _clearColorBuffer(dpn._clearColorBuffer)
37{
38    _distAccumulator = new DistanceAccumulator;
39    _numCameras = 0;
40}
41
42CURRENT_CLASS::~CURRENT_CLASS() {}
43
44void CURRENT_CLASS::init()
45{
46    _active = true;
47    _numCameras = 0;
48    setCullingActive(false);
49    _renderOrder = osg::Camera::POST_RENDER;
50    _clearColorBuffer = true;
51}
52
53void CURRENT_CLASS::setActive(bool active)
54{
55    if(_active == active) return;
56    _active = active;
57}
58
59void CURRENT_CLASS::setClearColorBuffer(bool clear)
60{
61    _clearColorBuffer = clear;
62
63    // Update the render order for the first Camera if it exists
64    if(!_cameraList.empty())
65    {
66      if(clear)
67        _cameraList[0]->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
68      else 
69        _cameraList[0]->setClearMask(GL_DEPTH_BUFFER_BIT);
70    }
71}
72
73void CURRENT_CLASS::setRenderOrder(osg::Camera::RenderOrder order)
74{
75    _renderOrder = order;
76
77    // Update the render order for existing Cameras
78    unsigned int numCameras = _cameraList.size();
79    for(unsigned int i = 0; i < numCameras; i++)
80    {
81      _cameraList[i]->setRenderOrder(_renderOrder);
82    }
83}
84
85void CURRENT_CLASS::traverse(osg::NodeVisitor &nv)
86{
87    // If the scene hasn't been defined then don't do anything
88    unsigned int numChildren = _children.size();
89    if(numChildren == 0) return;
90
91    // If the node is not active then don't analyze it
92    if(!_active)
93    {
94      // Traverse the graph as usual
95      Group::traverse(nv);
96      return;
97    }
98
99    // If the visitor is not a cull visitor, pass it directly onto the scene.
100    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
101    if(!cv)
102    {
103      Group::traverse(nv);
104      return;
105    }
106
107    // We are in the cull traversal, so first collect information on the
108    // current modelview and projection matrices and viewport.
109    osg::RefMatrix& modelview = *(cv->getModelViewMatrix());
110    osg::RefMatrix& projection = *(cv->getProjectionMatrix());
111    osg::Viewport* viewport = cv->getViewport();
112
113    // Prepare for scene traversal.
114    _distAccumulator->setMatrices(modelview, projection);
115    _distAccumulator->setNearFarRatio(cv->getNearFarRatio());
116    _distAccumulator->reset();
117
118    // Step 1: Traverse the children, collecting the near/far distances.
119    unsigned int i;
120    for(i = 0; i < numChildren; i++)
121    {
122      _children[i]->accept(*(_distAccumulator.get()));
123    }
124
125    // Step 2: Compute the near and far distances for every Camera that
126    // should be used to render the scene.
127    _distAccumulator->computeCameraPairs();
128
129    // Step 3: Create the Cameras, and add them as children.
130    DistanceAccumulator::PairList& camPairs = _distAccumulator->getCameraPairs();
131    _numCameras = camPairs.size(); // Get the number of cameras
132
133    // Create the Cameras, and add them as children.
134    if(_numCameras > 0)
135    {
136      osg::Camera *currCam;
137      DistanceAccumulator::DistancePair currPair;
138
139      for(i = 0; i < _numCameras; i++)
140      {
141        // Create the camera, and clamp it's projection matrix
142        currPair = camPairs[i];  // (near,far) pair for current camera
143        currCam = createOrReuseCamera(projection, currPair.first,
144                                      currPair.second, i);
145
146        // Set the modelview matrix and viewport of the camera
147        currCam->setViewMatrix(modelview);
148        currCam->setViewport(viewport);
149
150        // Redirect the CullVisitor to the current camera
151        currCam->accept(nv);
152      }
153
154      // Set the clear color for the first camera
155      _cameraList[0]->setClearColor(cv->getRenderStage()->getClearColor());
156    }
157}
158
159bool CURRENT_CLASS::addChild(osg::Node *child)
160{
161    return insertChild(_children.size(), child);
162}
163
164bool CURRENT_CLASS::insertChild(unsigned int index, osg::Node *child)
165{
166    if(!Group::insertChild(index, child)) return false; // Insert child
167
168    // Insert child into each Camera
169    unsigned int totalCameras = _cameraList.size();
170    for(unsigned int i = 0; i < totalCameras; i++)
171    {
172      _cameraList[i]->insertChild(index, child);
173    }
174    return true;
175}
176
177
178bool CURRENT_CLASS::removeChildren(unsigned int pos, unsigned int numRemove)
179{
180    if(!Group::removeChildren(pos, numRemove)) return false; // Remove child
181
182    // Remove child from each Camera
183    unsigned int totalCameras = _cameraList.size();
184    for(unsigned int i = 0; i < totalCameras; i++)
185    {
186      _cameraList[i]->removeChildren(pos, numRemove);
187    }
188    return true;
189}
190
191bool CURRENT_CLASS::setChild(unsigned int i, osg::Node *node)
192{
193    if(!Group::setChild(i, node)) return false; // Set child
194
195    // Set child for each Camera
196    unsigned int totalCameras = _cameraList.size();
197    for(unsigned int j = 0; j < totalCameras; j++)
198    {
199      _cameraList[j]->setChild(i, node);
200    }
201    return true;
202}
203
204osg::Camera* CURRENT_CLASS::createOrReuseCamera(const osg::Matrix& proj,
205                            double znear, double zfar,
206                            const unsigned int &camNum)
207{
208    if(_cameraList.size() <= camNum) _cameraList.resize(camNum+1);
209    osg::Camera *camera = _cameraList[camNum].get();
210   
211    if(!camera) // Create a new Camera
212    {
213      camera = new osg::Camera;
214      camera->setCullingActive(false);
215      camera->setRenderOrder(_renderOrder);
216      camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
217
218      // We will compute the near/far planes ourselves
219      camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
220      camera->setCullingMode(osg::CullSettings::ENABLE_ALL_CULLING);
221
222      if(camNum == 0 && _clearColorBuffer)
223        camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
224      else
225        camera->setClearMask(GL_DEPTH_BUFFER_BIT);
226
227      // Add our children to the new Camera's children
228      unsigned int numChildren = _children.size();
229      for(unsigned int i = 0; i < numChildren; i++)
230      {
231        camera->addChild(_children[i].get());
232      }
233
234      _cameraList[camNum] = camera;
235    }
236
237    osg::Matrixd &projection = camera->getProjectionMatrix();
238    projection = proj;
239
240    // Slightly inflate the near & far planes to avoid objects at the
241    // extremes being clipped out.
242    znear *= 0.999;
243    zfar *= 1.001;
244
245    // Clamp the projection matrix z values to the range (near, far)
246    double epsilon = 1.0e-6;
247    if(fabs(projection(0,3)) < epsilon &&
248       fabs(projection(1,3)) < epsilon &&
249       fabs(projection(2,3)) < epsilon ) // Projection is Orthographic
250    {
251      epsilon = -1.0/(zfar - znear); // Used as a temp variable
252      projection(2,2) = 2.0*epsilon;
253      projection(3,2) = (zfar + znear)*epsilon;
254    }
255    else // Projection is Perspective
256    {
257      double trans_near = (-znear*projection(2,2) + projection(3,2)) /
258                          (-znear*projection(2,3) + projection(3,3));
259      double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
260                         (-zfar*projection(2,3) + projection(3,3));
261      double ratio = fabs(2.0/(trans_near - trans_far));
262      double center = -0.5*(trans_near + trans_far);
263
264      projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
265                                       0.0, 1.0, 0.0, 0.0,
266                            0.0, 0.0, ratio, 0.0,
267                       0.0, 0.0, center*ratio, 1.0));
268    }
269
270    return camera;
271}
272#undef CURRENT_CLASS
Note: See TracBrowser for help on using the browser.