項目實戰:Qt+OSG教育學科工具之地理三維星球

若該文爲原創文章,未經容許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105372492
各位讀者,知識無窮而人力有窮,要麼改需求,要麼找專業人士,要麼本身研究node

紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中...(點擊傳送門)緩存

Qt開發專欄:項目實戰(點擊傳送門)

OSG開發專欄(點擊傳送門)

 

需求

        使用Qt開發內嵌的三維地理學科工具。app

 

原理

        使用Qt+Osg三維研發,依託Qt內嵌OSG。ide

 

相關博客

OSG三維開發專欄》:按部就班學習OSG工具

OSG開發筆記(一):OSG介紹、編譯:OSG介紹與編譯佈局

OSG開發筆記(四):OSG不使用osgQt重寫類嵌入Qt應用程序:OSG源碼嵌入Qt學習

OSG開發筆記(十):OSG模型的變換之平移、旋轉和縮放》:對於模型結點的基本操做測試

OSG開發筆記(十四):OSG交互》:按鍵消息和鼠標消息的交互優化

OSG開發筆記(十五):OSG光照》:光影的學習,產生立體感ui

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
原博主博客導航:http://www.javashuo.com/article/p-wxwjppoc-mo.html
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105372492

相關文章
相關標籤/搜索