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