zoukankan      html  css  js  c++  java
  • [osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)

    由于受够了OE的漫游器,想搞个可以在全球飞行的漫游器,所以就做了一个:

    请无视我的起名规则······

    类头文件:EarthWalkManipulator.h

    #pragma once
    //南水之源  20180101
    #include <osgGA/CameraManipulator>
    #include <osgEarth/MapNode>
    #include <osgEarth/Viewpoint>
    #include <osgEarth/GeoData>
    
    class EarthWalkManipulator :public osgGA::CameraManipulator
    {
    public:
        EarthWalkManipulator();
        ~EarthWalkManipulator();
    
        //所有漫游器都必须实现的4个纯虚函数  
        virtual void setByMatrix(const osg::Matrixd& matrix) {}  //设置相机的位置姿态矩阵  
        virtual void setByInverseMatrix(const osg::Matrixd& matrix) {}  //设置相机的视图矩阵  
        virtual osg::Matrixd getMatrix() const;  //获取相机的姿态矩阵 
        virtual osg::Matrixd getInverseMatrix() const;   //获取相机的视图矩阵 
    
        //所有操作在这里响应
        virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);
    
        // Attach a node to the manipulator.
        virtual void setNode(osg::Node*);
        virtual osg::Node* getNode();
        bool established();
    
        /**
        * Sets the camera position, optionally moving it there over time.
        */
        //virtual void setViewpoint(const osgEarth::Viewpoint& vp, double duration_s = 0.0);
        virtual void home(double /*unused*/);
        virtual void home(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);
    
    
        void addMouseEvent(const osgGA::GUIEventAdapter& ea);
        bool calcMovement(const osgGA::GUIEventAdapter& ea);
    protected:
        osg::Vec3   _eye;               //视点位置  
        osg::Quat    _rotate;            //旋转姿态 
        osg::ref_ptr<osg::Node>  _root;
    
        osg::observer_ptr<osg::Node> _node;
        osg::observer_ptr<osgEarth::MapNode>   _mapNode;
    
        osg::ref_ptr<const osgEarth::SpatialReference> _srs;
    
        float        _speed;                //速度
    
        // Internal event stack comprising last two mouse events.
        osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t1;
        osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t0;
    
    };

    类实现:EarthWalkManipulator.cpp

    //南水之源  20180101
    #include "EarthWalkManipulator.h"
    #include <osgViewerViewer>
    
    #include <osgDBReadFile>
    #include <osgMatrixTransform>
    
    
    using namespace osgEarth;
    
    EarthWalkManipulator::EarthWalkManipulator()
    {
        _eye = osg::Vec3d(0, 0, 0);
        //_rotate = osg::Quat(-osg::PI_2, osg::X_AXIS);
        _speed = 1.0;
    }
    
    EarthWalkManipulator::~EarthWalkManipulator()
    {
    }
    
    //获取相机的姿态矩阵 
    osg::Matrixd EarthWalkManipulator::getMatrix() const
    {
        osg::Matrix mat;
        mat.setRotate(_rotate);//先旋转
        mat.postMultTranslate(_eye);//再平移
        return mat;
    }
    
    osg::Matrixd EarthWalkManipulator::getInverseMatrix() const
    {
        osg::Matrix mat;
        mat.setRotate(-_rotate);
        mat.preMultTranslate(-_eye);
        return mat;
        //return osg::Matrixd::inverse(getMatrix());
    }
    
    void
    EarthWalkManipulator::home(double unused)
    {
        _eye = osg::Vec3d(0, 0, 0);
        _speed = 1.0;
    }
    
    void
    EarthWalkManipulator::home(const osgGA::GUIEventAdapter&, osgGA::GUIActionAdapter& us)
    {
        home(0.0);
        us.requestRedraw();
    }
    
    void
    EarthWalkManipulator::setNode(osg::Node* node)
    {
        // you can only set the node if it has not already been set, OR if you are setting
        // it to NULL. (So to change it, you must first set it to NULL.) This is to prevent
        // OSG from overwriting the node after you have already set on manually.
        if (node == 0L || !_node.valid())
        {
            _root = node;
            _node = node;
            _mapNode = 0L;
            _srs = 0L;
    
            established();
    
            osg::Matrix matrixGood1;
            GeoPoint point1(_srs, 0, 0, 10000.0);
            point1.createLocalToWorld(matrixGood1);
    
            _eye = matrixGood1.getTrans();
    
            osg::Vec3d worldup;
            point1.createWorldUpVector(worldup);
    
            osg::Matrix mat;
            matrixGood1.getRotate().get(mat);
            osg::Vec3d eye, center, up;
            mat.getLookAt(eye, center, up);
            mat.makeLookAt(eye, -worldup, up);
    
            _rotate = mat.getRotate();
    
        }
    }
    
    osg::Node*
    EarthWalkManipulator::getNode()
    {
        return _node.get();
    }
    
    bool EarthWalkManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
    {
        switch (ea.getEventType())
        {
        case(osgGA::GUIEventAdapter::FRAME):
        {
            if (calcMovement(ea))//根据鼠标在屏幕中的位置调整相机转向
                us.requestRedraw();
            return true;
        }break;
        case(osgGA::GUIEventAdapter::SCROLL):
        {
            osg::Quat qat;
            osg::Matrix mat;
            _rotate.get(mat);
            osg::Vec3d eye, center, up;
            mat.getLookAt(eye, center, up);
    
            osg::Vec3d dirction = center - eye;
            dirction.normalize();
            up.normalize();
            osg::Vec3d cross = dirction^up;
            cross.normalize();
    
            cross *= 0.01;
            switch (ea.getScrollingMotion())
            {
            case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_UP://逆时针旋转相机
            {
                mat = osg::Matrix::lookAt(eye, center, up + cross);
                _rotate = mat.getRotate();
            }break;
            case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_DOWN://顺时针旋转相机
            {
                mat = osg::Matrix::lookAt(eye, center, up - cross);
                _rotate = mat.getRotate();
            }break;
            }
            return true;
        }break;
        case (osgGA::GUIEventAdapter::KEYDOWN):
        {
            osg::Vec3   v3Direction;         //视点方向  
            osg::Matrix mCameraQuat;
            osg::Vec3d  v3Eye, v3Center, v3Up;
            _rotate.get(mCameraQuat);
            mCameraQuat.getLookAt(v3Eye, v3Center, v3Up);//这里的v3Eye不是实际相机的位置,而是0,0,0
            v3Direction = v3Center - v3Eye;
            v3Direction.normalize();
            osg::Vec3d v3CrossVector = v3Up^v3Direction;
            v3CrossVector.normalize();
            if (ea.getKey() == 'w' || ea.getKey() == 'W' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前进
            {
                _eye += v3Direction * _speed;
            }
            if (ea.getKey() == 's' || ea.getKey() == 'S' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//后退
            {
                _eye -= v3Direction * _speed;
            }
            if (ea.getKey() == 'a' || ea.getKey() == 'A' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移
            {
                _eye += v3CrossVector * _speed;
            }
            if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移
            {
                _eye -= v3CrossVector * _speed;
            }
            if (ea.getKey() == '-' || ea.getKey() == '_' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L)//减10倍移动速度
            {
                _speed /= 10.0;
                if (_speed < 1.0)
                {
                    _speed = 1.0;
                }
            }
            if (ea.getKey() == '=' || ea.getKey() == '+' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L)//加10倍移动速度
            {
                _speed *= 10.0;
                if (_speed > 100000.0)
                {
                    _speed = 100000.0;
                }
            }
    
            if (ea.getKey() == 'h' || ea.getKey() == 'H')//在当前经纬度,姿态回正:1.视点向地面 2.头部向正北
            {
                v3Eye = _eye;//使用相机实际位置
                osg::Vec3d v3EyeLonLat;
                _srs->transformFromWorld(v3Eye, v3EyeLonLat);
                //先获取当前位置的经纬度,再获取当前正上,正北
                osg::Matrix mRealAttitude;
    
                if (v3EyeLonLat.z() < 0)//v3EyeLonLat.z()是眼点实际海拔
                    v3EyeLonLat.z() = 100;//将海拔0以下的物体拉到海拔100米
    
                GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z());
                gEyeGeo.createLocalToWorld(mRealAttitude);
    
                osg::Vec3d v3HorizonUp;//指天向量
                gEyeGeo.createWorldUpVector(v3HorizonUp);
                
                _eye = mRealAttitude.getTrans();
    
                mRealAttitude.getLookAt(v3Eye, v3Center, v3Up);//获取新的位置和姿态
    
                osg::Matrix mDeviationAttitude;//向北位置偏移0.00001纬度,为了计算正北方向
                GeoPoint gDeviationEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y() + 0.00001, v3EyeLonLat.z());
                gDeviationEyeGeo.createLocalToWorld(mDeviationAttitude);
                osg::Vec3d v3DeviationNorthPoint = mDeviationAttitude.getTrans();
                osg::Vec3d v3NorthHeadUp = v3DeviationNorthPoint - v3Eye;
                v3NorthHeadUp.normalize();//指北向量
    
                //if (v3EyeLonLat.y() < 90.0 && v3EyeLonLat.y() > 0.0)//没研究出为什么北半球和南半球需要相反,但实际使用没问题
                //{
                //    mRealAttitude.makeLookAt(osg::Vec3d(0,0,0), -v3HorizonUp, -v3NorthHeadUp);
                //}
                if (v3EyeLonLat.y() < 89.99999  && v3EyeLonLat.y() > -90.0)
                {
                    mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), -v3HorizonUp, v3NorthHeadUp);
                }
                _rotate = mRealAttitude.getRotate();
            }
        }break;
        default:
            return false;
        }
    }
    
    bool
    EarthWalkManipulator::established()
    {
        if (_srs.valid() && _mapNode.valid() && _node.valid())
            return true;
    
        // lock down the observed node:
        osg::ref_ptr<osg::Node> safeNode;
        if (!_node.lock(safeNode))
            return false;
    
        // find a map node or fail:
        _mapNode = osgEarth::MapNode::findMapNode(safeNode.get());
        if (!_mapNode.valid())
            return false;
    
        // Cache the SRS.
        _srs = _mapNode->getMapSRS();
        return true;
    }
    
    void EarthWalkManipulator::addMouseEvent(const osgGA::GUIEventAdapter& ea)
    {
        _ga_t1 = _ga_t0;
        _ga_t0 = &ea;
    }
    
    bool EarthWalkManipulator::calcMovement(const osgGA::GUIEventAdapter& ea)
    {
        osg::Quat qat;
        osg::Matrix mat;
        _rotate.get(mat);
        osg::Vec3d eye, center, up;
        mat.getLookAt(eye, center, up);
    
        osg::Vec3d dirction = center - eye;
        dirction.normalize();
        up.normalize();
        osg::Vec3d cross = dirction^up;
        cross.normalize();
    
        double x1 = ea.getXnormalized();
        double y1 = ea.getYnormalized();
    
        osg::Vec3d deviation(0, 0, 0);
        if (x1 > 0.1)
        {
            deviation += cross * 0.001;
        }
        else if (x1 < -0.1)
        {
            deviation -= cross * 0.001;
        }
        if (y1 > 0.1)
        {
            deviation += up * 0.001;
        }
        else if (y1 < -0.1)
        {
            deviation -= up * 0.001;
        }
    
        mat = osg::Matrix::lookAt(eye, deviation + center, up);
        _rotate = mat.getRotate();
    
        return true;
    }

    使用:main.cpp

    #include <osg/Image>
    #include <osgGA/StateSetManipulator>
    #include <osgViewer/Viewer>
    #include <osgViewer/ViewerEventHandlers>
    #include <osgEarth/Map>
    #include <osgEarth/MapNode>
    #include <osgEarth/Registry>
    #include <osgEarthSymbology/Geometry>
    #include <osgEarthSymbology/GeometryRasterizer>
    #include <osgEarthUtil/EarthManipulator>
    #include <osgEarthUtil/AutoClipPlaneHandler>
    #include <osgEarth/ImageToHeightFieldConverter>
    #include <osgEarth/ImageUtils>
    #include <osgEarth/FileUtils>
    #include <osgEarth/Registry>
    #include <osgEarth/MapFrame>
    #include <osgDB/FileUtils>
    #include <osgDB/FileNameUtils>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    
    #include <osgEarthUtil/ExampleResources>
    #include <math.h>
    
    #include <osgGA/NodeTrackerManipulator>
    #include <osgGA/AnimationPathManipulator>
    #include <osgGA/KeySwitchMatrixManipulator>
    #include "EarthWalkManipulator.h"
    
    
    using namespace osgEarth;
    using namespace osgEarth::Util;
    using namespace osgEarth::Symbology;
    
    
    int main(int argc, char** argv)
    {
        //正常的.earth文件加载
        osg::ArgumentParser arguments(&argc, argv);
        osgViewer::Viewer viewer;
        MapNode* s_mapNode = 0L;
        osg::Node* earthFile = MapNodeHelper().load(arguments, &viewer);
        if (earthFile)
            s_mapNode = MapNode::get(earthFile);
        if (!s_mapNode)
        {
            OE_WARN << "Unable to load earth file." << std::endl;
            return -1;
        }
        osg::Group* root = new osg::Group();
        root->addChild(earthFile);
    
        osg::Matrix matrixGood1;
        osg::Vec3d geopoint1, geopoint2, geopoint3;
        GeoPoint point1(s_mapNode->getMapSRS(), 0, 0, 1000);
        point1.createLocalToWorld(matrixGood1);
        //matrixGood1.getLookAt(geopoint1, geopoint2, geopoint3);
        //osg::Vec3 _vector = geopoint1 - geopoint2;
    
        //添加一头牛,查看位置是否正确
        //osg::Node* cow = osgDB::readNodeFile("D:\temp\node\cow.osg");
        //
        //osg::ref_ptr<osg::MatrixTransform> pat = new osg::MatrixTransform;
        //pat->addChild(cow);
        //pat->setMatrix(osg::Matrix::scale(200000, 200000, 200000));
    
        //osg::Matrix maaat2;
        //osg::ref_ptr<osg::MatrixTransform> pat2 = new osg::MatrixTransform;
        //pat2->setMatrix(osg::Matrix::rotate(matrixGood1.getRotate())*
        //    osg::Matrix::translate(matrixGood1.getTrans()));
        //pat2->addChild(pat);
        //root->addChild(pat2);
    
        viewer.setSceneData(root);
    
        //模型漫游器
        osgGA::NodeTrackerManipulator* nodeTrack = new osgGA::NodeTrackerManipulator();
        nodeTrack->setTrackNode(root);
    
        /*************************************动画漫游器**下*********************************/
        GeoPoint gPoint1(s_mapNode->getMap()->getSRS(), 32, 118, 400);
        osg::Matrix gMatrix1;
        gPoint1.createLocalToWorld(gMatrix1);//获取当前地球上的正确姿态
        //由于相机,自身向下看,所以在当前姿态基础上抬起60度,注意是前乘!
        gMatrix1.preMultRotate(osg::Quat(osg::DegreesToRadians(60.0), osg::X_AXIS));
        osg::Quat q1;    gMatrix1.get(q1);//获取当前矩阵姿态
        osg::Vec3d vPos1 = gMatrix1.getTrans();//获取当前矩阵位置
    
        GeoPoint gPoint2(s_mapNode->getMap()->getSRS(), 32.01, 118.01, 400);
        osg::Matrix gMatrix2;
        gPoint2.createLocalToWorld(gMatrix2);
        gMatrix2.preMultRotate(osg::Quat(osg::DegreesToRadians(60.0), osg::X_AXIS));
        osg::Quat q2;    
        gMatrix2.get(q2);
        osg::Vec3d vPos2 = gMatrix2.getTrans();
    
        GeoPoint gPoint3(s_mapNode->getMap()->getSRS(), 32.02, 118.02, 400);
        osg::Matrix gMatrix3;
        gPoint3.createLocalToWorld(gMatrix3);
        osg::Quat q3;
        gMatrix3.get(q3);
        osg::Vec3d vPos3 = gMatrix3.getTrans();
        //获取相机之后再顺旋转,其实是错误的姿态
        osg::Quat qbuf(osg::DegreesToRadians(60.0), osg::X_AXIS);
        q3    *= qbuf;
    
        //使用动画漫游器
        osgGA::AnimationPathManipulator *animationPathMp = new osgGA::AnimationPathManipulator();
        //给动画漫游器添加关键帧
        osg::AnimationPath* _animationPath = new osg::AnimationPath;
        _animationPath->insert(0.0, osg::AnimationPath::ControlPoint(vPos1, q1));//姿态正确
        _animationPath->insert(3.0, osg::AnimationPath::ControlPoint(vPos2, q2));//姿态正确
        _animationPath->insert(6.0, osg::AnimationPath::ControlPoint(vPos3, q3));//姿态错误!
        _animationPath->setLoopMode(osg::AnimationPath::SWING);//设置路径是回摆的
        animationPathMp->setAnimationPath(_animationPath);
        /*************************************动画漫游器**上*********************************/
    
        //这里添加三个漫游器,使用一个控制漫游器选择,按键盘‘3’就切换到路径动画漫游器了
        osgGA::KeySwitchMatrixManipulator* keyPtr = new osgGA::KeySwitchMatrixManipulator();
        keyPtr->addMatrixManipulator('1', "earthMan", new EarthManipulator());
        keyPtr->addMatrixManipulator('2', "trakerMan", nodeTrack);
        keyPtr->addMatrixManipulator('3', "animationPathMan", animationPathMp);
        keyPtr->addMatrixManipulator('4', "earthWalkMan", new EarthWalkManipulator());
        viewer.setCameraManipulator(keyPtr);
        //viewer.setUpViewOnSingleScreen(0);
    
    
        {
            osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
            traits->x = 40;
            traits->y = 40;
            traits->width = 600;
            traits->height = 480;
            traits->windowDecoration = true;
            traits->doubleBuffer = true;
            traits->sharedContext = 0;
    
            osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
    
            osg::ref_ptr<osg::Camera> camera = new osg::Camera;
            camera->setGraphicsContext(gc.get());
            camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
            GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
            camera->setDrawBuffer(buffer);
            camera->setReadBuffer(buffer);
    
            // add this slave camera to the viewer, with a shift left of the projection matrix
            viewer.addSlave(camera.get());
        }
    
        while(!viewer.done())
            viewer.frame();
    
    
        return 1;
    }

    由于是初级版,所以有些操作还是比较反人类···

    运行起来是用其他漫游器告诉你:能看到个地球

    开始操作:

    1.按‘4’切换到自定义的漫游器,现在你的视点在球心,啥也看不到

    2.按‘s’或者‘下’,再按‘h’现在应该是在地球表面了(别问为什么会需要这么SB的操作···)

    3.然后自己体验吧(不要晕了···)

    后期会更新一个有良好操作的版本

  • 相关阅读:
    php.ini中Magic_Quotes_Gpc开关设置
    This is the Manual for Quagga 1.2.0. Quagga is a fork of GNU Zebra
    Are virtual interfaces supported on Quagga v0.98.3 (on Debian GNU/Linux 2.6.16)?
    [quagga-users 8071] Re: Virtual interfaces / aliases supported?
    quagga-0.99.20mr2.1
    Equal Cost Multipath Load Sharing
    (ECMP) Equal-cost multi-path routing
    Multipath suport not working in quagga 0.98.6
    Android-x86-7.1.1
    Android
  • 原文地址:https://www.cnblogs.com/lyggqm/p/8336810.html
Copyright © 2011-2022 走看看