6

インスタンス化されたレンダリングに適切にVAOを使用する方法に頭を悩ませようとしています(特にQt 5.2では、OpenGL 3.3を使用しています)。私の理解では、VAO は VBO と関連する属性の状態を保存するため、描画時にすべてをバインドして有効にすることを心配する必要はなく、VAO をバインドするだけです。しかし、インスタンス化では、複数の VBO を持つことがよくあります。それらすべてをバインドする必要があることをどのように回避しますか? それとも、頂点ごとのデータとインスタンスごとのデータの両方に単一の VBO を使用する必要がありますか?

たとえば、いくつかのチュートリアルを見てきました。http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html

彼が行っていることは、インスタンスごとのデータではなく、頂点ごとのデータに VAO を使用しているように見えます。私は自分の Qt ベースのコードで同じことを試みましたが、うまくいきません (おそらく、それがどのように機能するかを完全には理解していないためです...描画が発生したときに、彼のインスタンス データをバインドする必要があるべきではありません)。 ?)

いくつかのダミー コード...これは少しばかげています。インスタンスごとの属性として透視行列を使用して、2 つの三角形の 1 つのインスタンスを描画しているだけです。

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);
}

GLWindow::~GLWindow()
{}

void GLWindow::initGL()
{  
  setupShaders();
  _program->bind();
  _positionAttr = _program->attributeLocation("position");
  _colourAttr = _program->attributeLocation("colour");
  _matrixAttr = _program->attributeLocation("matrix");

  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);

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

  _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.bind();
  _vbo.write(0, triangles.constData(), positionSize);
  _vbo.write(positionSize, colours.constData(), colourSize);
  _colourOffset = positionSize;

  _program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
  _program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);

  _program->enableAttributeArray(_positionAttr);  
  _program->enableAttributeArray(_colourAttr);

  _vao.release();

  _matbo.create();
  _matbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
  _matbo.bind();

  _matbo.allocate(4 * sizeof(QVector4D));
  _program->setAttributeBuffer(_matrixAttr, GL_FLOAT, 0, 4, 4 * sizeof(QVector4D));
  _program->enableAttributeArray(_matrixAttr);

  _func330->glVertexAttribDivisor(_matrixAttr, 1);
  _matbo.release();

  _program->release();
  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();

  _matbo.bind();
  _matbo.write(0, matrix.constData(), 4 * sizeof(QVector4D));

  _vao.bind();

  glEnable(GL_DEPTH_TEST);
  _func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);

  _vao.release();

  _program->release();

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

}

void GLWindow::setupShaders()
{

  QString vShaderSrc("#version 330\n"
    "layout(location = 0) in vec4 position;\n"
    "layout(location = 1) in vec4 colour;\n"
    "layout(location = 2) in mat4 matrix;\n"
    "smooth out vec4 col;\n"
    "void main() {\n"
    "   col = colour;\n"
    "   gl_Position = matrix * position;\n"
    "}\n");

  QString fShaderSrc("#version 330\n"
    "smooth in vec4 col;\n"
    "void main() {\n"
    "   gl_FragColor = col;\n"
    "}\n");


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


}

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

  if (isExposed())
  {
    if (! _context)
    {
      _context = new QOpenGLContext(this);
      QSurfaceFormat format(requestedFormat());
      format.setVersion(3,3);
      format.setDepthBufferSize(24);

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

      _context->makeCurrent(this);
      initializeOpenGLFunctions();

      _func330 = _context->versionFunctions<QOpenGLFunctions_3_3_Core>();
      if (_func330)
        _func330->initializeOpenGLFunctions();
      else
      {
        qWarning() << "Could not obtain required OpenGL context version";
        exit(1);
      }

      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 <QOpenGLFunctions_3_3_Core>
#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;
  QOpenGLFunctions_3_3_Core *_func330;

  GLuint _positionAttr;
  GLuint _colourAttr;
  GLuint _matrixAttr;

  size_t _colourOffset;

} ; 

#endif

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();

}

glbuffertest.pro:

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

TEMPLATE = app
TARGET = glbuffertest
INCLUDEPATH += .

CONFIG += qt debug

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

_matbo更新:バッファーを取り除き、代わりに行列データを位置と色の属性と同じ VBO に入れようとしましたが、うまくいきません。私のinitGL関数は次のようになります。

void GLWindow::initGL()
{  
  setupShaders();
  _program->bind();
  _positionAttr = _program->attributeLocation("position");
  _colourAttr = _program->attributeLocation("colour");
  _matrixAttr = _program->attributeLocation("matrix");

  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);

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

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

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


  _colourOffset = positionSize;
  _matrixOffset = positionSize + colourSize;

  _program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
  _program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);
  _program->setAttributeBuffer(_matrixAttr, GL_FLOAT, _matrixOffset, 4, 4 * sizeof(QVector4D));

  _program->enableAttributeArray(_positionAttr);  
  _program->enableAttributeArray(_colourAttr);
  _program->enableAttributeArray(_matrixAttr);
  _func330->glVertexAttribDivisor(_matrixAttr, 1);

  _vao.release();

  _program->release();
  resizeGL(width(), height());
}

paintGL:

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();

  _vao.bind();
  _vbo.write(_matrixOffset, matrix.constData(), 4 * sizeof(QVector4D));

  /* I tried replacing the three preceding lines with the following, without success: */

  /*
  _vao.bind();
  _vbo.bind();
  _vbo.write(_matrixOffset, matrix.constData(), 4 * sizeof(QVector4D));


  _program->bind();
  _program->enableAttributeArray(_matrixAttr);
  _func330->glVertexAttribDivisor(_matrixAttr, 1); */

  glEnable(GL_DEPTH_TEST);
  _func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);

  _vao.release();

  _program->release();

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

}

したがって、私のインスタンス化の問題は、間違ったタイミングで間違ったバッファーをバインドすることよりも大きいようです。他に何が間違っていますか?

4

2 に答える 2

5

私はそれを持っている。主な問題は次のとおりです。

  1. mat4 属性の 4 つの列すべてをループし、それぞれを設定して有効にし、それぞれを呼び出す必要がありglVertexAttribDivisor()ました。
  2. QOpenGLShaderProgram::setAttributeBuffer()mat4 属性の呼び出しを完全に台無しにしてしまいました。

基本的に、mat4 を 4 つの個別の vec4 属性 (列ごとに 1 つ) として扱う必要があります。これは、QMatrix4x4 データを QOpenGLBuffer オブジェクトにコピーする方法にはまったく影響しません。シェーダー プログラムにデータを処理するように指示する方法だけです。これは、元の質問でリンクしたチュートリアルと、OpenGLプログラミングガイドのインスタンス化チュートリアルの両方でよく説明されていますが、わかりませんでした。したがって、上記の最初の試みに戻ると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);
}

GLWindow::~GLWindow()
{}

void GLWindow::initGL()
{  
  setupShaders();
  _program->bind();
  _positionAttr = _program->attributeLocation("position");
  _colourAttr = _program->attributeLocation("colour");
  _matrixAttr = _program->attributeLocation("matrix");

  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);

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

  _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.bind();
  _vbo.write(0, triangles.constData(), positionSize);
  _vbo.write(positionSize, colours.constData(), colourSize);
  _colourOffset = positionSize;

  _program->setAttributeBuffer(_positionAttr, GL_FLOAT, 0, 3, 0);
  _program->setAttributeBuffer(_colourAttr, GL_FLOAT, _colourOffset, 3, 0);

  _program->enableAttributeArray(_positionAttr);  
  _program->enableAttributeArray(_colourAttr);


  _matbo.create();
  _matbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
  _matbo.bind();

  _matbo.allocate(4 * sizeof(QVector4D));

  // This is completely wrong
  /*_program->setAttributeBuffer(_matrixAttr, GL_FLOAT, 0, 4, 4 * sizeof(QVector4D));
  _program->enableAttributeArray(_matrixAttr);

  _func330->glVertexAttribDivisor(_matrixAttr, 1);
  */      

  // The right way to set up a mat4 attribute for instancing
  for (unsigned i = 0; i < 4; i++)
  {
    _program->setAttributeBuffer(_matrixAttr + i, GL_FLOAT, i * sizeof(QVector4D), 4, 4 * sizeof(QVector4D));
    _program->enableAttributeArray(_matrixAttr + i);
    _func330->glVertexAttribDivisor(_matrixAttr + i, 1);
  }

  _matbo.release();
  _vao.release();

  _program->release();
  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();
  _vao.bind();

  _matbo.bind();
  _matbo.write(0, matrix.constData(), 4 * sizeof(QVector4D));


  glEnable(GL_DEPTH_TEST);
  _func330->glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);

  _vao.release();

  _program->release();

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

}

void GLWindow::setupShaders()
{

  QString vShaderSrc("#version 330\n"
    "layout(location = 0) in vec4 position;\n"
    "layout(location = 1) in vec4 colour;\n"
    "layout(location = 2) in mat4 matrix;\n"
    "smooth out vec4 col;\n"
    "void main() {\n"
    "   col = colour;\n"
    "   gl_Position = matrix * position;\n"
    "}\n");

  QString fShaderSrc("#version 330\n"
    "smooth in vec4 col;\n"
    "void main() {\n"
    "   gl_FragColor = col;\n"
    "}\n");


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


}

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

  if (isExposed())
  {
    if (! _context)
    {
      _context = new QOpenGLContext(this);
      QSurfaceFormat format(requestedFormat());
      format.setVersion(3,3);
      format.setDepthBufferSize(24);

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

      _context->makeCurrent(this);
      initializeOpenGLFunctions();

      _func330 = _context->versionFunctions<QOpenGLFunctions_3_3_Core>();
      if (_func330)
        _func330->initializeOpenGLFunctions();
      else
      {
        qWarning() << "Could not obtain required OpenGL context version";
        exit(1);
      }

      initGL();
    }

    paintGL();
  }
}

_matboVAO をリリースする前にすべてが完了するように、mat4 属性のバインドと設定も移動したことに注意してください。私は当初、許可されている VBO の数とバインドが必要な時期について非常に混乱していました。単一の VAO 内に複数の VBO があっても問題はありません。適切な VBO を書き込み先にバインドする必要があり、適切な VBO を呼び出す前にバインドする必要があるだけQOpenGLShaderProgram::setAttributeBuffer()です。が呼び出されたときにどのバッファがバインドされているかは問題ではありませんglDraw*()(私が間違っていれば誰かがコメントしてくれると信じています)。

于 2014-05-22T07:43:27.817 に答える