osgEarth示例分析——osgearth_skyview

osgEarth示例分析——osgearth_skyview分析osgearth操作深空场景示例

前言

本示例分析osgearth操作深空场景,或者是银河系场景,可以想象人拿着相机站在地球表面上观看天空/银河系的场景。

重点是相机操作器的使用。

在命令框输入执行程序,在data路径下有加载的图,且被写入了earth文件。

// 两个文件仅加载图片不同
osgearth_skyviewd.exe ..\..\..\tests\skyview1.earth

osgearth_skyviewd.exe ..\..\..\tests\skyview2.earth

运行结果

天球场景。

osgEarth示例分析——osgearth_skyview

osgEarth示例分析——osgearth_skyview

第三幅图,特别像带VR眼镜,周围可以看到不同的场景,相机此时像站在十字路口,看周围的场景。

 osgEarth示例分析——osgearth_skyview

类分析

osgEarth示例分析——osgearth_skyview

 重点就是处理handle的操作器。下面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;

代码分析

仅将操作器的实现文件和主程序文件拷贝到此处。

osgearth_skyview.cpp文件

#include <osgViewer/Viewer>
#include <osg/CullFace>
#include <osgEarth/Notify>
#include <osgEarthUtil/ExampleResources>
#include "SkyManipulator"


#define LC "[viewer] "

using namespace osgEarth;
using namespace osgEarth::Util;

int
usage(const char* name)
{
    OE_NOTICE 
        << "\nUsage: " << name << " file.earth" << std::endl
        << MapNodeHelper().usage() << std::endl;

    return 0;
}

int
main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc,argv);

    // help?
    if ( arguments.read("--help") )
        return usage(argv[0]);

    // Increase the fov to provide a more immersive experience.
	// 增加fov值以提供更沉浸的体验。vfov:视野(Field of View),通常设置45度
	// 如果想要一个末日风格的结果,可以将其设置一个更大的值
    float vfov = 100.0f;
    arguments.read("--vfov", vfov); // 也可以支持命令行输入

    // create a viewer:
    osgViewer::Viewer viewer(arguments);

    // Tell the database pager to not modify the unref settings 不修改任何设置
    viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );

    // thread-safe initialization of the OSG wrapper manager. Calling this here
    // prevents the "unsupported wrapper" messages from OSG
	// 获取 图片 包装管理器
    osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper("osg::Image");

    // disable the small-feature culling
    viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);

    // set a near/far ratio that is smaller than the default. This allows us to get
    // closer to the ground without near clipping. If you need more, use --logdepth
    viewer.getCamera()->setNearFarRatio(0.0001);

    if ( vfov > 0.0 )
    {
        double fov, ar, n, f;
        viewer.getCamera()->getProjectionMatrixAsPerspective(fov, ar, n, f);// 获取到透视矩阵的各个参数
        viewer.getCamera()->setProjectionMatrixAsPerspective(vfov, ar, n, f);// 重新设置透视矩阵的各个参数
    }

    // load an earth file, and support all or our example command-line options
    // and earth file <external> tags    
    osg::Node* node = MapNodeHelper().load( arguments, &viewer );

    //Set our custom manipulator
    viewer.setCameraManipulator(new SkyManipulator());// 天空的操作器,继承自osgGA::CameraManipulator的操作器
    //viewer.setCameraManipulator( new osgGA::FirstPersonManipulator() );

    
    
    if ( node )
    {
        // Disable backface culling
       node->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);


        viewer.setSceneData( node );
        while(!viewer.done())
        {
            viewer.frame();            
        }
    }
    else
    {
        return usage(argv[0]);
    }
}

SkyManipulator.cpp 文件

#include "SkyManipulator"
#include <iostream>


SkyManipulator::SkyManipulator():
_heading(0.0), // 偏航角
_pitch(0.0),   // 俯仰角
_distance(1.0),// 距离
_prevX(FLT_MAX),// 初始(X, Y) 坐标点值
_prevY(FLT_MAX)
{
}

void SkyManipulator::setByMatrix(const osg::Matrixd& matrix)
{
}

void SkyManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{
}

osg::Matrixd SkyManipulator::getMatrix() const
{
    osg::Quat rot = getRotation();
    return osg::Matrixd::translate(0,0,-_distance) *  
           osg::Matrixd::rotate(rot);
}

osg::Matrixd SkyManipulator::getInverseMatrix() const
{
    return osg::Matrixd::inverse(getMatrix());
}

bool SkyManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    double maxDistance = osg::WGS_84_RADIUS_EQUATOR;// 地球(赤道/长)半径

    if (ea.getEventType() == osgGA::GUIEventAdapter::SCROLL)
    {
        
        double speed = 0.1;
        double diff = (maxDistance - _distance) * speed;

        if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
        {
            _distance += diff; // 滚轮向上
        }
        else
        {
            _distance -= diff; // 滚轮向下
        }

        _distance = osg::clampBetween(_distance, 0.0, maxDistance);
        
        return true;
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::DRAG)// 拖拽
    {
        if (_prevX != FLT_MAX && _prevY != FLT_MAX)
        {
            float dx = ea.getX() - _prevX;
            float dy = ea.getY() - _prevY;

            double maxSpeed = osg::PI * 2.0 / 300.0;
            double minSpeed = osg::PI * 2.0 / 30000.0;
			// _distance距离较远时,速度大;_distance距离较近时,速度减小
            double speed = minSpeed + (1.0 - _distance / maxDistance) * (maxSpeed - minSpeed);

            _heading -= dx * speed;
            _pitch -= dy * speed;
        }

        _prevX = ea.getX();
        _prevY = ea.getY();
        return true;
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH)// 获取坐标位置
    {
        _prevX = ea.getX();
        _prevY = ea.getY();
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE)//释放鼠标后,两个点位置还原
    {
        _prevX = FLT_MAX;
        _prevY = FLT_MAX;
    }
    else if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
    {
        if (ea.getKey()== osgGA::GUIEventAdapter::KEY_Space)// 空格键,回到home位置
        {
            home(0.0);
        }
    }
        
    
    return false;
}
// 得到旋转角
osg::Quat SkyManipulator::getRotation() const
{
    osg::Quat azim_q (  _heading,            osg::Vec3d(0,0,1) );
    osg::Quat pitch_q( -_pitch-osg::PI_2, osg::Vec3d(1,0,0) );
    osg::Matrix newRot = osg::Matrixd( azim_q * pitch_q );
    return osg::Matrixd::inverse(newRot).getRotate();  
}

void
SkyManipulator::home(double unused)
{
    _heading = 0.0;
    _pitch = 0.0;
    _distance = 0.0;
}

void
SkyManipulator::home(const osgGA::GUIEventAdapter& ,osgGA::GUIActionAdapter& us)
{
    home( 0.0 );
    us.requestRedraw();
}

今天的文章osgEarth示例分析——osgearth_skyview分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/63084.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注