项目实战:Qt+OSG教育学科工具之地理三维星球

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105372492
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)

Qt开发专栏:项目实战(点击传送门)

OSG开发专栏(点击传送门)

需求

        使用Qt开发内嵌的三维地理学科工具。

原理

        使用Qt+Osg三维研发,依托Qt内嵌OSG。

相关博客

OSG三维开发专栏》:循序渐进学习OSG

OSG开发笔记(一):OSG介绍、编译:OSG介绍与编译

OSG开发笔记(四):OSG不使用osgQt重写类嵌入Qt应用程序:OSG源码嵌入Qt

OSG开发笔记(十):OSG模型的变换之平移、旋转和缩放》:对于模型结点的基本操作

OSG开发笔记(十四):OSG交互》:按键消息和鼠标消息的交互

OSG开发笔记(十五):OSG光照》:光影的学习,产生立体感

OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源》:pick拾取三维物体交互

OSG开发笔记(二十一):OSG使用HUD绘制图形以及纹理混合模式》:hud绘制背景和前景

OSG开发笔记(二十三):Qt使用QOpenGLWidget渲染OSG和地球仪》:基础版本的地球仪开发关键

(以上是支撑该需求的三维技术博客)

Demo v3.1.0

相比于v2.0.0版本:修复了星球纹理贴图存在缝隙的问题;修复了缩放无限制的bug;对球体、贴图、2d/3d切换、缩放、旋转增加了序列化接口(demo为启动应用后恢复之前关闭的状态)。

下载地址

Demo v3.1.0运行包下载地址:https://download.csdn.net/download/qq21497936/12542665

QQ群:1047134658(点击“文件”搜索“教育学科工具”,群内与博文同步更新)

Demo v2.0.0

相比于v1.0.0版本,增加了地球以外的八大行星,对布局进行了调整,适配了多种分辨率,并且优化了部分代码;

下载地址

Demo v2.0.0运行包下载地址:https://download.csdn.net/download/qq21497936/12312105

QQ群:1047134658(点击“文件”搜索“教育学科工具”,群内与博文同步更新所有可开源的源码模板)

Demo v1.0.0

完成地理星球中地球的研发,包括基本操作、鼠标pick旋转、缩放等,包含海洋分布、人口分布、气候分布、海平线等等功能;

下载地址

Demo v1.0.0运行包下载地址:https://download.csdn.net/download/qq21497936/11489564

QQ群:1047134658(点击“文件”搜索“教育学科工具”,群内与博文同步更新所有可开源的源码模板)

关键代码

获取背景Hud结点(传入文件)


osg::ref_ptr<osg::Node> OsgStarWidget::getBackgroundNode(QString imageFile)
{
    osg::ref_ptr<osg::Group> pGroup = new osg::Group();
    osg::ref_ptr<osg::Camera> pCamera = 0;
    osg::ref_ptr<osg::Geode> pGeode = 0;
    // 创建背景相机
    {
        // 步骤一:创建相机 pCamera = new osg::Camera(); // 步骤二:设置矩阵 显示得界面边坐标 左 右 下 上 pCamera->setProjectionMatrixAsOrtho2D(0, 1920, 0, 1080); // 步骤三:设置视图矩阵 pCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // 步骤四:不受父类矩阵影响 pCamera->setViewMatrix(osg::Matrix::identity()); // 步骤五:清除深度缓存 pCamera->setClearMask(GL_DEPTH_BUFFER_BIT); // 步骤六:设置为不接受事件,让其得不到焦点 pCamera->setAllowEventFocus(false); // 步骤七:设置渲染顺序 pCamera->setRenderOrder(osg::Camera::NESTED_RENDER); // 显示为背景HUD // 步骤八:关闭光照,通过osg::StateSet设置 pGeode = new osg::Geode(); osg::ref_ptr<osg::StateSet> pStateSet = pGeode->getOrCreateStateSet(); pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 步骤九:关闭深度测试 pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); } // 创建背景图形图片 { // 步骤一:创建几何信息体 osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry; // 步骤二:绑定顶点 osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array; pGeometry->setVertexArray(pVec3Array.get()); // 步骤三:设置顶点(屏幕坐标) pVec3Array->push_back(osg::Vec3( 0, 0, 0)); pVec3Array->push_back(osg::Vec3(1920, 0, 0)); pVec3Array->push_back(osg::Vec3(1920, 1080, 0)); pVec3Array->push_back(osg::Vec3( 0, 1080, 0)); // 步骤四:读取图片(纹理图片) osg::ref_ptr<osg::Image> pImage = new osg::Image; pImage = osgDB::readImageFile(imageFile.toStdString()); if(!pImage || !pImage->valid()) { LOG_WARN(QString("Failed to load image file: %1").arg(imageFile)); return 0; } // 步骤五:创建纹理 osg::ref_ptr<osg::Texture2D> pTexture2D = new osg::Texture2D; pTexture2D->setImage(pImage); pTexture2D->setUnRefImageDataAfterApply(true); // 步骤六:绑定纹理坐标 osg::ref_ptr<osg::Vec2Array> pVec2Array = new osg::Vec2Array; pGeometry->setTexCoordArray(0, pVec2Array.get()); // 步骤七:设置纹理坐标 pVec2Array->push_back(osg::Vec2(0.0, 0.0)); pVec2Array->push_back(osg::Vec2(1.0, 0.0)); pVec2Array->push_back(osg::Vec2(1.0, 1.0)); pVec2Array->push_back(osg::Vec2(0.0, 1.0)); // 步骤八:关联纹理状态 osg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet(); pStateSet->setTextureAttributeAndModes(0, pTexture2D.get(), osg::StateAttribute::ON); // 步骤九:绑定法线 osg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array; pGeometry->setNormalArray(pVec3ArrayNormal.get()); // 步骤十:设置法线方式 pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL); // 步骤十一:设置法线方向 pVec3ArrayNormal->push_back(osg::Vec3f(0.0, 1.0, 0.0)); // 步骤十二:绘制四个顶点的图形 pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4)); // 步骤十三:将图形添加进几何节点 pGeode->addDrawable(pGeometry.get()); } pCamera->addChild(pGeode); pGroup->addChild(pCamera); return pGroup; } 

更换地球纹理


void OsgStarWidget::change3DImage(QString imageFile)
{
    // 步骤一:读取图片(纹理图片)
    osg::ref_ptr<osg::Image> pImage = 0;
    pImage = osgDB::readImageFile(imageFile.toStdString());
    if(!pImage || !pImage->valid())
    {
        LOG_WARN(QString("Failed to load image file: %1").arg(imageFile)); return; } // 步骤二:创建纹理 osg::ref_ptr<osg::Texture2D> pTexture2D = new osg::Texture2D; pTexture2D->setImage(pImage); pTexture2D->setUnRefImageDataAfterApply(true); // 步骤三:球体体渲染纹理 osg::ref_ptr<osg::StateSet> pStateSet = _pGeode->getOrCreateStateSet(); pStateSet->setTextureAttribute(0, pTexture2D.get()); pStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); _pGeode->setStateSet(pStateSet); }

拾取pick、缩放

MyUserPickEventHandler.h

#ifndef MYUSERPICKEVENTHANDLER_H
#define MYUSERPICKEVENTHANDLER_H

#include <osg/Node> #include <osgViewer/Viewer> class MyUserPickEventHandler : public osgGA::GUIEventHandler { public: MyUserPickEventHandler(); public: osg::ref_ptr<osg::MatrixTransform> getMatrixTransform() const; void setMatrixTransform(const osg::ref_ptr<osg::MatrixTransform> &pMatrixTransform); float getRadius() const; void setRadius(float radius); float getMinScale() const; void setMinScale(float minScale); float getMaxScale() const; void setMaxScale(float maxScale); float getZoomInStep() const; void setZoomInStep(float zoomInStep); float getZoomOutStep() const; void setZoomOutStep(float zoomOutStep); public: /** Handle event. Override the handle(..) method in your event handlers to respond to events. */ // virtual bool handle(osgGA::Event* event, osg::Object* pObject, osg::NodeVisitor* pNodeVisitor); /** Handle events, return true if handled, false otherwise. */ // virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter, osgGA::GUIActionAdapter& guiActionAdapter, osg::Object* pObject, osg::NodeVisitor* pNodeVisitor); /** Deprecated, Handle events, return true if handled, false otherwise. */ virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter, osgGA::GUIActionAdapter& guiActionAdapter); protected: bool pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Vec3dArray *pVec3dArrayOut); bool pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Node *pNode, osg::Vec3dArray *pVec3dArrayOut); osg::Vec3d screen2Word(osg::Vec3d screenVec3d, osgViewer::Viewer *pViewer); private: bool _pickEarth; osg::Vec3d _originVec3d; osg::Vec3d _lastVec3d; float _radius; float _maxScale; float _minScale; float _zoomInStep; float _zoomOutStep; osg::ref_ptr<osg::MatrixTransform> _pMatrixTransform; }; #endif // MYUSEREVENTHANDLER_H 

MyUserPickEventHandler.cpp

#include "MyUserPickEventHandler.h"
#include "define.h" #include "osg/MatrixTransform" #include <QtMath> #include "MyMath.h" MyUserPickEventHandler::MyUserPickEventHandler() : osgGA::GUIEventHandler(), _pickEarth(false) { } osg::ref_ptr<osg::MatrixTransform> MyUserPickEventHandler::getMatrixTransform() const { return _pMatrixTransform; } void MyUserPickEventHandler::setMatrixTransform(const osg::ref_ptr<osg::MatrixTransform> &pMatrixTransform) { _pMatrixTransform = pMatrixTransform; } float MyUserPickEventHandler::getRadius() const { return _radius; } void MyUserPickEventHandler::setRadius(float radius) { _radius = radius; } float MyUserPickEventHandler::getMaxScale() const { return _maxScale; } void MyUserPickEventHandler::setMaxScale(float maxScale) { _maxScale = maxScale; } float MyUserPickEventHandler::getMinScale() const { return _minScale; } void MyUserPickEventHandler::setMinScale(float minScale) { _minScale = minScale; } float MyUserPickEventHandler::getZoomInStep() const { return _zoomInStep; } void MyUserPickEventHandler::setZoomInStep(float zoomInStep) { _zoomInStep = zoomInStep; } //bool MyUserEventHandler::handle(osgGA::Event *event, osg::Object *object, osg::NodeVisitor *pNodeVisitor) //{ // LOG_DEBUG(""); // return false; //} //bool MyUserEventHandler::handle(const osgGA::GUIEventAdapter &guiEventAdapter, osgGA::GUIActionAdapter &guiActionAdapter, osg::Object *pObject, osg::NodeVisitor *pNodeVisitor) //{ // LOG_DEBUG(""); // return true; //} bool MyUserPickEventHandler::handle(const osgGA::GUIEventAdapter &guiEventAdapter, osgGA::GUIActionAdapter &guiActionAdapter) { switch (guiEventAdapter.getEventType()) { case osgGA::GUIEventAdapter::EventType::SCROLL: case osgGA::GUIEventAdapter::EventType::PUSH: case osgGA::GUIEventAdapter::EventType::RELEASE: case osgGA::GUIEventAdapter::EventType::DRAG: break; default: return true; break; } bool flag = false; if(_pMatrixTransform.get() == 0) { LOG_INFO("Fialed to handle, because it's not set the node of transform!!!"); return true; } // 使用智能指针就挂,原因未知 // osg::ref_ptr<osgViewer::Viewer> pViewer = dynamic_cast<osgViewer::Viewer*>(&guiActionAdapter); osgViewer::Viewer *pViewer = dynamic_cast<osgViewer::Viewer*>(&guiActionAdapter); if(pViewer == 0) { LOG_WARN("Fialed to get viewer!"); return true; } osg::Matrix matrix = _pMatrixTransform->getMatrix(); osg::Vec3d vec3d; osg::ref_ptr<osg::Vec3dArray> pVec3dArray = new osg::Vec3dArray(); qreal offsetAngle; float nowRadius = qSqrt(_pMatrixTransform->getBound().radius2() / 3.0); switch (guiEventAdapter.getEventType()) { case osgGA::GUIEventAdapter::EventType::SCROLL: switch (guiEventAdapter.getScrollingMotion()) { case osgGA::GUIEventAdapter::SCROLL_UP: // 鼠标滚轮向上放大 if(nowRadius / _radius >= _maxScale) { break; } matrix *= osg::Matrix::scale(_zoomInStep, _zoomInStep, _zoomInStep); _pMatrixTransform->setMatrix(matrix); flag = true; break; case osgGA::GUIEventAdapter::SCROLL_DOWN: // 鼠标滚轮向下缩小 if(nowRadius / _radius <= _minScale) { break; } matrix *= osg::Matrix::scale(_zoomOutStep, _zoomOutStep, _zoomOutStep); _pMatrixTransform->setMatrix(matrix); flag = true; break; default: break; } break; case osgGA::GUIEventAdapter::EventType::PUSH: switch (guiEventAdapter.getButton()) { case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON: if(pick(guiEventAdapter.getX(), guiEventAdapter.getY(), pViewer, _pMatrixTransform, pVec3dArray.get())) { // 拾取到物体 _pickEarth = true; _lastVec3d = pVec3dArray->at(0); }else{ _pickEarth = false; } break; default: break; } break; case osgGA::GUIEventAdapter::EventType::DRAG: if(pick(guiEventAdapter.getX(), guiEventAdapter.getY(), pViewer, _pMatrixTransform, pVec3dArray.get())) { if(_pickEarth == false) { // 拾取到物体 _pickEarth = true; _lastVec3d = pVec3dArray->at(0); break; } // 相交点 vec3d = pVec3dArray->at(0); // 计算x轴方向角度 offsetAngle = MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(vec3d.y(), vec3d.z())) -MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(_lastVec3d.y(), _lastVec3d.z())); matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-offsetAngle), 1, 0, 0); // 计算z轴方向角度 offsetAngle = MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(vec3d.y(), vec3d.x())) -MyMath::lineAngleRakeRatio(QPoint(0,0), QPointF(_lastVec3d.y(), _lastVec3d.x())); matrix *= osg::Matrix::rotate(osg::DegreesToRadians(offsetAngle), 0, 0, 1); _pMatrixTransform->setMatrix(matrix); _lastVec3d = vec3d; }else{ _pickEarth = false; } break; case osgGA::GUIEventAdapter::EventType::RELEASE: _pickEarth = false; break; default: break; } return true; } bool MyUserPickEventHandler::pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Vec3dArray *pVec3dArrayOut) { bool ret = false; // 判断场景 if(!pViewer->getSceneData()) { return false; } // 判断是否拾取到物体 osgUtil::LineSegmentIntersector::Intersections intersections; if(pViewer->computeIntersections(x, y, intersections)) { for(auto iter = intersections.begin(); iter != intersections.end(); iter++) { pVec3dArrayOut->push_back(iter->getWorldIntersectPoint()); ret = true; } } return ret; } bool MyUserPickEventHandler::pick(const double x, const double y, osgViewer::Viewer *pViewer, osg::Node *pNode, osg::Vec3dArray *pVec3dArrayOut) { bool ret = false; // 判断场景 if(!pViewer->getSceneData()) { return false; } // 判断是否拾取到物体 osgUtil::LineSegmentIntersector::Intersections intersections; if(pViewer->computeIntersections(x, y, intersections)) { for(auto iter = intersections.begin(); iter != intersections.end(); iter++) { for(int index = 0; index < iter->nodePath.size(); index++) { if(iter->nodePath.at(index)->asNode() == pNode) { pVec3dArrayOut->push_back(iter->getWorldIntersectPoint()); ret = true; break; } } break; } } return ret; } osg::Vec3d MyUserPickEventHandler::screen2Word(osg::Vec3d screenVec3d, osgViewer::Viewer *pViewer) { osg::ref_ptr<osg::Camera> pCamera = pViewer->getCamera(); osg::Matrix matrix = pCamera->getViewMatrix() * pCamera->getProjectionMatrix() * pCamera->getViewport()->computeWindowMatrix(); osg::Matrix intertMatrix = osg::Matrix::inverse(matrix); osg::Vec3d worldVec3d = screenVec3d * intertMatrix; return worldVec3d; } float MyUserPickEventHandler::getZoomOutStep() const { return _zoomOutStep; } void MyUserPickEventHandler::setZoomOutStep(float zoomOutStep) { _zoomOutStep = zoomOutStep; } 

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105372492

猜你喜欢

转载自www.cnblogs.com/qq21497936/p/13179432.html