OSG3.6.4+osgQt+Qt5.14制作的osgb三维模型展示工具

1. 工具准备

1.1 OSG3.6.4

关于OSG的编译我之前的博客已经写的很详细,这里贴出链接。

1.2 osgQt

osgQt的编译过程也在我之前的博客中,这里接着贴链接。

2. 正文开始

2.1 需求分析

在做osgb三维模型的分割处理的时候,因为要查看处理之后的三维模型,每次双击打开osgb文件再选择osgviewer.exe实在是麻烦,而且命令行使用osgviewer来同时查看多个模型,也着实麻烦。
基于此,就想着写个程序,能同时选中多个osgb文件,并在一个窗口中显示。
因为是模型展示工具,因此只需要能显示选中的三维模型就行。

2.2 源码分析

2.2.1 Widget.h

Widget类是继承自QWidget的类,而要使用的osgQt则是导入的外部库osgQOpenGL.lib。该库是结合Qt和OSG的第三方库,其中要用到的osgQOpenGLWidget也是继承自QWidget,因此该类使用起来和常规的窗口类一样。
具体代码如下:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QFileDialog>
#include <QDir>

#include <osgQOpenGL/osgQOpenGLWidget>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Texture2D>

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    
    
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    osg::Camera *backGround(QString sImagePath, int iWidth, int iHeight);

    void resizeEvent(QResizeEvent *event) override;

protected slots:
    void onChoseFileButtonClicked();
    void onChoseDirButtonClicked();
    void onShowModelButtonClicked();
    void onClearButtonClicked();
    void initOsgWindow();

private:
    Ui::Widget *ui;
    osgQOpenGLWidget* _pOsgWidget;
    osg::ref_ptr<osgViewer::Viewer> _viewer;

    QStringList _lFileNames;
};
#endif // WIDGET_H

基本思路为:将选中的osgb文件通过OSG的组节点将模型读入到内存,然后使用osgQOpenGLWidget获取该窗口组件的viewer,将存储模型数据的group组节点设置为当前viewer的场景数据。
具体实现如下。

2.2.2 Widget.cpp

#include "Widget.h"
#include "ui_Widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    
    
    ui->setupUi(this);
    _pOsgWidget = new osgQOpenGLWidget(this);
    _pOsgWidget->setGeometry(220, 0, 580, 580);
    //    _pOsgWidget->setHidden(true);

    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(onChoseFileButtonClicked()));
    connect(ui->pushButton_4, SIGNAL(clicked()), this, SLOT(onChoseDirButtonClicked()));
    connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(onShowModelButtonClicked()));
    connect(ui->pushButton_3, SIGNAL(clicked()), this, SLOT(onClearButtonClicked()));
    connect(_pOsgWidget, SIGNAL(initialized()), this, SLOT(initOsgWindow()));
}

Widget::~Widget()
{
    
    
    delete ui;
}

osg::Camera *Widget::backGround(QString sImagePath, int iWidth, int iHeight)
{
    
    
    osg::ref_ptr<osg::Camera> camera = new osg::Camera;

    camera->setAllowEventFocus(false);
    camera->setProjectionMatrixAsOrtho2D(0, iWidth, 0, iHeight);
    camera->setViewport(0, 0, iWidth, iHeight);

    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setRenderOrder(osg::Camera::PRE_RENDER);
    camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    camera->setViewMatrix(osg::Matrix::identity());
    //    camera->setRenderOrder(osg::Camera::NESTED_RENDER);

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    //    geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
    geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
    osg::ref_ptr<osg::Vec3Array> vertex = new osg::Vec3Array;
    vertex->push_back(osg::Vec3(0, 0, 0));
    vertex->push_back(osg::Vec3(iWidth, 0, 0));
    vertex->push_back(osg::Vec3(iWidth, iHeight, 0));
    vertex->push_back(osg::Vec3(0, iHeight, 0));
    geometry->setVertexArray(vertex);

    osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;
    normal->push_back(osg::Vec3(0.0, 0.0, 1.0));
    geometry->setNormalArray(normal);
    geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);

    osg::ref_ptr<osg::Vec2Array> texCoord = new osg::Vec2Array;
    texCoord->push_back(osg::Vec2(0.0, 0.0));
    texCoord->push_back(osg::Vec2(1.0, 0.0));
    texCoord->push_back(osg::Vec2(1.0, 1.0));
    texCoord->push_back(osg::Vec2(0.0, 1.0));
    geometry->setTexCoordArray(0, texCoord);

    geometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::QUADS, 0, 4));

    osg::ref_ptr<osg::Image> img = osgDB::readImageFile(sImagePath.toStdString());

    osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
    tex->setImage(img);
    //    tex->setUnRefImageDataAfterApply(true);
    geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);

    geode->addDrawable(geometry);
    camera->addChild(geode);

    return camera.release();
}

void Widget::resizeEvent(QResizeEvent *)
{
    
    
    _pOsgWidget->setGeometry(220, 0, this->width() - 120, this->height() - 20);
    ui->textBrowser->setGeometry(10, 130, 190, this->height() - 150);
//    initOsgWindow();
}

void Widget::onChoseFileButtonClicked()
{
    
    
    _lFileNames.append(QFileDialog::getOpenFileNames(this, "Select osgb files", "C:/Users/Administrator/Deskop", "Osgb(*.osgb)"));

    for(auto file: _lFileNames)
    {
    
    
        ui->textBrowser->append(file);
        ui->textBrowser->append("\n");
    }
}

void Widget::onChoseDirButtonClicked()
{
    
    
    QFileInfoList infoList1 = QDir(QFileDialog::getExistingDirectory()).entryInfoList();
    for(auto file: infoList1)
    {
    
    
        if(file.isFile() && file.suffix().toStdString() == "osgb")
        {
    
    
            _lFileNames.push_back(file.filePath());
            ui->textBrowser->append(file.filePath());
            ui->textBrowser->append("\n");
        }
    }
}

void Widget::onShowModelButtonClicked()
{
    
    
    initOsgWindow();
}

void Widget::onClearButtonClicked()
{
    
    
    _lFileNames.clear();
    ui->textBrowser->setText("");
    initOsgWindow();
}

void Widget::initOsgWindow()
{
    
    
    _viewer = _pOsgWidget->getOsgViewer();

    // +++++++++这一句很重要++++++++++++
    _viewer->getCamera()->setClearMask(GL_DEPTH_BUFFER_BIT);
    // +++++++++这一句很重要++++++++++++

    _viewer->setCameraManipulator(new osgGA::TrackballManipulator);
    osg::ref_ptr<osg::Group> group = new osg::Group;
    group->addChild(backGround("here_add_your_back_ground_image_path", _pOsgWidget->width(), _pOsgWidget->height()));
    for(auto file: _lFileNames)
    {
    
    
        group->addChild(osgDB::readNodeFile(file.toStdString()));
    }
    _viewer->setSceneData(group);
}

2.2.3 ui_Widget.h

这是根据ui文件生成的ui头文件,这里直接给出设计好的界面文件:

/********************************************************************************
** Form generated from reading UI file 'Widget.ui'
**
** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_WIDGET_H
#define UI_WIDGET_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTextBrowser>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Widget
{
    
    
public:
    QTextBrowser *textBrowser;
    QPushButton *pushButton;
    QPushButton *pushButton_2;
    QLabel *label_2;
    QPushButton *pushButton_3;
    QPushButton *pushButton_4;

    void setupUi(QWidget *Widget)
    {
    
    
        if (Widget->objectName().isEmpty())
            Widget->setObjectName(QString::fromUtf8("Widget"));
        Widget->resize(800, 600);
        textBrowser = new QTextBrowser(Widget);
        textBrowser->setObjectName(QString::fromUtf8("textBrowser"));
        textBrowser->setGeometry(QRect(10, 130, 191, 451));
        QFont font;
        font.setFamily(QString::fromUtf8("\345\256\213\344\275\223"));
        font.setPointSize(10);
        textBrowser->setFont(font);
        textBrowser->setAutoFormatting(QTextEdit::AutoAll);
        pushButton = new QPushButton(Widget);
        pushButton->setObjectName(QString::fromUtf8("pushButton"));
        pushButton->setGeometry(QRect(10, 0, 71, 31));
        pushButton->setFont(font);
        pushButton_2 = new QPushButton(Widget);
        pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));
        pushButton_2->setGeometry(QRect(90, 0, 61, 31));
        pushButton_2->setFont(font);
        label_2 = new QLabel(Widget);
        label_2->setObjectName(QString::fromUtf8("label_2"));
        label_2->setGeometry(QRect(10, 90, 191, 31));
        QFont font1;
        font1.setFamily(QString::fromUtf8("\345\256\213\344\275\223"));
        font1.setPointSize(12);
        label_2->setFont(font1);
        pushButton_3 = new QPushButton(Widget);
        pushButton_3->setObjectName(QString::fromUtf8("pushButton_3"));
        pushButton_3->setGeometry(QRect(90, 40, 61, 31));
        pushButton_3->setFont(font);
        pushButton_4 = new QPushButton(Widget);
        pushButton_4->setObjectName(QString::fromUtf8("pushButton_4"));
        pushButton_4->setGeometry(QRect(10, 40, 71, 31));
        pushButton_4->setFont(font);

        retranslateUi(Widget);

        QMetaObject::connectSlotsByName(Widget);
    } // setupUi

    void retranslateUi(QWidget *Widget)
    {
    
    
        Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));
        pushButton->setText(QCoreApplication::translate("Widget", "\351\200\211\346\213\251\346\226\207\344\273\266", nullptr));
        pushButton_2->setText(QCoreApplication::translate("Widget", "\346\230\276\347\244\272", nullptr));
        label_2->setText(QCoreApplication::translate("Widget", "\345\275\223\345\211\215\350\246\201\346\230\276\347\244\272\347\232\204\346\226\207\344\273\266\357\274\232", nullptr));
        pushButton_3->setText(QCoreApplication::translate("Widget", "\346\270\205\347\251\272", nullptr));
        pushButton_4->setText(QCoreApplication::translate("Widget", "\351\200\211\346\213\251\346\226\207\344\273\266\345\244\271", nullptr));
    } // retranslateUi

};

namespace Ui {
    
    
    class Widget: public Ui_Widget {
    
    };
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_WIDGET_H

2.2.4 main.cpp

main函数里只需要实例化主窗口类并显示就行。代码如下:

#include "Widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

2.3 完整源码

见上文

3. 效果图

在这里插入图片描述

4. 不足

  1. 在窗口放大的时候,背景图片无法随之自适应大小,需点击一次显示按钮才能正常显示
  2. 模型显示窗口不支持osgViewer.exe打开时的各种快捷键操作,如W显示三角网或点云,S显示当前渲染信息等。
  3. 如移动模型之后继续添加新的模型进行显示,会将当前显示的模型恢复原位,跟新添加的模型无法进行直接对比,当然这一步可通过new一个新的osgQOpenGLWidget进行解决。
  4. 只支持三维模型的展示,别的操作啥都没有。

如果你觉得有用,不妨点个赞~~~

猜你喜欢

转载自blog.csdn.net/GeomasterYi/article/details/108720269
今日推荐