Я пытаюсь написать простое приложение OpenGL в Qt 5.2, используя QWindow. Я не могу включить глубинное тестирование. Я упростил Пример QWindow OpenGL в большой степени: я рисую треугольник с цветными вершинами, а затем треугольник с белыми вершинами. Белый треугольник имеет большие координаты Z, поэтому должен появиться за цветным треугольником. Это не так.
Я явно устанавливаю размер буфера глубины формата поверхности QWindow равным 24, но когда я проверяю с помощью QWindow::format()
функция, размер буфера глубины равен 0. С QGLFormat я знаю, что есть setDepth()
функция, которую вы можете использовать для включения буфера глубины, но в QSurfaceFormat подобной функции нет.
Что я делаю неправильно?
Мой код …
testWindow.cpp:
#include <QApplication>
#include <QDialog>
#include <QLabel>
#include <QResizeEvent>
#include <QSurfaceFormat>
#include <QWidget>
#include <QWindow>
#include <QVBoxLayout>
#include "SphereWindow.h"
class GLDialog : public QDialog
{
public:
GLDialog(QWidget *parent = 0, Qt::WindowFlags f = 0) : QDialog(parent, f)
{
QVBoxLayout *layout = new QVBoxLayout(this);
QSurfaceFormat format;
format.setSamples(16);
format.setDepthBufferSize(24);
qDebug() << "requested format:" << format;
window = new SphereWindow;
window->setFormat(format);
qDebug() << "actual format:" << window->format();
window->render();
QWidget *glWidget = QWidget::createWindowContainer(window, this);
layout->addWidget(glWidget);
}
~GLDialog()
{
delete window;
}
protected:
void resizeEvent(QResizeEvent *event)
{
window->resize(event->size());
window->render();
}
private:
SphereWindow *window;};int main(int argc, char **argv)
{
QApplication app(argc, argv);
QDialog *dlg = new GLDialog;
dlg->resize(640,480);
dlg->show();
return app.exec();
}
SphereWindow.h:
#include <QColor>
#include <QEvent>
#include <QExposeEvent>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLPaintDevice>
#include <QOpenGLShaderProgram>
#include <QPainter>
#include <QResizeEvent>
#include <QSize>
#include <QWindow>class SphereWindow : public QWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
SphereWindow(QWindow * = 0);
virtual ~SphereWindow();
virtual void render();
virtual void initialize();
public slots:
void resizeViewport(const QSize &);
protected:
virtual void resizeEvent(QResizeEvent *);private:
bool _initialized;
QOpenGLContext *_context;
QOpenGLPaintDevice *_device;
QOpenGLShaderProgram *_program;
QColor _backgroundColour;
GLuint _posAttr;
GLuint _colAttr;
};
SphereWindow.cpp:
#include <QCoreApplication>
#include <QMatrix4x4>
#include <QOpenGLShader>
#include <QScreen>
#include <QSurfaceFormat>
#include <QDebug>
#include "SphereWindow.h"
SphereWindow::SphereWindow(QWindow *parent)
: QWindow(parent),
_initialized(0),
_program(0),
_backgroundColour(Qt::black)
{
setSurfaceType(QWindow::OpenGLSurface);
create();
_context = new QOpenGLContext(this);
_context->setFormat(requestedFormat());
_context->create();
}
SphereWindow::~SphereWindow()
{ }void SphereWindow::resizeEvent(QResizeEvent *event)
{
resizeViewport(event->size());
}
void SphereWindow::resizeViewport(const QSize &size)
{
int width = size.width();
int height = size.height();
int side = qMin(width, height);
int hoffset = (int)((width - side) / 2.0 + 0.5);
int voffset = (int)((height - side) / 2.0 + 0.5);
glViewport(hoffset, voffset, side, side);
}
void SphereWindow::render()
{
if (! _initialized)
initialize();
if (! isExposed()) return;
glEnable(GL_DEPTH_TEST);
_context->makeCurrent(this);
glClearColor(_backgroundColour.redF(), _backgroundColour.greenF(), _backgroundColour.blueF(), 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
_program->bind();
GLfloat vertices[] = {
-0.75f, 0.75f, 0.0f,
-0.75f, -0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
0.75f, 0.75f, 0.5f,
0.75f, -0.75f, 0.5f,
-0.75f, -0.75f, 0.5f,
};
GLfloat colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
};
glVertexAttribPointer(_posAttr, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
_program->release();
_context->swapBuffers(this);
_context->doneCurrent();
}
static const char *vertexShaderSource =
"attribute highp vec4 posAttr;\n""attribute lowp vec4 colAttr;\n""varying lowp vec4 col;\n""void main() {\n"" col = colAttr;\n"" gl_Position = posAttr;\n""}\n";
static const char *fragmentShaderSource =
"varying lowp vec4 col;\n""void main() {\n"" gl_FragColor = col;\n""}\n";void SphereWindow::initialize()
{
_context->makeCurrent(this);
_program = new QOpenGLShaderProgram(this);
_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
_program->link();
_program->bind();
_posAttr = _program->attributeLocation("posAttr");
_colAttr = _program->attributeLocation("colAttr");
_program->release();initializeOpenGLFunctions();
}
testqwindow.pro:
######################################################################
# Automatically generated by qmake (3.0) Sat May 3 05:01:55 2014
######################################################################
TEMPLATE = app
TARGET = testqwindow
INCLUDEPATH += .
QT += widgets
CONFIG += debug
# Input
HEADERS += SphereWindow.h
SOURCES += SphereWindow.cpp testWindow.cpp
Проблема была в следующем: я устанавливал формат поверхности после вызова моего конструктора SphereWindow, но создавал QOpenGLContext и устанавливал его формат внутри конструктора. В результате контекст не получил буфер глубины. Я перевёл звонки на QOpenGLContext::setFormat()
а также QOpenGLContext::create()
к моему SphereWindow::initialize()
функция, и буферизация глубины работает для меня сейчас.
SphereWindow::SphereWindow(QWindow *parent)
: QWindow(parent),
_initialized(0),
_program(0),
_backgroundColour(Qt::black)
{
setSurfaceType(QWindow::OpenGLSurface);
create();
qDebug() << "format:" << format();_context = new QOpenGLContext(this);
/* Move these lines into initialize() */
// _context->setFormat(requestedFormat());
// _context->create();
}
...
void SphereWindow::initialize()
{
_context->setFormat(requestedFormat());
_context->create();
_context->makeCurrent(this);
_program = new QOpenGLShaderProgram(this);
_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
_program->link();
_program->bind();
_posAttr = _program->attributeLocation("posAttr");
_colAttr = _program->attributeLocation("colAttr");
_program->release();initializeOpenGLFunctions();
}
Как я упоминал в комментарии выше, у меня был почти идентичный код в настройке на основе QGLWidget, и буферизация глубины работала «из коробки». Я предполагаю, что QGLWidget (или QGLFormat?) Должен иметь буфер глубины, включенный по умолчанию, а QWindow (или QSurfaceFormat?) Нет.