【发布时间】:2021-08-20 09:39:49
【问题描述】:
为什么/如何将顶点属性绑定到着色器? - 有例子,但从不解释。
如果我在 GLSL 位置 = 0 中允许顶点属性,是否还必须在代码中允许?
如何正确设置 Q-vertex 数组缓冲区/对象?
这个*奇怪的神器是从哪里来的?
*蓝色方块是用于显示 QPixmap 图像的标签。绿色的是继承自 QOpenGLWidget 的 1 个 GLWidget。如您所见,它还在左上角创建了一个奇怪的正方形。
绿色窗口应该在右下角显示一个红色三角形。
相关代码可能只有最后一段,GLWidget.h。
由于某种原因,paintGL() 也只运行了几次。 代码:
.pro:
QT += core gui opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11 console
LIBS += -lopengl32
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
GLWidget.h \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
主要:
#include <iostream>
#include <cstdlib>
#include "mainwindow.h"
#include <QApplication>
#include <QGLFormat>
#include <qimagereader.h>
#include "GLWidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
//format.setSampleBuffers(true); - throws undefined
QSurfaceFormat::setDefaultFormat(format);
std::cout<<"\nContext set up!";
MainWindow w;
GLWidget g(&w);
w.show();
return a.exec();
}
主窗口.h
#include <QMainWindow>
#include <QPixmap>
#include <QDir>
#include <QFileDialog>
#include <QListWidgetItem>
#include <map>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_openButton_clicked();
void on_closeButton_clicked();
void on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
private:
Ui::MainWindow *ui;
std::map<QString, QPixmap> pictures;
};
#endif // MAINWINDOW_H
主窗口.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->label_pic->setStyleSheet("QLabel { background-color : blue; color: white;}");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_openButton_clicked()
{
QString file_name = "";
file_name = QFileDialog::getOpenFileName(this, "Open a File", QDir::homePath());
if(file_name == "") return;
QPixmap map(file_name);
///chopping just the filename
for(unsigned i = file_name.length()-1; i > 0; i--){
if(file_name[i] == '/'){
file_name = file_name.mid(i+1);
break;
}
}
ui->listWidget->addItem(file_name);
pictures.insert(std::pair<QString, QPixmap>(file_name, map));
}
void MainWindow::on_closeButton_clicked()
{
QString item = ui->listWidget->currentItem()->text();
std::map<QString, QPixmap>::iterator It = pictures.find(item);
if( It != pictures.end() ) pictures.erase( It );
QList<QListWidgetItem*> items = ui->listWidget->selectedItems();
foreach(QListWidgetItem * item, items)
{
delete ui->listWidget->takeItem(ui->listWidget->row(item));
}
}
void MainWindow::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
QString item = ui->listWidget->currentItem()->text();
ui->label_pic->setPixmap(pictures.at(item));
}
GLWidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLContext>
#include <QSurface>
#include <QWindow>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShader> //for compiling
#include <QOpenGLShaderProgram> //for link and use
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QMatrix>
#include <QGLFormat>
#include <iostream>
#include <cstdlib>
const QString vertex_src =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"}\n";
const QString fragment_src =
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"FragColor = FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
"}\n";
const GLfloat vertices[] = {
1.0f, 1.0f, -4.0f,
-1.0f, -1.0f, -4.0f,
1.0f, -1.0f, -4.0f,
1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 4.0f,
-1.0f, -1.0f, 4.0f,
1.0f, -1.0f, 4.0f
};
class GLWidget : public QOpenGLWidget
{
private:
QOpenGLShader *fragmentShader;
QOpenGLShader *vertexShader;
QOpenGLShaderProgram *shaderProgram;
QOpenGLFunctions_3_3_Core *f;
//QOpenGLFunctions *f;
QOpenGLVertexArrayObject VAO;
QOpenGLBuffer VBO;
public:
GLWidget(QWidget *parent = 0) : QOpenGLWidget(parent) {
std::cout<<"\nGLWidget lives";
}
protected:
void initializeGL() override
{
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
//initializeOpenGLFunctions<QT_OPENGL_3_3_FUNCTIONS>();
//f = QOpenGLFunctions::initializeOpenGLFunctions();
// Set up the rendering context, load shaders and other resources, etc.:
//this->setFormat(QSurfaceFormat::defaultFormat());
//f = QOpenGLContext::currentContext()->functions();
f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
f->glClearColor(0.0f, 0.2f, 0.0f, 1.0f);
f->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
f->glDisable(GL_CULL_FACE);
vertexShader = new QOpenGLShader ( QOpenGLShader :: Vertex );
if (!vertexShader->compileSourceCode(vertex_src) ) {std::cout<<"\ncould not compile vertex shader"; exit(1);}
fragmentShader = new QOpenGLShader( QOpenGLShader :: Fragment ) ;
if (! fragmentShader->compileSourceCode(fragment_src) ) {std::cout<<"\ncould not compile fragment shader"; exit(1);}
shaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
shaderProgram->addShader( vertexShader );
shaderProgram->addShader( fragmentShader );
shaderProgram->link();
//shaderProgram->create();
shaderProgram->bind();
shaderProgram->enableAttributeArray("aPos");
shaderProgram->setAttributeArray("aPos", &vertices[0], 3, 0);
/*
VAO = new QOpenGLVertexArrayObject(this);
VAO->create();
VAO->bind();
VBO = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
VBO->create();
VBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
VBO->bind();
VBO->allocate(&vertices[0], 9);
m_funcs->glEnableVertexAttribArray(0);
m_funcs->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3, (void*)0);
shaderProgram->enableAttributeArray(0);
shaderProgram->setAttributeBuffer("aPos", GL_FLOAT, 0, 3, 0);
*/
VAO.create();
if (VAO.isCreated()) VAO.bind();
else {std::cout<<"\nCould not bind VAO"; exit(1);}
VBO = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
VBO.create();
VBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
if (VBO.isCreated()) VBO.bind();
else {std::cout<<"\nCould not bind VBO"; exit(1);}
VBO.allocate(&vertices[0], 9);
f->glEnableVertexAttribArray(0);
f->glVertexAttribPointer(0, 27 * sizeof(float), GL_FLOAT, GL_FALSE, 0, (void*)0);
}
void resizeGL(int w, int h) override
{
// Update projection matrix and other size related settings:
// m_projection.setToIdentity();
// m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
glViewport( 0, 0, w, qMax( h, 1 ) );
}
void paintGL() override
{
//QOpenGLFunctions_3_3_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
// Draw the scene:
std::cout<<"\npaint runs";
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
f->glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(shaderProgram->bind()) {std::cout<<"\n\tshader bound";}
if(VBO.bind()) {std::cout<<"\n\tVAO bound";}
f->glDrawArrays(GL_TRIANGLES, 0, 9);
}
public:
void cleanup()
{
makeCurrent();
delete vertexShader;
delete fragmentShader;
delete shaderProgram;
VAO.destroy();
VBO.destroy();
doneCurrent();
}
~GLWidget()
{
cleanup();
}
};
#endif // GLWIDGET_H
(三角形顶点存在于 -1、0 和 1 Z 位置。我不想将它们绘制在视图窗格的后面。)
UI.xml
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>718</width>
<height>472</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label_pic">
<property name="geometry">
<rect>
<x>170</x>
<y>20</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="maximumSize">
<size>
<width>501</width>
<height>431</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string>Picture Goes Here (or not)</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
<widget class="QPushButton" name="openButton">
<property name="geometry">
<rect>
<x>0</x>
<y>20</y>
<width>161</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Open File..</string>
</property>
</widget>
<widget class="QPushButton" name="closeButton">
<property name="geometry">
<rect>
<x>0</x>
<y>430</y>
<width>161</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Close File</string>
</property>
</widget>
<widget class="QListWidget" name="listWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>50</y>
<width>161</width>
<height>371</height>
</rect>
</property>
</widget>
<widget class="GLWidget" name="openGLWidget">
<property name="geometry">
<rect>
<x>310</x>
<y>100</y>
<width>281</width>
<height>261</height>
</rect>
</property>
</widget>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>GLWidget</class>
<extends>QOpenGLWidget</extends>
<header location="global">GLWidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
【问题讨论】:
-
您不必在paintGl 中
makeCurrent(),它已经完成了吗?除非您使用不同的程序集(在通道中进行渲染),否则每次重新绑定着色器也可能过多。大多数关于何时和为什么的知识来自 OpenGL 而不是来自 Qt。 -
@Swift-FridayPie 是的,我读到了。在这里做了很多事情只是为了看看它是否有效。您还可以看到一些注释掉的部分。这里尝试了许多排列。现在我只想看看我的三角形,不管效率如何
-
PaintGL作为渲染过程的一部分被调用,但您通过 doneCurrent() 提前结束渲染过程。事实上,它的调用者调用了这些,但它不是递归的(即你不能“使当前”两次,然后“完成”两次)。它实际上是未定义的,因为正式的 OpenGL 上下文不再处于活动状态......并且您正在渲染到其他地方。如果您尝试在正常“更新”之外调用 OpenGL 函数,则通常使用该对,例如在事件处理程序中,以不推荐的方式呈现 -
@Swift-FridayPie 删除了它们,没有任何改变。感谢您的提示。
-
我正在尝试重新创建,但缺少 .UI xml 会阻碍这一点。可以用最少的窗口设置重新创建它吗? (只是小部件,没有别的)