1

Qt 5 でインスタンス化されたレンダリングを使用しようとしていますが、問題が発生しています。私の問題は、VAO の使用にまでさかのぼると思います。私は経験豊富なプログラマーであり、これらの問題はほとんど常に私のせいであることを知っていますが、時折 Qt のバグに遭遇したので、バグ レポートを提出する前に助けを借りることができると思いました。

インスタンス化を使用しない簡単な例をまとめました (開発中の「実際の」ソフトウェアではこの問題が発生していないにもかかわらず、何らかの理由で最新バージョンの OpenGL を要求できません)。 .

初期化時に、VAO と 2 つの VBO を作成します。1 つの VBO には何らかのデータが入力され、バインドされたままになります。もう 1 つは割り当てられますが、解放されます (実際には使用しません。最終的にインスタンス化のために行列を書き込むことを計画していましたが、そこまでは行きませんでした)。

VAO または 2 番目の VBO の使用を簡単にオンまたはオフにするために、いくつかのプリプロセッサ ディレクティブを追加しました。VAO と VBO の両方を使用すると、セグメンテーション エラーが発生します。2 番目の VBO または VAO のいずれかを取り除くと、セグ フォールトはなくなり、図面は正しく表示されます (色付きの三角形の後ろに白い三角形が描かれるはずです)。

コードは次のとおりです。

glbuffertest.cpp:

######################################################################
# Automatically generated by qmake (3.0) Fri May 16 09:49:41 2014
######################################################################

TEMPLATE = app
TARGET = glbuffertest
INCLUDEPATH += .

CONFIG += qt debug

DEFINES += USE_VAO 
DEFINES += USE_MATBO

# Input
SOURCES += glbuffertest.cpp glwindow.cpp
HEADERS += glwindow.h

glbuffertest.cpp:

#include <QGuiApplication>
#include <QSurfaceFormat>

#include "glwindow.h"



int main(int argc, char **argv)
{

  QGuiApplication app(argc, argv);

  GLWindow window;  
  window.resize(400, 400);
  window.show();

  return app.exec();
}

glwindow.cpp:

#include "glwindow.h"

#include <QColor>
#include <QMatrix4x4>
#include <QVector>
#include <QVector3D>
#include <QVector4D>

#include <QDebug>


GLWindow::GLWindow(QWindow *parent) 
  : QWindow(parent)
  , _vbo(QOpenGLBuffer::VertexBuffer)
  , _matbo(QOpenGLBuffer::VertexBuffer)
  , _context(0)
{
  setSurfaceType(QWindow::OpenGLSurface);
  create();
}

GLWindow::~GLWindow()
{}

void GLWindow::initGL()
{
  if (_context) // already initialized
    return;

  _context = new QOpenGLContext(this);
  QSurfaceFormat format(requestedFormat());
  format.setDepthBufferSize(24);

  _context->setFormat(format);
  _context->create();
  _context->makeCurrent(this);

  setupShaders();
  _program->bind();
  _positionAttr = _program->attributeLocation("position");
  _colourAttr = _program->attributeLocation("colour");
  _matrixUnif = _program->uniformLocation("matrix");
  _program->release();

  initializeOpenGLFunctions();

  QVector<QVector3D> triangles;
  triangles << QVector3D(-0.5, 0.5, 1) << QVector3D(-0.5, -0.5, 1) << QVector3D(0.5, -0.5, 1);
  triangles << QVector3D(0.5, 0.5, 0.5) << QVector3D(-0.5, -0.5, 0.5) << QVector3D(0.5, -0.5, 0.5);

  QVector<QVector3D> colours;
  colours << QVector3D(1, 0, 0) << QVector3D(0, 1, 0) << QVector3D(0, 0, 1);
  colours << QVector3D(1, 1, 1) << QVector3D(1, 1, 1) << QVector3D(1, 1, 1);

#ifdef USE_VAO

  _vao.create();
  _vao.bind();

#endif  
  _vbo.create();
  _vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
  _vbo.bind();

  size_t positionSize = triangles.size() * sizeof(QVector3D);
  size_t colourSize = colours.size() * sizeof(QVector3D);
  _vbo.allocate(positionSize + colourSize);
  _vbo.write(0, triangles.constData(), positionSize);
  _vbo.write(positionSize, colours.constData(), colourSize);
  _colourOffset = positionSize;

#ifdef USE_MATBO
  _matbo.create();
  _matbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
  _matbo.bind();

  _matbo.allocate(4 * sizeof(QVector4D));
  qDebug() << "matrix buffer size:" << _matbo.size() << "requested:" << 4 * sizeof(QVector4D);
  _matbo.release();
#endif

#ifdef USE_VAO
  glVertexAttribPointer(_positionAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
  glVertexAttribPointer(_colourAttr, 3, GL_FLOAT, GL_FALSE, 0, (void*)(_colourOffset));

  glEnableVertexAttribArray(_positionAttr);  
  glEnableVertexAttribArray(_colourAttr);
  _vao.release();
#else
  _vbo.release();
#endif

  resizeGL(width(), height());
}

void GLWindow::resizeGL(int w, int h)
{
  glViewport(0, 0, w, h);
}

void GLWindow::paintGL()
{
  if (! _context) // not yet initialized
    return;

  _context->makeCurrent(this);
  QColor background(Qt::black);

  glClearColor(background.redF(), background.greenF(), background.blueF(), 1.0f);
  glClearDepth(1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  QMatrix4x4 matrix;
  matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
  matrix.translate(0, 0, -2);

  _program->bind();

  _program->setUniformValue(_matrixUnif, matrix);

#ifdef USE_VAO
  _vao.bind();

#else
  _vbo.bind();
  glVertexAttribPointer(_positionAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
  glVertexAttribPointer(_colourAttr, 3, GL_FLOAT, GL_FALSE, 0, (void*)(_colourOffset));

  glEnableVertexAttribArray(_positionAttr);  
  glEnableVertexAttribArray(_colourAttr);
#endif

  glEnable(GL_DEPTH_TEST);

  glDrawArrays(GL_TRIANGLES, 0, 6);

#ifdef USE_VAO
  _vao.release();
#else
  glDisableVertexAttribArray(_positionAttr);
  glDisableVertexAttribArray(_colourAttr);
  _vbo.release();

#endif
  _program->release();

  _context->swapBuffers(this);
  _context->doneCurrent();

}

static const char *vertexShaderSource =
    "attribute highp vec4 position;\n"
    "attribute lowp vec4 colour;\n"
    "uniform highp mat4 matrix;\n" 
    "varying lowp vec4 col;\n"
    "void main() {\n"
    "   col = colour;\n"
    "   gl_Position = matrix * position;\n"
    "}\n";

static const char *fragmentShaderSource =
    "varying lowp vec4 col;\n"
    "void main() {\n"
    "   gl_FragColor = col;\n"
    "}\n";

void GLWindow::setupShaders()
{

  _program = new QOpenGLShaderProgram(this);
  _program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
  _program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
  _program->link();


}

void GLWindow::exposeEvent(QExposeEvent *event)
{
  Q_UNUSED(event);

  if (isExposed())
  {
    if (! _context)
      initGL();

    paintGL();
  }
}

glwindow.h:

#ifndef GL_WINDOW_H
#define GL_WINDOW_H

#include <QExposeEvent>
#include <QSurfaceFormat>
#include <QWindow>

#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>


class GLWindow : public QWindow, protected QOpenGLFunctions
{
  Q_OBJECT
public:
  GLWindow(QWindow * = 0);
  virtual ~GLWindow();

  void initGL();
  void paintGL();
  void resizeGL(int, int);

protected:
  virtual void exposeEvent(QExposeEvent *);


private:

  void setupShaders();

  QOpenGLBuffer _vbo;
  QOpenGLBuffer _matbo;
  QOpenGLContext *_context;
  QOpenGLShaderProgram *_program;
  QOpenGLVertexArrayObject _vao;

  GLuint _positionAttr;
  GLuint _colourAttr;
  GLuint _matrixUnif;

  size_t _colourOffset;

} ; 

#endif

私がやっている愚かなことを誰かが見つけることができますか?

4

1 に答える 1

2

明らかな GL の問題はglVertexAttribPointer通話にあります。

glVertexAttribPointerジェネリック頂点属性データを設定します。その動作は、現在 buffer がGL_ARRAY_BUFFERbindingにバインドされているかどうかによって異なります。

はい、それは恐ろしいです。

そして、これがそのバインディング ポイントにバインドされたバッファーの主な使用法であるため、頂点バッファー オブジェクトと呼ばれます。

バインドされたバッファがある場合、そのバッファからデータを読み取るようにその属性を構成し、最後の引数はバッファの先頭からのバイト単位のオフセットとして解釈されます。読み取られるデータの実際の量は、他の引数 (カウント、データ型のサイズ、ストライド) によって異なります。

そのバインディング ポイントでバインドされたバッファーがない場合は、最後の引数が指すメモリ位置 (プログラムのアドレス空間内) からデータを読み取ります。ここでも、メイン メモリから読み取られて GL に転送されるデータの量は、他の引数によって異なります。

あなたの場合、何もバインドされていません。バインドされていたものを解放しただけGL_ARRAY_BUFFERです。はい、それらのバッファポイントは「積み重なる」ことはありません。そのバインディング ポイントでバインドできるバッファは最大で1 つです。

電話すると

_matbo.release();

GL_ARRAY_BUFFERバインディングポイントへのバインディングをドロップするようGLに指示しています。したがって、これらの呼び出し:

glVertexAttribPointer(_positionAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(_colourAttr, 3, GL_FLOAT, GL_FALSE, 0, (void*)(_colourOffset));

GL にメイン メモリから頂点属性データを読み取るように指示していますが、メモリ アドレス0_colourOffset. すぐにクラッシュすることを期待してください...

ソリューション?を呼び出す前に、適切なバッファ オブジェクトをバインディング ポイントに再バインドするだけglVertexAttribPointerです。

_vbo.bind();
glVertexAttribPointer(_positionAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(_colourAttr, 3, GL_FLOAT, GL_FALSE, 0, (void*)(_colourOffset));

これは、作業中の非 VAO パスで行うこととまったく同じです。


その他の提案:

  1. を既に使用しているのでQOpenGLShaderProgram、その関数を使用することもできます。

    program->setAttributeBuffer(...);
    
  2. QVector3D や QMatrix4x4 などの Qt タイプの表現を OpenGL にアップロードする際には、十分に注意する必要があります。それらのメモリ内表現を制御することはできません。Qtラッパーを使用するか、生データをアップロードする必要があります(100%確実です)。

  3. 特定の (最小) GL バージョンを要求するか、少なくとも VAO の作成が成功する ( createtrue を返す) ことを使用する前にテストする必要があります。VAO は、たとえば GL 2 または ES 2 には存在しませんが、拡張機能が必要です。

于 2014-05-18T13:45:20.740 に答える