[32] | 1 | #pragma once |
---|
[221] | 2 | /* -*-c++-*- osgVisual - Copyright (C) 2009-2011 Torben Dannhauer |
---|
[32] | 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 | { |
---|
[88] | 44 | #include <leakDetection.h> |
---|
[32] | 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 | { |
---|
[87] | 58 | #include <leakDetection.h> |
---|
| 59 | |
---|
[32] | 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 | |
---|
[112] | 101 | if (skyDrawable) |
---|
[32] | 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 | |
---|
[112] | 126 | if (skyDrawable) |
---|
[32] | 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. |
---|
[133] | 151 | SL_VECTOR(SilverLining::ObjectHandle) &objects = atmosphere->GetObjects(); |
---|
[32] | 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"); |
---|
[133] | 166 | OSG_ALWAYS << "has limb " << hasLimb << std::endl; |
---|
[32] | 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 |
---|
[130] | 183 | SL_VECTOR(SilverLining::ObjectHandle)::iterator it; |
---|
[32] | 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; |
---|
[112] | 225 | util::getXYZofCamera( camera, x, y, z ); |
---|
| 226 | if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) ) |
---|
[32] | 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; |
---|
[112] | 241 | util::getXYZofCamera( camera, x, y, z ); |
---|
| 242 | if( util::queryHeightAboveTerrainInWorld( hat, csn, x, y, z ) ) |
---|
[32] | 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 | */ |
---|
[107] | 262 | osg::ref_ptr<osgUtil::CullVisitor> stockCullVisitor; |
---|
[32] | 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 | */ |
---|
[112] | 272 | osg::Camera *camera; |
---|
[32] | 273 | |
---|
| 274 | /** |
---|
| 275 | * Pointer to the skyDrawable |
---|
| 276 | */ |
---|
[112] | 277 | skySilverLining_skyDrawable *skyDrawable; |
---|
[32] | 278 | |
---|
| 279 | /** |
---|
| 280 | * ? |
---|
| 281 | * @todo: wofür ist diese variable nötig? |
---|
| 282 | */ |
---|
[112] | 283 | osg::CoordinateSystemNode *csn; |
---|
[32] | 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 |
---|