source: osgVisual/trunk/include/sky_Silverlining/skySilverLining_ProjectionMatrixCallback.h @ 393

Last change on this file since 393 was 292, checked in by Torben Dannhauer, 13 years ago

Better Near&Far plane calculation to allow views from deeper space.

File size: 11.7 KB
Line 
1#pragma once
2/* -*-c++-*- osgVisual - Copyright (C) 2009-2011 Torben Dannhauer
3 *
4 * This library is based on OpenSceneGraph, open source and may be redistributed and/or modified under
5 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
6 * (at your option) any later version.  The full license is in LICENSE file
7 * included with this distribution, and on the openscenegraph.org website.
8 *
9 * osgVisual requires for some proprietary modules a license from the correspondig manufacturer.
10 * You have to aquire licenses for all used proprietary modules.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * OpenSceneGraph Public License for more details.
16 *
17 * This file is based on the OSG example of the Silverlining SDK:
18 * Copyright (c) 2008 Sundog Software, LLC. All rights reserved worldwide.
19*/
20
21#include <SilverLining.h>
22#include <osg/Camera>
23#include <osg/CullSettings>
24#include <osgAnimation/Animation>
25#include <skySilverLining_skyDrawable.h>
26#include <visual_util.h>
27
28
29
30namespace osgVisual
31{
32
33/**
34 * \brief This class intercepts OSG's method for automatically computing the near and far clip planes, taking into
35    account SilverLining's objects in the scene (sky box, clouds, and possibly an atmospheric limb.)
36 *
37 * @todo : Create interface to control nearplane while tracking near plane.
38 *
39 * @author Torben Dannhauer
40 * @date  Sep 2009
41 */ 
42class skySilverLining_projectionMatrixCallback : public osg::CullSettings::ClampProjectionMatrixCallback
43{
44        #include <leakDetection.h>
45public:
46        /**
47         * \brief Constructor : Initializes the attributes with valid values.
48         *
49         * @todo : why is CSN required.
50         *
51         * @param atm : Pointer to the atmosphere object.
52         * @param cam : Pointer to the rendering camera.
53         * @param csn_ : Pointer to the coordinatesystemode.
54         */ 
55        skySilverLining_projectionMatrixCallback(SilverLining::Atmosphere *atm, osg::Camera *cam, osg::CoordinateSystemNode *csn_) : osg::CullSettings::ClampProjectionMatrixCallback(),
56        atmosphere(atm), camera(cam), csn(csn_), skyDrawable(0), minFar(90000), maxNear(2)
57    {
58                #include <leakDetection.h>
59
60        stockCullVisitor = osgUtil::CullVisitor::create();
61                //stockCullVisitor->setNearFarRatio( 0.00005 );
62
63                samplerClipPlanes = new osgAnimation::Vec2LinearSampler;
64                keys = samplerClipPlanes->getOrCreateKeyframeContainer();
65
66                //                                                                                      Flughöhe                                near            far
67                keys->push_back(osgAnimation::Vec2Keyframe(      0.0, osg::Vec2(     1.0,     80000.0)));
68                keys->push_back(osgAnimation::Vec2Keyframe(     50.0, osg::Vec2(     5.0,     90000.0)));
69                keys->push_back(osgAnimation::Vec2Keyframe(    500.0, osg::Vec2(     5.0,    100000.0)));
70                keys->push_back(osgAnimation::Vec2Keyframe(   1000.0, osg::Vec2(    10.0,    100000.0)));
71        //keys->push_back(osgAnimation::Vec2Keyframe(  10000.0, osg::Vec2(   100.0,   1000000.0)));
72        //keys->push_back(osgAnimation::Vec2Keyframe(1000000.0, osg::Vec2(100000.0, 200000000.0)));
73                keys->push_back(osgAnimation::Vec2Keyframe(   10000.0, osg::Vec2(   50.0,   1000000.0)));
74                keys->push_back(osgAnimation::Vec2Keyframe( 1000000.0, osg::Vec2(  100.0, 200000000.0)));
75                keys->push_back(osgAnimation::Vec2Keyframe( 2000000.0, osg::Vec2(  250.0, 200000000.0)));
76                keys->push_back(osgAnimation::Vec2Keyframe( 3000000.0, osg::Vec2(  500.0, 200000000.0)));
77                keys->push_back(osgAnimation::Vec2Keyframe( 4000000.0, osg::Vec2( 1000.0, 200000000.0)));
78                keys->push_back(osgAnimation::Vec2Keyframe( 5000000.0, osg::Vec2(10000.0, 200000000.0)));
79                keys->push_back(osgAnimation::Vec2Keyframe( 6000000.0, osg::Vec2(  10000.0, 200000000.0)));
80                keys->push_back(osgAnimation::Vec2Keyframe( 7000000.0, osg::Vec2( 100000.0, 200000000.0)));
81                keys->push_back(osgAnimation::Vec2Keyframe( 8000000.0, osg::Vec2(1000000.0, 200000000.0)));
82                keys->push_back(osgAnimation::Vec2Keyframe( 9000000.0, osg::Vec2(1250000.0, 200000000.0)));
83                keys->push_back(osgAnimation::Vec2Keyframe(10000000.0, osg::Vec2(2500000.0, 200000000.0)));
84                keys->push_back(osgAnimation::Vec2Keyframe(11000000.0, osg::Vec2(5000000.0, 200000000.0)));
85                keys->push_back(osgAnimation::Vec2Keyframe(12000000.0, osg::Vec2(7500000.0, 200000000.0)));
86                keys->push_back(osgAnimation::Vec2Keyframe(50000000.0, osg::Vec2(15000000.0,2000000000.0)));
87
88    }
89
90        /**
91         * \brief This functions sets the pointer to the skyDrawable. This pointer is requiered to adjust the skybox size.
92         *
93         * @param sd : Pointer to the skyDrawable to store.
94         */ 
95        void setSkyDrawable(skySilverLining_skyDrawable *sd) {skyDrawable = sd;}
96
97protected:
98        /**
99         * \brief Implementation for float values to clamp the projection matrix.
100         *
101         * @param projection : Projection Matrix.
102         * @param znear : Near value of the projection matrix.
103         * @param zfar : Far value of the projection matrix.
104         * @return : True if successful
105         */ 
106    bool clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const
107    {
108           computeNearFar( znear, zfar );
109           //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << std::endl;
110
111           if (skyDrawable)
112           {
113               skyDrawable->setSkyboxSize(((zfar - znear) * 0.5 + znear) * 2.0);
114           }
115               
116           double fovy, ar, zn, zf;
117       camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf);
118           camera->setProjectionMatrixAsPerspective(fovy, ar, znear, zfar);
119
120                return true;
121    }
122
123        /**
124         * \brief Implementation for double values to clamp the projection matrix.
125         *
126         * @param projection : Projection Matrix.
127         * @param znear : Near value of the projection matrix.
128         * @param zfar : Far value of the projection matrix.
129         * @return : True if successful
130         */ 
131    bool clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const
132    {
133           computeNearFar( znear, zfar );
134           //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << std::endl;
135
136           if (skyDrawable)
137           {
138               skyDrawable->setSkyboxSize(((zfar - znear) * 0.5 + znear) * 2.0);
139           }
140               
141           double fovy, ar, zn, zf;
142       camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf);
143           //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << ", zn: " << zn << std::endl;
144           camera->setProjectionMatrixAsPerspective(fovy, ar, znear, zfar);
145
146                return true;
147    }
148
149        /**
150         * \brief This function computes the near and far value against the cloud objects of silverlining.
151         *
152         * @param znear : Referenced to store the calculated near value into.
153         * @param zfar : Referenced to store the calculated far value into.
154         */ 
155    void computeNearFarClouds(double &znear, double &zfar) const
156    {
157                const double fudge = 5000.0;
158        double minDist = 1E10; double maxDist = -1E10;
159
160                // Retrieve all atmosphere objects.
161                SL_VECTOR(SilverLining::ObjectHandle) &objects = atmosphere->GetObjects();
162                int size = objects.size();
163               
164                osg::Vec3d eye, dirVector, upVector;
165                camera->getViewMatrixAsLookAt(eye,dirVector,upVector); // Get XYZ from camera
166                //osg::Vec3d camPos = camera->getViewMatrix().getTrans();
167                osg::Vec3d camPos = eye;
168        osg::Vec3d up = camPos;
169        up.normalize();
170        osg::Vec3d down = up * -1.0;
171
172                double dToOrigin = camPos.length();
173
174                // Calculations if atmopshere is rendered from space
175                bool hasLimb = atmosphere->GetConfigOptionBoolean("enable-atmosphere-from-space");
176                OSG_ALWAYS << "has limb " << hasLimb << std::endl;
177                if (hasLimb)
178                {
179                        // Compute distance to edge of atmospheric limb
180                        double earthRadius = atmosphere->GetConfigOptionDouble("earth-radius-meters");
181                        double atmosphereHeight = earthRadius + atmosphere->GetConfigOptionDouble("atmosphere-height");
182                        double atmosphereThickness = atmosphere->GetConfigOptionDouble("atmosphere-scale-height-meters") + earthRadius;
183                        if (dToOrigin > atmosphereThickness) // Bail if limb not rendered
184                        {
185                                double dToLimbEdge = sqrt(dToOrigin * dToOrigin + atmosphereHeight * atmosphereHeight);
186                                maxDist = dToLimbEdge;
187                                double dToLimbBase = sqrt(dToOrigin * dToOrigin + earthRadius * earthRadius);
188                                minDist = dToLimbBase;
189                        }
190                }
191
192                // Walk through all objects and check if they influence the near plane or far plane
193                SL_VECTOR(SilverLining::ObjectHandle)::iterator it;
194        for (it = objects.begin(); it != objects.end(); it++)
195        {
196            float ox, oy, oz;
197            atmosphere->GetObjectPosition(*it, ox, oy, oz);
198            osg::Vec3d oPos(ox, oy, oz);
199            double oHeight = oPos.length();
200            osg::Vec3d testVec = camPos;
201                        // Compare distance to origin of the camera and the object. wenn objecte nah aneinander:
202                        //vertikal shiften, um eine erkennbare Distanz errechnen zu können.
203            if (dToOrigin > oHeight)
204            {
205                testVec = camPos + down * 100.0; // 100 for floating point precision problems
206            }
207            else
208            {
209                testVec = camPos + up * 100.0;
210            }
211           
212            const double farFarAway = 500000;
213
214            double dist = atmosphere->GetObjectDistance(*it, testVec.x(), testVec.y(), testVec.z(),
215                                (float)camPos.x(), (float)camPos.y(), (float)camPos.z());
216
217
218            if (dist < farFarAway) // an intersection was found
219            {
220                if (dist < minDist) minDist = dist;
221                if (dist > maxDist) maxDist = dist;
222            }
223        }       // For (all objects) END
224
225        double fovy, ar, zn, zf;
226        camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf);
227        double halfFovx = (fovy * ar) * 0.5;
228        minDist *= cos(halfFovx * (3.14159265 / 180.0));
229
230        znear = minDist - fudge;
231        zfar = maxDist + fudge;
232
233                //clamp the near plane if low above ground.
234            double x,y,z,hat;
235            util::getXYZofCamera( camera, x, y, z );
236                if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) )
237                {
238                        if (hat < 80 ) 
239                        {
240                                znear = maxNear;
241                        }
242                }
243            //OSG_NOTIFY( osg::ALWAYS ) << "Near: " << znear << ", Far: " << zfar << std::endl;
244    }
245
246        void computeNearFar( double& near_, double& far_ ) const
247        {
248                double x,y,z,hat;
249                near_ = 2;
250                far_ = 125000;
251            util::getXYZofCamera( camera, x, y, z );
252                if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) )
253                {
254                        osg::Vec2 planesNearFar;
255                        samplerClipPlanes->getValueAt(hat, planesNearFar);
256
257                        near_ = planesNearFar.x();
258                        far_  = planesNearFar.y();
259
260                        //OSG_NOTIFY( osg::ALWAYS ) << "hat: " << hat << ", near: " << near_ << ", far: " << far_ << std::endl;
261                } // IF HAT END
262                else 
263                        OSG_NOTIFY( osg::FATAL ) << "ERROR: Unable to Compute NearFar!" << std::endl;
264
265                if (near_ < 0.5 ) near_ = 0.5;
266        }
267
268   
269        /**
270         * Pointer to the Cullvisitor which applies the projection matrix.
271         */ 
272        osg::ref_ptr<osgUtil::CullVisitor> stockCullVisitor;
273
274        /**
275         * Pointer to silverlinings atmosphere instance.
276         */ 
277    SilverLining::Atmosphere *atmosphere;
278
279        /**
280         * Pointer to the camera on which the callback is installed
281         */ 
282    osg::Camera *camera;
283
284        /**
285         * Pointer to the skyDrawable
286         */ 
287        skySilverLining_skyDrawable *skyDrawable;
288
289        /**
290         * ?
291         * @todo: wofür ist diese variable nötig?
292         */ 
293        osg::CoordinateSystemNode *csn;
294
295
296        osg::ref_ptr<osgAnimation::Vec2LinearSampler> samplerClipPlanes;
297        osg::ref_ptr<osgAnimation::Vec2KeyframeContainer> keys;
298
299        /**
300         * Minimal far distance. The far plane is never nearer than this value.
301         */ 
302        double minFar;
303
304        /**
305         * Maximal near distance. The near plane is never farther than this value.
306         * It is used to clamp the near plane on a fix near value if the camera is low above ground
307         */ 
308        double maxNear;
309};
310
311}       // END NAMESPACE
Note: See TracBrowser for help on using the repository browser.