1 | #pragma once |
---|
2 | /* -*-c++-*- osgVisual - Copyright (C) 2009-2010 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 | |
---|
30 | namespace 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 | */ |
---|
42 | class skySilverLining_projectionMatrixCallback : public osg::CullSettings::ClampProjectionMatrixCallback |
---|
43 | { |
---|
44 | #include <leakDetection.h> |
---|
45 | public: |
---|
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( 500.0, osg::Vec2( 5.0, 100000.0))); |
---|
74 | keys->push_back(osgAnimation::Vec2Keyframe( 1000.0, osg::Vec2( 10.0, 100000.0))); |
---|
75 | keys->push_back(osgAnimation::Vec2Keyframe( 10000.0, osg::Vec2( 50.0, 1000000.0))); |
---|
76 | keys->push_back(osgAnimation::Vec2Keyframe(1000000.0, osg::Vec2(100.0, 200000000.0))); |
---|
77 | |
---|
78 | } |
---|
79 | |
---|
80 | /** |
---|
81 | * \brief This functions sets the pointer to the skyDrawable. This pointer is requiered to adjust the skybox size. |
---|
82 | * |
---|
83 | * @param sd : Pointer to the skyDrawable to store. |
---|
84 | */ |
---|
85 | void setSkyDrawable(skySilverLining_skyDrawable *sd) {skyDrawable = sd;} |
---|
86 | |
---|
87 | protected: |
---|
88 | /** |
---|
89 | * \brief Implementation for float values to clamp the projection matrix. |
---|
90 | * |
---|
91 | * @param projection : Projection Matrix. |
---|
92 | * @param znear : Near value of the projection matrix. |
---|
93 | * @param zfar : Far value of the projection matrix. |
---|
94 | * @return : True if successful |
---|
95 | */ |
---|
96 | bool clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const |
---|
97 | { |
---|
98 | computeNearFar( znear, zfar ); |
---|
99 | //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << std::endl; |
---|
100 | |
---|
101 | if (skyDrawable) |
---|
102 | { |
---|
103 | skyDrawable->setSkyboxSize(((zfar - znear) * 0.5 + znear) * 2.0); |
---|
104 | } |
---|
105 | |
---|
106 | double fovy, ar, zn, zf; |
---|
107 | camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); |
---|
108 | camera->setProjectionMatrixAsPerspective(fovy, ar, znear, zfar); |
---|
109 | |
---|
110 | return true; |
---|
111 | } |
---|
112 | |
---|
113 | /** |
---|
114 | * \brief Implementation for double values to clamp the projection matrix. |
---|
115 | * |
---|
116 | * @param projection : Projection Matrix. |
---|
117 | * @param znear : Near value of the projection matrix. |
---|
118 | * @param zfar : Far value of the projection matrix. |
---|
119 | * @return : True if successful |
---|
120 | */ |
---|
121 | bool clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const |
---|
122 | { |
---|
123 | computeNearFar( znear, zfar ); |
---|
124 | //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << std::endl; |
---|
125 | |
---|
126 | if (skyDrawable) |
---|
127 | { |
---|
128 | skyDrawable->setSkyboxSize(((zfar - znear) * 0.5 + znear) * 2.0); |
---|
129 | } |
---|
130 | |
---|
131 | double fovy, ar, zn, zf; |
---|
132 | camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); |
---|
133 | //OSG_NOTIFY( osg::ALWAYS ) << "znear: " << znear << ", zfar: " << zfar << ", zn: " << zn << std::endl; |
---|
134 | camera->setProjectionMatrixAsPerspective(fovy, ar, znear, zfar); |
---|
135 | |
---|
136 | return true; |
---|
137 | } |
---|
138 | |
---|
139 | /** |
---|
140 | * \brief This function computes the near and far value against the cloud objects of silverlining. |
---|
141 | * |
---|
142 | * @param znear : Referenced to store the calculated near value into. |
---|
143 | * @param zfar : Referenced to store the calculated far value into. |
---|
144 | */ |
---|
145 | void computeNearFarClouds(double &znear, double &zfar) const |
---|
146 | { |
---|
147 | const double fudge = 5000.0; |
---|
148 | double minDist = 1E10; double maxDist = -1E10; |
---|
149 | |
---|
150 | // Retrieve all atmosphere objects. |
---|
151 | SL_VECTOR(SilverLining::ObjectHandle) &objects = atmosphere->GetObjects(); |
---|
152 | int size = objects.size(); |
---|
153 | |
---|
154 | osg::Vec3d eye, dirVector, upVector; |
---|
155 | camera->getViewMatrixAsLookAt(eye,dirVector,upVector); // Get XYZ from camera |
---|
156 | //osg::Vec3d camPos = camera->getViewMatrix().getTrans(); |
---|
157 | osg::Vec3d camPos = eye; |
---|
158 | osg::Vec3d up = camPos; |
---|
159 | up.normalize(); |
---|
160 | osg::Vec3d down = up * -1.0; |
---|
161 | |
---|
162 | double dToOrigin = camPos.length(); |
---|
163 | |
---|
164 | // Calculations if atmopshere is rendered from space |
---|
165 | bool hasLimb = atmosphere->GetConfigOptionBoolean("enable-atmosphere-from-space"); |
---|
166 | OSG_ALWAYS << "has limb " << hasLimb << std::endl; |
---|
167 | if (hasLimb) |
---|
168 | { |
---|
169 | // Compute distance to edge of atmospheric limb |
---|
170 | double earthRadius = atmosphere->GetConfigOptionDouble("earth-radius-meters"); |
---|
171 | double atmosphereHeight = earthRadius + atmosphere->GetConfigOptionDouble("atmosphere-height"); |
---|
172 | double atmosphereThickness = atmosphere->GetConfigOptionDouble("atmosphere-scale-height-meters") + earthRadius; |
---|
173 | if (dToOrigin > atmosphereThickness) // Bail if limb not rendered |
---|
174 | { |
---|
175 | double dToLimbEdge = sqrt(dToOrigin * dToOrigin + atmosphereHeight * atmosphereHeight); |
---|
176 | maxDist = dToLimbEdge; |
---|
177 | double dToLimbBase = sqrt(dToOrigin * dToOrigin + earthRadius * earthRadius); |
---|
178 | minDist = dToLimbBase; |
---|
179 | } |
---|
180 | } |
---|
181 | |
---|
182 | // Walk through all objects and check if they influence the near plane or far plane |
---|
183 | SL_VECTOR(SilverLining::ObjectHandle)::iterator it; |
---|
184 | for (it = objects.begin(); it != objects.end(); it++) |
---|
185 | { |
---|
186 | float ox, oy, oz; |
---|
187 | atmosphere->GetObjectPosition(*it, ox, oy, oz); |
---|
188 | osg::Vec3d oPos(ox, oy, oz); |
---|
189 | double oHeight = oPos.length(); |
---|
190 | osg::Vec3d testVec = camPos; |
---|
191 | // Compare distance to origin of the camera and the object. wenn objecte nah aneinander: |
---|
192 | //vertikal shiften, um eine erkennbare Distanz errechnen zu können. |
---|
193 | if (dToOrigin > oHeight) |
---|
194 | { |
---|
195 | testVec = camPos + down * 100.0; // 100 for floating point precision problems |
---|
196 | } |
---|
197 | else |
---|
198 | { |
---|
199 | testVec = camPos + up * 100.0; |
---|
200 | } |
---|
201 | |
---|
202 | const double farFarAway = 500000; |
---|
203 | |
---|
204 | double dist = atmosphere->GetObjectDistance(*it, testVec.x(), testVec.y(), testVec.z(), |
---|
205 | (float)camPos.x(), (float)camPos.y(), (float)camPos.z()); |
---|
206 | |
---|
207 | |
---|
208 | if (dist < farFarAway) // an intersection was found |
---|
209 | { |
---|
210 | if (dist < minDist) minDist = dist; |
---|
211 | if (dist > maxDist) maxDist = dist; |
---|
212 | } |
---|
213 | } // For (all objects) END |
---|
214 | |
---|
215 | double fovy, ar, zn, zf; |
---|
216 | camera->getProjectionMatrixAsPerspective(fovy, ar, zn, zf); |
---|
217 | double halfFovx = (fovy * ar) * 0.5; |
---|
218 | minDist *= cos(halfFovx * (3.14159265 / 180.0)); |
---|
219 | |
---|
220 | znear = minDist - fudge; |
---|
221 | zfar = maxDist + fudge; |
---|
222 | |
---|
223 | //clamp the near plane if low above ground. |
---|
224 | double x,y,z,hat; |
---|
225 | util::getXYZofCamera( camera, x, y, z ); |
---|
226 | if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) ) |
---|
227 | { |
---|
228 | if (hat < 80 ) |
---|
229 | { |
---|
230 | znear = maxNear; |
---|
231 | } |
---|
232 | } |
---|
233 | //OSG_NOTIFY( osg::ALWAYS ) << "Near: " << znear << ", Far: " << zfar << std::endl; |
---|
234 | } |
---|
235 | |
---|
236 | void computeNearFar( double& near_, double& far_ ) const |
---|
237 | { |
---|
238 | double x,y,z,hat; |
---|
239 | near_ = 2; |
---|
240 | far_ = 125000; |
---|
241 | util::getXYZofCamera( camera, x, y, z ); |
---|
242 | if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) ) |
---|
243 | { |
---|
244 | osg::Vec2 planesNearFar; |
---|
245 | samplerClipPlanes->getValueAt(hat, planesNearFar); |
---|
246 | |
---|
247 | near_ = planesNearFar.x(); |
---|
248 | far_ = planesNearFar.y(); |
---|
249 | |
---|
250 | //OSG_NOTIFY( osg::ALWAYS ) << "hat: " << hat << ", near: " << near_ << ", far: " << far_ << std::endl; |
---|
251 | } // IF HAT END |
---|
252 | else |
---|
253 | OSG_NOTIFY( osg::FATAL ) << "ERROR: Unable to Compute NearFar!" << std::endl; |
---|
254 | |
---|
255 | if (near_ < 0.5 ) near_ = 0.5; |
---|
256 | } |
---|
257 | |
---|
258 | |
---|
259 | /** |
---|
260 | * Pointer to the Cullvisitor which applies the projection matrix. |
---|
261 | */ |
---|
262 | osg::ref_ptr<osgUtil::CullVisitor> stockCullVisitor; |
---|
263 | |
---|
264 | /** |
---|
265 | * Pointer to silverlinings atmosphere instance. |
---|
266 | */ |
---|
267 | SilverLining::Atmosphere *atmosphere; |
---|
268 | |
---|
269 | /** |
---|
270 | * Pointer to the camera on which the callback is installed |
---|
271 | */ |
---|
272 | osg::Camera *camera; |
---|
273 | |
---|
274 | /** |
---|
275 | * Pointer to the skyDrawable |
---|
276 | */ |
---|
277 | skySilverLining_skyDrawable *skyDrawable; |
---|
278 | |
---|
279 | /** |
---|
280 | * ? |
---|
281 | * @todo: wofür ist diese variable nötig? |
---|
282 | */ |
---|
283 | osg::CoordinateSystemNode *csn; |
---|
284 | |
---|
285 | |
---|
286 | osg::ref_ptr<osgAnimation::Vec2LinearSampler> samplerClipPlanes; |
---|
287 | osg::ref_ptr<osgAnimation::Vec2KeyframeContainer> keys; |
---|
288 | |
---|
289 | /** |
---|
290 | * Minimal far distance. The far plane is never nearer than this value. |
---|
291 | */ |
---|
292 | double minFar; |
---|
293 | |
---|
294 | /** |
---|
295 | * Maximal near distance. The near plane is never farther than this value. |
---|
296 | * It is used to clamp the near plane on a fix near value if the camera is low above ground |
---|
297 | */ |
---|
298 | double maxNear; |
---|
299 | }; |
---|
300 | |
---|
301 | } // END NAMESPACE |
---|