osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 00020 #include <osgEarth/NodeUtils> 00021 #include <osg/TemplatePrimitiveFunctor> 00022 #include <osg/Geode> 00023 #include <osg/CullSettings> 00024 #include <vector> 00025 00026 using namespace osgEarth; 00027 00028 //------------------------------------------------------------------------ 00029 00030 namespace 00031 { 00032 struct ComputeMaxNormalLength 00033 { 00034 void set( const osg::Vec3& normalECEF, const osg::Matrixd& local2world, float* maxNormalLen ) 00035 { 00036 _normal = normalECEF; 00037 _local2world = local2world; 00038 _maxNormalLen = maxNormalLen; 00039 } 00040 00041 void operator()( const osg::Vec3 &v1, bool) 00042 { 00043 compute( v1 ); 00044 } 00045 00046 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, bool) 00047 { 00048 compute( v1 ); 00049 compute( v2 ); 00050 } 00051 00052 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3& v3, bool) 00053 { 00054 compute( v1 ); 00055 compute( v2 ); 00056 compute( v3 ); 00057 } 00058 00059 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3& v3, const osg::Vec3& v4, bool) 00060 { 00061 compute( v1 ); 00062 compute( v2 ); 00063 compute( v3 ); 00064 compute( v4 ); 00065 } 00066 00067 void compute( const osg::Vec3& v ) 00068 { 00069 osg::Vec3d vworld = v * _local2world; 00070 double vlen = vworld.length(); 00071 vworld.normalize(); 00072 00073 // the dot product of the 2 vecs is the cos of the angle between them; 00074 // mult that be the vector length to get the new normal length. 00075 float normalLen = fabs(_normal * vworld) * vlen; 00076 00077 if ( normalLen < *_maxNormalLen ) 00078 *_maxNormalLen = normalLen; 00079 } 00080 00081 osg::Vec3 _normal; 00082 osg::Matrixd _local2world; 00083 float* _maxNormalLen; 00084 }; 00085 00086 struct ComputeMaxRadius2 00087 { 00088 void set( const osg::Vec3& center, float* maxRadius2 ) 00089 { 00090 _center = center; 00091 _maxRadius2 = maxRadius2; 00092 } 00093 00094 void operator()( const osg::Vec3 &v1, bool ) 00095 { 00096 compute( v1 ); 00097 } 00098 00099 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, bool ) 00100 { 00101 compute( v1 ); 00102 compute( v2 ); 00103 } 00104 00105 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, bool ) 00106 { 00107 compute( v1 ); 00108 compute( v2 ); 00109 compute( v3 ); 00110 } 00111 00112 void operator()( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, const osg::Vec3& v4, bool ) 00113 { 00114 compute( v1 ); 00115 compute( v2 ); 00116 compute( v3 ); 00117 compute( v4 ); 00118 } 00119 00120 void compute( const osg::Vec3& v ) 00121 { 00122 float dist = (v - _center).length2(); 00123 if ( dist > *_maxRadius2 ) 00124 *_maxRadius2 = dist; 00125 } 00126 00127 00128 00129 osg::Vec3 _center; 00130 float* _maxRadius2; 00131 }; 00132 00133 struct ComputeVisitor : public osg::NodeVisitor 00134 { 00135 ComputeVisitor() 00136 : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), 00137 _maxRadius2(0.0f) { } 00138 00139 void run( osg::Node* node, const osg::Vec3d& centerECEF ) 00140 { 00141 _centerECEF = centerECEF; 00142 _normalECEF = _centerECEF; 00143 _normalECEF.normalize(); 00144 _maxNormalLen = _centerECEF.length(); 00145 00146 _pass = 1; 00147 node->accept( *this ); 00148 00149 _centerECEF = _normalECEF * _maxNormalLen; 00150 00151 _pass = 2; 00152 node->accept( *this ); 00153 } 00154 00155 void apply( osg::Geode& geode ) 00156 { 00157 if ( _pass == 1 ) 00158 { 00159 osg::Matrixd local2world; 00160 if ( !_matrixStack.empty() ) 00161 local2world = _matrixStack.back(); 00162 00163 osg::TemplatePrimitiveFunctor<ComputeMaxNormalLength> pass1; 00164 pass1.set( _normalECEF, local2world, &_maxNormalLen ); 00165 00166 for( unsigned i=0; i<geode.getNumDrawables(); ++i ) 00167 geode.getDrawable(i)->accept( pass1 ); 00168 } 00169 00170 else // if ( _pass == 2 ) 00171 { 00172 osg::Vec3d center = _matrixStack.empty() ? _centerECEF : _centerECEF * osg::Matrixd::inverse(_matrixStack.back()); 00173 00174 osg::TemplatePrimitiveFunctor<ComputeMaxRadius2> pass2; 00175 pass2.set( center, &_maxRadius2 ); 00176 for( unsigned i=0; i<geode.getNumDrawables(); ++i ) 00177 geode.getDrawable(i)->accept( pass2 ); 00178 } 00179 } 00180 00181 void apply( osg::Transform& xform ) 00182 { 00183 osg::Matrixd matrix; 00184 if (!_matrixStack.empty()) matrix = _matrixStack.back(); 00185 xform.computeLocalToWorldMatrix( matrix, this ); 00186 _matrixStack.push_back( matrix ); 00187 traverse(xform); 00188 _matrixStack.pop_back(); 00189 } 00190 00191 unsigned _pass; 00192 osg::Vec3d _centerECEF; 00193 osg::Vec3f _normalECEF; 00194 float _maxNormalLen; 00195 float _maxRadius2; 00196 std::vector<osg::Matrixd> _matrixStack; 00197 }; 00198 00204 struct MyClusterCullingCallback : public osg::ClusterCullingCallback 00205 { 00206 bool cull(osg::NodeVisitor* nv, osg::Drawable* , osg::State*) const 00207 { 00208 osg::CullSettings* cs = dynamic_cast<osg::CullSettings*>(nv); 00209 if (cs && !(cs->getCullingMode() & osg::CullSettings::CLUSTER_CULLING)) 00210 { 00211 return false; 00212 } 00213 00214 if (_deviation<=-1.0f) 00215 { 00216 return false; 00217 } 00218 00219 osg::Vec3 eye_cp = nv->getViewPoint() - _controlPoint; 00220 float radius = eye_cp.length(); 00221 00222 if (radius<_radius) 00223 { 00224 return false; 00225 } 00226 00227 float deviation = (eye_cp * _normal)/radius; 00228 00229 return deviation < _deviation; 00230 } 00231 }; 00232 } 00233 00234 //------------------------------------------------------------------------ 00235 00236 osg::ClusterCullingCallback* 00237 ClusterCullerFactory::create( osg::Node* node, const osg::Vec3d& centerECEF ) 00238 { 00239 // Cluster culling computer. This works in two passes. 00240 // 00241 // It starts with a control point provided by the caller. I the first pass it computes 00242 // a new control point that is along the same geocentric normal but at a lower Z. This 00243 // corresponds to the lowest Z of a vertex with respect to that normal. This means we 00244 // can always use a "deviation" of 0 -- and it gets around the problem of the control 00245 // point being higher than a vertex and corrupting the deviation. 00246 // 00247 // In the second pass, we compute the radius based on the new control point. 00248 00249 osg::ClusterCullingCallback* ccc = 0L; 00250 if ( node ) 00251 { 00252 ComputeVisitor cv; 00253 cv.run( node, centerECEF ); 00254 00255 ccc = new MyClusterCullingCallback(); //osg::ClusterCullingCallback(); 00256 ccc->set( cv._centerECEF, cv._normalECEF, 0.0f, sqrt(cv._maxRadius2) ); 00257 } 00258 return ccc; 00259 } 00260 00261 //------------------------------------------------------------------------ 00262 00263 RemoveEmptyGroupsVisitor::RemoveEmptyGroupsVisitor() : 00264 osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ) 00265 { 00266 //nop 00267 } 00268 00269 void 00270 RemoveEmptyGroupsVisitor::apply( osg::Group& group ) 00271 { 00272 bool removed = true; 00273 while( removed ) 00274 { 00275 removed = false; 00276 for( unsigned i = 0; i < group.getNumChildren(); ++i ) 00277 { 00278 osg::Group* child = group.getChild(i)->asGroup(); 00279 if ( child ) 00280 { 00281 if (child->className() == "Group" && 00282 child->getStateSet() == 0L && 00283 child->getCullCallback() == 0L && 00284 child->getUpdateCallback() == 0L && 00285 child->getUserData() == 0L && 00286 child->getName().empty() && 00287 child->getDescriptions().size() == 0 ) 00288 { 00289 for( unsigned j = 0; j < child->getNumChildren(); ++j ) 00290 { 00291 group.addChild( child->getChild( j ) ); 00292 } 00293 00294 group.removeChild( i-- ); 00295 removed = true; 00296 } 00297 } 00298 } 00299 } 00300 00301 traverse(group); 00302 }