天天看點

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

net修複工具_項目實戰: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為啟動應用後恢複之前關閉的狀态)。

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

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

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

下載下傳位址

Demo v3.1.0運作包下載下傳位址:https://download.csdn.net/download/qq21497936/12542665

QQ群:1047134658(點選“檔案”搜尋“教育學科工具”,群内與博文同步更新)

Demo v2.0.0

相比于v1.0.0版本,增加了地球以外的八大行星,對布局進行了調整,适配了多種分辨率,并且優化了部分代碼;

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

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

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

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

下載下傳位址

Demo v2.0.0運作包下載下傳位址:https://download.csdn.net/download/qq21497936/12312105

QQ群:1047134658(點選“檔案”搜尋“教育學科工具”,群内與博文同步更新所有可開源的源碼模闆)

Demo v1.0.0

完成地理星球中地球的研發,包括基本操作、滑鼠pick旋轉、縮放等,包含海洋分布、人口分布、氣候分布、海平線等等功能;

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

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

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

下載下傳位址

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; }

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

更換地球紋理

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); }

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

拾取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: // virtual bool handle(osgGA::Event* event, osg::Object* pObject, osg::NodeVisitor* pNodeVisitor); // virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter, osgGA::GUIActionAdapter& guiActionAdapter, osg::Object* pObject, osg::NodeVisitor* pNodeVisitor); 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

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

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; }

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

原部落客部落格位址:https://blog.csdn.net/qq21497936

原部落客部落格導航:https://blog.csdn.net/qq21497936/article/details/102478062

本文章部落格位址:https://blog.csdn.net/qq21497936/article/details/105372492

繼續閱讀