简体   繁体   English

无法在QWIndow(Qt5)中使用OpenGL启用深度测试

[英]Can't enable depth test with OpenGL in QWIndow (Qt5)

I'm trying to write a simple OpenGL application in Qt 5.2 using a QWindow. 我正在尝试使用QWindow在Qt 5.2中编写一个简单的OpenGL应用程序。 I can't seem to enable depth testing. 我似乎无法启用深度测试。 I've simplified the QWindow OpenGL example heavily: I'm drawing a triangle with coloured vertices, followed by a triangle with white vertices. 我已经大大简化了QWindow OpenGL示例 :我绘制了一个带有彩色顶点的三角形,然后是一个带有白色顶点的三角形。 The white triangle has larger Z coordinates, so should appear behind the coloured triangle. 白色三角形的Z坐标较大,因此应出现在彩色三角形的后面。 It doesn't. 没有。

I'm explicitly setting the QWindow's surface format's depth buffer size to 24, but when I check with the QWindow::format() function, the depth buffer size is 0. With QGLFormat, I know there's a setDepth() function that you can use to turn on the depth buffer, but there's no similar function in QSurfaceFormat. 我将QWindow的表面格式的深度缓冲区大小明确设置为24,但是当我使用QWindow::format()函数检查时,深度缓冲区大小为0。使用QGLFormat时,我知道有一个setDepth()函数可以用于打开深度缓冲区,但是QSurfaceFormat中没有类似的功能。

What am I doing wrong? 我究竟做错了什么?

My code... 我的代码...

testWindow.cpp: 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: 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: 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: 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

The problem was this: I was setting the surface format after calling my SphereWindow constructor, but creating a QOpenGLContext and setting its format inside the constructor. 问题是这样的:我在调用SphereWindow构造函数后设置了表面格式,但是创建了一个QOpenGLContext并在构造函数内设置了其格式。 The result was that the context wasn't getting a depth buffer. 结果是上下文没有获得深度缓冲区。 I've moved the calls to QOpenGLContext::setFormat() and QOpenGLContext::create() to my SphereWindow::initialize() function, and depth buffering is working for me now. 我已经QOpenGLContext::setFormat()QOpenGLContext::create()的调用移到了SphereWindow::initialize()函数中,并且深度缓冲现在对我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();
}

As I mentioned in a comment above, I had pretty much identical code in a QGLWidget-based setup, and depth buffering worked "out of the box". 正如我在上面的评论中提到的那样,我在基于QGLWidget的设置中具有几乎相同的代码,并且深度缓冲“开箱即用”。 I guess QGLWidget (or QGLFormat?) must have a depth buffer turned on by default, and QWindow (or QSurfaceFormat?) doesn't. 我猜QGLWidget(或QGLFormat?)默认情况下必须打开深度缓冲区,而QWindow(或QSurfaceFormat?)却没有。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM