I have used OpenGL in SDL before, but I have just started to learn QT. In QT, using OpenGL is proving to be somewhat of a pain. I have the following two files:
我以前在SDL中使用过OpenGL,但我刚开始学习QT。在QT中,使用OpenGL被证明有点痛苦。我有以下两个文件:
main.cpp
main.cpp中
#include <stdio.h>
#include <QApplication>
#include "glwidget.hpp"
#include <QGLFormat>
int main(int args, char *argv[]) {
QApplication app(args, argv);
GLWidget openGLWidget;
openGLWidget.show();
return app.exec();
}
glwidget.hpp
glwidget.hpp
#include <GL/glew.h>
#include <QGLWidget>
class GLWidget : public QGLWidget {
protected:
void initializeGL();
void paintGL();
};
void GLWidget::initializeGL() {
if(glewInit() != GLEW_OK) {
fprintf(stderr, "GLEW failed to initialize.");
}
}
void GLWidget::paintGL() {
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
QGLWidget::swapBuffers();
}
helloworld.pro
helloworld.pro
TEMPLATE = app
INCLUDEPATH += .
LIBS += -lGL -lGLEW
# Input
SOURCES += main.cpp
HEADERS += glwidget.hpp
QT += widgets opengl
When I compile and run this, I get a window that has whatever was behind it at the time of creation imprinted on it. What I am expecting is a red screen. What am I missing?
当我编译并运行它时,我会得到一个窗口,其中包含创建时印在其上的任何内容。我期待的是一个红色的屏幕。我错过了什么?
UPDATE
UPDATE
I have edited my GLWidget implementation, and I got it to work. However, it only works when I call glDrawArrays (see the paintGL function below). In SDL, glDrawArrays wasn't necessary to see a blank colored screen. Without glDrawArrays, qt seems to ignore glClear() for some reason. Does anyone know why?
我已经编辑了我的GLWidget实现,我得到了它的工作。但是,它只在我调用glDrawArrays时才有效(参见下面的paintGL函数)。在SDL中,glDrawArrays不需要看到空白的彩色屏幕。没有glDrawArrays,由于某种原因,qt似乎忽略了glClear()。有谁知道为什么?
GLWidget::GLWidget(QGLWidget* parent) : QGLWidget(QGLFormat(), parent) {
}
void GLWidget::initializeGL() {
if(glewInit() != GLEW_OK) {
fprintf(stderr, "GLEW failed to initialize.");
}
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.addShaderFromSourceFile(QGLShader::Vertex,
"vertexShader.vert");
shaderProgram.addShaderFromSourceFile(QGLShader::Fragment,
"fragmentShader.frag");
shaderProgram.link();
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
}
void GLWidget::paintGL() {
shaderProgram.bind();
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
setAutoBufferSwap(false);
//glDrawArrays(GL_TRIANGLES, 0, 1);
swapBuffers();
shaderProgram.release();
}
void GLWidget::resizeGL(int width, int height) {
if(height == 0) {
height = 1;
}
if(width == 0) {
width = 1;
}
glViewport(0, 0, width, height);
}
UPDATE 2
更新2
I thought that maybe Qt was doing something sneaky under the hood, and that if I did everything manually, I would get rid of the problem. But qt still somehow knows whether I am using a program or not, and whether I am using glDrawArrays or not. In the code below, taking out either glDrawArrays or glUseProgram makes the code not work. It must have something to do with what happens inside QGLContext.
我想也许Qt正在做一些鬼鬼祟祟的事情,如果我手动完成所有事情,我就会摆脱这个问题。但qt仍然以某种方式知道我是否使用程序,以及我是否使用glDrawArrays。在下面的代码中,取出glDrawArrays或glUseProgram会使代码无效。它必须与QGLContext中发生的事情有关。
#include <stdio.h>
#include <fstream>
#include <string>
#include "glwidget.hpp"
GLWidget::GLWidget(QWidget* parent) : QGLWidget(QGLFormat(), parent) {
}
void GLWidget::initializeGL() {
if(glewInit() != GLEW_OK) {
fprintf(stderr, "GLEW failed to initialize.");
}
glContext = this->context();
if(!glContext->create()) {
fprintf(stderr, "Failed to create context.\n");
}
glContext->makeCurrent();
program = glCreateProgram();
addShader(program, GL_VERTEX_SHADER, "vertexShader.vert");
addShader(program, GL_FRAGMENT_SHADER, "fragmentShader.frag");
linkProgram(program);
setAutoBufferSwap(false);
}
void GLWidget::paintGL() {
glUseProgram(program);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 1);
glContext->swapBuffers();
glUseProgram(0);
}
void GLWidget::resizeGL(int width, int height) {
if(height == 0) {
height = 1;
}
if(width == 0) {
width = 1;
}
glViewport(0, 0, width, height);
}
GLuint GLWidget::addShader(GLuint programID, GLuint shaderType, std::string fileName) {
GLuint shader = glCreateShader(shaderType);
std::ifstream file(fileName.c_str());
std::string source = "";
if(file.is_open()) {
std::string line;
while(getline(file, line)) {
source += line + "\n";
}
} else {
fprintf(stderr, "File %s failed to open.\n", fileName.c_str());
}
const char* sourceC = source.c_str();
glShaderSource(shader, 1, &sourceC, NULL);
glCompileShader(shader);
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if(compileStatus == GL_FALSE) {
fprintf(stderr, "Shader %s failed to compile.\n", fileName.c_str());
return 0;
}
glAttachShader(programID, shader);
return shader;
}
void GLWidget::linkProgram(GLuint programID) {
glLinkProgram(programID);
GLint linkStatus;
glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
if(linkStatus == GL_FALSE) {
fprintf(stderr,"Failed to link program.\n");
}
}
2 个解决方案
#1
5
I found the solution to my problem. QGLWidget is deprecated. Anyone who sees this question in the future should use QOpenGLWidget instead.
我找到了解决问题的方法。不推荐使用QGLWidget。任何在将来看到这个问题的人都应该使用QOpenGLWidget。
#include "GLShaderWidget.hpp"
GLShaderWidget::GLShaderWidget(QWidget* parent) : QOpenGLWidget(parent)
{
}
GLShaderWidget::~GLShaderWidget() {
}
void GLShaderWidget::initializeGL() {
glClearColor(1, 0, 0, 1);
}
void GLShaderWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
}
This code works just fine. The only difference is that I am using QOpenGLWidget instead of QGLWidget. It is far better than QGLWidget anyways, because it automatically re-sizes the view port, and actually uses two frame-buffers internally (apparently QGLWidget was just pretending to use two buffers).
这段代码工作得很好。唯一的区别是我使用的是QOpenGLWidget而不是QGLWidget。它远比QGLWidget好得多,因为它会自动重新调整视图端口的大小,实际上在内部使用两个帧缓冲区(显然QGLWidget只是假装使用两个缓冲区)。
#2
0
You may have a configuration problem on your PC.
您的PC上可能存在配置问题。
Here is the example I use on debian amd64/stable with Qt4.8.
这是我在debian amd64 / stable和Qt4.8上使用的例子。
header
头
#ifndef GLWIDGET_HPP
#define GLWIDGET_HPP
#include <QGLWidget>
class GlWidget:
public QGLWidget
{
public:
GlWidget(QWidget *parent=0);
~GlWidget();
protected:
void initializeGL();
void paintGL();
};
#endif // GLWIDGET_HPP
implementation
履行
#include "glwidget.hpp"
GlWidget::GlWidget(QWidget* parent)
: QGLWidget(QGLFormat(), parent)
{
}
GlWidget::~GlWidget()
{
}
void GlWidget::initializeGL()
{
}
void GlWidget::paintGL()
{
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
The only problem I see is the creation of another window owned by GLEW. But you may close it. The QGLWidget
instance is promoted at the bottom right.
我看到的唯一问题是创建GLEW拥有的另一个窗口。但你可以关闭它。 QGLWidget实例在右下方提升。
#1
5
I found the solution to my problem. QGLWidget is deprecated. Anyone who sees this question in the future should use QOpenGLWidget instead.
我找到了解决问题的方法。不推荐使用QGLWidget。任何在将来看到这个问题的人都应该使用QOpenGLWidget。
#include "GLShaderWidget.hpp"
GLShaderWidget::GLShaderWidget(QWidget* parent) : QOpenGLWidget(parent)
{
}
GLShaderWidget::~GLShaderWidget() {
}
void GLShaderWidget::initializeGL() {
glClearColor(1, 0, 0, 1);
}
void GLShaderWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
}
This code works just fine. The only difference is that I am using QOpenGLWidget instead of QGLWidget. It is far better than QGLWidget anyways, because it automatically re-sizes the view port, and actually uses two frame-buffers internally (apparently QGLWidget was just pretending to use two buffers).
这段代码工作得很好。唯一的区别是我使用的是QOpenGLWidget而不是QGLWidget。它远比QGLWidget好得多,因为它会自动重新调整视图端口的大小,实际上在内部使用两个帧缓冲区(显然QGLWidget只是假装使用两个缓冲区)。
#2
0
You may have a configuration problem on your PC.
您的PC上可能存在配置问题。
Here is the example I use on debian amd64/stable with Qt4.8.
这是我在debian amd64 / stable和Qt4.8上使用的例子。
header
头
#ifndef GLWIDGET_HPP
#define GLWIDGET_HPP
#include <QGLWidget>
class GlWidget:
public QGLWidget
{
public:
GlWidget(QWidget *parent=0);
~GlWidget();
protected:
void initializeGL();
void paintGL();
};
#endif // GLWIDGET_HPP
implementation
履行
#include "glwidget.hpp"
GlWidget::GlWidget(QWidget* parent)
: QGLWidget(QGLFormat(), parent)
{
}
GlWidget::~GlWidget()
{
}
void GlWidget::initializeGL()
{
}
void GlWidget::paintGL()
{
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
The only problem I see is the creation of another window owned by GLEW. But you may close it. The QGLWidget
instance is promoted at the bottom right.
我看到的唯一问题是创建GLEW拥有的另一个窗口。但你可以关闭它。 QGLWidget实例在右下方提升。