3

新しい QOpenGLWidget クラスを試しています (これは QGLWidget クラスではないことに注意してください)。

三角形を描いています。クリップ空間で座標を受け取る単純な頂点シェーダーがあるため、行列や投影は関係ありません。-1, -1, 0, 1頂点の 1 つには座標があり、別の頂点には座標があり1, 1, 0, 1ます。

glViewport への呼び出しがまったくない場合、プログラムはresizeGLglViewport(0, 0, w, h);関数を呼び出し ているかのようにレンダリングされますが、そうではありません。つまり、三角形の 2 つの頂点は、ウィンドウのサイズをどのように変更しても、ウィンドウの左下隅と右上隅に取り付けられます。

実際に関数に呼び出しを追加すると、明らかに無視されます-w/2、h/2、またはその他の値を渡すかどうかは関係ありません。レンダリングは、呼び出した場合とまったく同じです(たとえば、三角形がウィンドウの左下 4 分の 1 に表示されることを期待します)glViewportresizeGLglViewport(0, 0, w, h);glViewport(0, 0, w/2, h/2);

関数を呼び出すとglViewport(0, 0, width()/2, height()/2)paingGLレンダリングは期待どおりです。すべてがウィンドウの左下 4 分の 1 に描画されます。

そのため、glViewport は と の間のどこかでオーバーライドされているようresizeGLですpaintGL。何が起こっていて、どうすれば修正できますか? 関数でビューポート変換を行う必要がありpaintGLますか?

ドキュメントに記載されている QGLWidget と QOpenGLWidgets の違いの 1 つは、後者が画面に直接ではなくフレームバッファにレンダリングされることです。これは説明の鍵を握ることができますか?

念のため、参照用に完全なコードを添付します。

//三角形.h

#ifndef TRIANGLE_H
#define TRIANGLE_H

#include <QOpenGLBuffer>
#include <QOpenGLFunctions>

class Triangle
{
public:
    Triangle();
    void render();
    void create();

private:
    QOpenGLBuffer position_vbo;
    QOpenGLFunctions *glFuncs;
};

#endif // TRIANGLE_H

//triangle.cpp

#include "triangle.h"

Triangle::Triangle()
    :position_vbo(QOpenGLBuffer::VertexBuffer)
{    

}

void Triangle::create()
{
    glFuncs = QOpenGLContext::currentContext()->functions();
    position_vbo.create();
    float val[] = {
           -1.0f,   -1.0f, 0.0f, 1.0f,
            0.0f, -0.366f, 0.0f, 1.0f,
            1.0f,    1.0f, 0.0f, 1.0f,
            1.0f,    0.0f, 0.0f, 1.0f,
            0.0f,    1.0f, 0.0f, 1.0f,
            0.0f,    0.0f, 1.0f, 1.0f,
        };
    position_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
    position_vbo.bind();
    position_vbo.allocate(val, sizeof(val));
    position_vbo.release();
}

void Triangle::render()
{
    position_vbo.bind();
    glFuncs->glEnableVertexAttribArray(0);
    glFuncs->glEnableVertexAttribArray(1);
    glFuncs->glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glFuncs->glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(3*4*sizeof(float)));
    glFuncs->glDrawArrays(GL_TRIANGLES, 0, 3);
    glFuncs->glDisableVertexAttribArray(0);
    glFuncs->glDisableVertexAttribArray(1);
    position_vbo.release();
}

//widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>

#include "triangle.h"

class Widget : public QOpenGLWidget
             , protected QOpenGLFunctions
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);    
    ~Widget();

protected:
    virtual void initializeGL() override;
    virtual void paintGL() override;
    virtual void resizeGL(int w, int h) override;
private:
    QOpenGLShaderProgram* program;
    Triangle t;
};

#endif // WIDGET_H

//widget.cpp

#include "widget.h"
#include <exception>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

Widget::~Widget()
{

}

void Widget::initializeGL()
{
    initializeOpenGLFunctions();
    program = new QOpenGLShaderProgram(this);
    if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertexshader.vert"))
    {
       throw std::exception(("Vertex Shader compilation error: " + program->log()).toLocal8Bit().constData());
    }
    if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragmentshader.frag"))
    {
       throw std::exception(("Fragment Shader compilation error: " + program->log()).toLocal8Bit().constData());
    }
    if(!program->link())
    {
       throw std::exception(("Program Link error: " + program->log()).toLocal8Bit().constData());
    }

    t.create();
}


void Widget::paintGL()
{
    glClearColor(0.f, 0.15f, 0.05f, 0.f);
    glClear(GL_COLOR_BUFFER_BIT);
    //glViewport(0, 0, width()/2, height()/2); //works!!
    program->bind();
    t.render();
    program->release();
}

void Widget::resizeGL(int w, int h)
{
    glViewport(0, 0, w/2, h/2); //doesn't work
}

//main.cpp

#include "widget.h"

#include <exception>

#include <QApplication>
#include <QMessageBox>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    try
    {
        Widget w;
        w.show();
        return a.exec();
    }
    catch(std::exception const & e)
    {
        QMessageBox::warning(nullptr, "Error", e.what());
    }
}

//頂点シェーダー

#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;

smooth out vec4 theColor;

void main()
{
    gl_Position = position;
    theColor = color;
}

//フラグメントシェーダー

#version 330
out vec4 fragColor;
smooth in vec4 theColor;
void main()
{
    fragColor = theColor;
}
4

1 に答える 1

2

そのため、glViewport は resizeGL と paintGL の間のどこかでオーバーライドされているようです。何が起こっていて、どうすれば修正できますか? paintGL 関数でビューポート変換を行う必要がありますか?

Qt5 は、独自の描画に OpenGL を使用する場合があります。また、QOpenGLWindow の子であるウィジェットのコンテンツも FBO にレンダリングされます。つまり、多くの glViewport 呼び出しがコードと Qt の動作の間で行われるということです。

実際に resizeGL 関数で glViewport の呼び出しを追加すると、明らかに無視されます (…)

はい。そして、あなたの期待は正確には何ですか?glViewportOpenGL プログラムを堅牢にするための唯一の有効な場所は、描画コードです。そこにあるすべてのチュートリアルglViewportで、ウィンドウのサイズ変更ハンドラー内の場所が間違っているため、焼き付ける必要があります。

paingGL 関数で glViewport(0, 0, width()/2, height()/2) を呼び出すと、レンダリングは期待どおりです

はい、それはあなたがそれを使用することになっている方法です。

于 2015-10-11T14:09:06.677 に答える