我是 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();
}