Qt OpenGLWidget:清除 OpenGLWidget 并显示新加载的 OBJ 文件

问题描述 投票:0回答:0

我是 OpenGL 世界的新手,我正在开发一个 Qt C++ 应用程序来加载 3D 模型(.OBJ 文件)并将其显示在模型类 UI 中的 QOpenGLWidget 中。然后,当我双击加载到我的 listWidget 中的文件时,我想清除 QOpenGLWidget 并加载在 loadOBJ() 中读取的新 3D 对象并将其显示在 QOpenGLWidget 中。我已经尝试了从执行 update()、QOpenGLWidget::update() 到销毁构造函数并再次调用它们的所有方法,但仍然没有任何反应。我想知道如何解决这个问题,因为我已经为此工作了很多个小时,但我无法解决它。

下面我放了我的 3 个代码:第一类:模型,第二类:modelDisplay,第三类:modelData

#include "model.h"
#include "ui_model.h"
#include <modeldisplay.h>
#include <modeldata.h>
#include <QCloseEvent>
#include <QMessageBox>
#include <QDir>
#include <QFileDialog>

model::model(QWidget *parent) : QDialog(parent), ui(new Ui::model)
{
    ui->setupUi(this);
    this->showMaximized();
    setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);
    setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
    ui->bt_setHome->setDisabled(true);
    ui->bt_confDraw->setDisabled(true);
    ui->bt_getCoordinates->setDisabled(true);
    ui->bt_save->setDisabled(true);

    listView();
}

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

void model::closeEvent(QCloseEvent *event)
{
    if(startDraw == true)
    {
        QMessageBox::StandardButton resBtn = QMessageBox::critical(this, "RobotProcessPath", tr("Are you sure you want to close without saving?\n"), QMessageBox::No | QMessageBox::Yes);
        if (resBtn != QMessageBox::Yes)
        {
            event->ignore();
        }
        else event->accept();
    }
    else event->accept();
}

void model::on_bt_exit2_clicked()
{
    this->close();
}

void model::on_bt_startDraw_clicked()
{
    startDraw = true;
    ui->bt_startDraw->setDisabled(true);
    ui->bt_setHome->setDisabled(false);
    ui->listWidget->setDisabled(true);
    ui->bt_save->setDisabled(false);
}

void model::on_bt_setHome_clicked()
{
    ui->bt_setHome->setDisabled(true);
}

void model::listView()
{
    folderPath = QDir::currentPath() + "/Models/";
    watcher = new QFileSystemWatcher(this);
    watcher->addPath(folderPath);
    disconnect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(NotifyChanges(QString)));
    QDir dir(folderPath);
    dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::Size | QDir::Reversed);
    QFileInfoList list = dir.entryInfoList();

    for(int i=0; i<list.size(); i++)
    {
        item = new QListWidgetItem(iconProvider.icon(list.at(i)), list.at(i).fileName(), ui->listWidget);
        ui->listWidget->addItem(item);
    }

    connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(listUpdate()));
    connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(listUpdate()));
}

void model::listUpdate()
{
    ui->listWidget->clear();
    QDir dir(folderPath);
    dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::Size | QDir::Reversed);
    QFileInfoList list = dir.entryInfoList();

    for(int i=0; i<list.size(); i++)
    {
        item = new QListWidgetItem(iconProvider.icon(list.at(i)), list.at(i).fileName(), ui->listWidget);
        ui->listWidget->addItem(item);
    }
}

void model::on_bt_upload_clicked()
{
    if(upload == false)
    {
        QString home(QDir::homePath());
        filename = QFileDialog::getOpenFileName(0, "Open file", home, "OBJ files (*.obj)");
        upload = true;
    }

    if(upload == true)
    {
        QFileInfo fname(filename);
        QString base = fname.baseName();
        QString folder = "Models";
        QString folderPath = QDir::currentPath() + "/" + folder + "/";
        QString objfile = base + ".obj";
        QString destination = folderPath + objfile;
        QDir modelsDir(folder);
        QString filePath = modelsDir.absoluteFilePath(base + ".obj");

        if(QFile::exists(filePath))
        {
            upload = false;
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Critical);
            msgBox.setWindowIcon(QIcon(":/resources/Images/4177635_arrows_loop_phases_process_icon.png"));
            msgBox.setText("The file is already uploaded, try a different file!");
            msgBox.exec();
        }
        else
        {
            QFile overWrite(destination);
            QFile::copy(filename, destination);
            QMessageBox msgBox;
            msgBox.setIcon(QMessageBox::Information);
            msgBox.setWindowIcon(QIcon(":/resources/Images/4177635_arrows_loop_phases_process_icon.png"));
            msgBox.setText("The 3D model was uploaded successfully!");
            msgBox.exec();
            upload = false;
        }
    }
}

void model::on_listWidget_doubleClicked(const QModelIndex &index)
{
    QVariant data = index.model()->data(index, Qt::DisplayRole);
    filename = data.toString();
    QString filePath = folderPath + filename;
    mD->reload();
    //mD->loadOBJ(filePath);
    ui->lb_modelname->setText(filename);
}

#include "modeldisplay.h"
#include <modeldata.h>
#include <QMouseEvent>
#include <QOpenGLContext>
#include <QDir>
#include <model.h>


modelDisplay::modelDisplay(QWidget* parent): QOpenGLWidget(parent)
{
   m_z = -400.0f;
}

modelDisplay::~modelDisplay()
{
    
}

void modelDisplay::reload()
{
    qDeleteAll(m_objects);
    m_objects.clear();
    modelDisplay* myWidget = new modelDisplay();
    QOpenGLWidget* myOpenGLWidget = new QOpenGLWidget();
    loadOBJ("obj file i want reload");
}

void modelDisplay::initializeGL()
{
    glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    initShaders();
    loadOBJ("obj default file");
}

void modelDisplay::resizeGL(int w, int h)
{
    float aspect = w / (float)h;
    m_projectionMatrix.setToIdentity();
    m_projectionMatrix.perspective(45, aspect, 1.0f, 5000.0f);
}

void modelDisplay::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    QMatrix4x4 viewMatrix;
    viewMatrix.setToIdentity();
    viewMatrix.translate(0.0, 0.0, m_z);
    viewMatrix.translate(m_translation);
    viewMatrix.rotate(m_rotation);

    m_program.bind();
    m_program.setUniformValue("u_projectionMatrix", m_projectionMatrix);
    m_program.setUniformValue("u_viewMatrix", viewMatrix);
    m_program.setUniformValue("u_lightPosition", QVector4D(0.0, 0.0, 0.0, 1.0));
    m_program.setUniformValue("u_lightPower", 0.4f);
    
    for (int i = 0; i < m_objects.size(); ++i)
    {
        m_objects[i]->draw(&m_program, context()->functions());
    }
}

void modelDisplay::initShaders()
{
    if(!m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.vsh")) close();
    if(!m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.fsh")) close();
    if(!m_program.link()) close();
}

void modelDisplay::loadOBJ(const QString &path)
{
    QFile filename(path);
    if(!filename.exists()) return;

    filename.open(QIODevice::ReadOnly);
    QTextStream input(&filename);

    QVector<QVector3D> coords;
    QVector<QVector2D> texCoord;
    QVector<QVector3D> normals;
    QVector <VertexData> vertexes;
    QVector <GLuint> indexes;

    while(!input.atEnd())
    {
        QString str = input.readLine();
        QStringList list = str.split(" ");

        if(list[0] == "v")
        {
            coords.append(QVector3D(list[1].toFloat(), list[2].toFloat(),list[3].toFloat()));
            continue;
        }
        else if(list[0] == "vt")
        {
            texCoord.append(QVector2D(list[1].toFloat(), list[2].toFloat()));
            continue;
        }
        else if(list[0] == "vn")
        {
            normals.append(QVector3D(list[1].toFloat(), list[2].toFloat(), list[3].toFloat()));
            continue;
        }
        else if(list[0] == "f")
        {
            for(int i = 1; i <= 3; ++i)
            {
                QStringList vert = list[i].split("/");
                vertexes.append(VertexData(coords[vert[0].toLong() - 1], texCoord[vert[1].toLong() - 1], normals[vert[2].toLong() - 1]));
                indexes.append(indexes.size());
            }
            continue;
            break;
        }
    }
    filename.close();
    m_objects.append(new modelData(vertexes, indexes, QImage(":/resources/Images/lightGrey.png")));
    update();
}

void modelDisplay::mousePressEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::LeftButton)
    {
        m_mousePosition = QVector2D(event->localPos());
    }
    else if (event->buttons() == Qt::RightButton)
    {
        m_mousePosition = QVector2D(event->localPos());
    }
    event->accept();
}

void modelDisplay::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() == Qt::LeftButton)
    {
        QVector2D diff = QVector2D(event->localPos()) - m_mousePosition;
        m_mousePosition = QVector2D(event->localPos());

        float angle = diff.length() / 2.0;
        QVector3D axis = QVector3D(diff.y(), diff.x(), 0.0);
        m_rotation = QQuaternion::fromAxisAndAngle(axis, angle) * m_rotation;
        update();
    }
    else if (event->buttons() == Qt::RightButton)
    {
        QVector2D diff = QVector2D(event->localPos()) - m_mousePosition;
        m_mousePosition = QVector2D(event->localPos());

        QVector3D trans(diff.x(), -diff.y(), 0.0);
        trans *= 0.5f;
        m_translation += trans;
        update();
    }
}

void modelDisplay::wheelEvent(QWheelEvent *event)
{
    if(event->delta() > 0)
    {
        m_z -= 20.0f;
    }
    else if (event->delta() < 0)
    {
        m_z += 20.0f;
    }
    update();
}

#include "modeldata.h"
#include <modeldisplay.h>

modelData::modelData():
    m_indexBuffer(QOpenGLBuffer::IndexBuffer)
    ,m_texture(0)
{

}

modelData::modelData(const QVector<VertexData> &vertData, const QVector<GLuint> &indexes, const QImage &texture):
    m_indexBuffer(QOpenGLBuffer::IndexBuffer)
    ,m_texture(0)
{
    init(vertData, indexes, texture);
}

modelData::~modelData()
{
    if(m_vertexBuffer.isCreated()) m_vertexBuffer.destroy();
    if(m_indexBuffer.isCreated()) m_indexBuffer.destroy();
    if(m_texture != 0)
    {
        if(m_texture->isCreated()) m_texture->destroy();
    }
}
void modelData::init(const QVector<VertexData> &vertData, const QVector<GLuint> &indexes, const QImage &texture)
{
    if(m_vertexBuffer.isCreated()) m_vertexBuffer.destroy();
    if(m_indexBuffer.isCreated()) m_indexBuffer.destroy();
    if(m_texture != 0)
    {
        if(m_texture->isCreated()) delete m_texture; m_texture=0;
    }

    m_vertexBuffer.create();
    m_vertexBuffer.bind();
    m_vertexBuffer.allocate(vertData.constData(), vertData.size() * sizeof(VertexData));
    m_vertexBuffer.release();

    m_indexBuffer.create();
    m_indexBuffer.bind();
    m_indexBuffer.allocate(indexes.constData(), indexes.size() * sizeof(GLuint));
    m_indexBuffer.release();

    m_texture = new QOpenGLTexture(texture.mirrored());
    m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
    m_texture->setMinificationFilter(QOpenGLTexture::Linear);
    m_texture->setWrapMode(QOpenGLTexture::Repeat);

    m_modelMatrix.setToIdentity();
}

void modelData::draw(QOpenGLShaderProgram *program, QOpenGLFunctions *functions)
{
    if(!m_vertexBuffer.isCreated() || !m_indexBuffer.isCreated()) return;

    m_texture->bind(0);

    program->setUniformValue("u_texture", 0);
    program->setUniformValue("u_modelMatrix", m_modelMatrix);

    m_vertexBuffer.bind();

    int offset = 0;
    int vertLoc = program->attributeLocation("a_position");
    program->enableAttributeArray(vertLoc);
    program->setAttributeBuffer(vertLoc, GL_FLOAT, offset, 3, sizeof(VertexData));

    offset += sizeof(QVector3D);

    int texLoc = program->attributeLocation("a_texcoord");
    program->enableAttributeArray(texLoc);
    program->setAttributeBuffer(texLoc, GL_FLOAT, offset, 2, sizeof(VertexData));

    offset += sizeof(QVector2D);

    int normLoc = program->attributeLocation("a_normal");
    program->enableAttributeArray(normLoc);
    program->setAttributeBuffer(normLoc, GL_FLOAT, offset, 3, sizeof(VertexData));

    m_indexBuffer.bind();

    functions->glDrawElements(GL_TRIANGLES, m_indexBuffer.size(), GL_UNSIGNED_INT, 0);

    m_vertexBuffer.release();
    m_indexBuffer.release();
    m_texture->release();
}

c++ qt qt-creator qtopengl
© www.soinside.com 2019 - 2024. All rights reserved.