QOpenGLWidget resizeGL НЕ место для вызова glViewport?

Я экспериментирую с новым классом QOpenGLWidget (обратите внимание, что это не класс QGLWidget).

Я рисую треугольник. У меня есть тривиальный вершинный шейдер, который получает координаты в пространстве клипа, поэтому матрицы и проекции не используются. Одна из вершин имеет координаты -1, -1, 0, 1и еще один имеет координаты 1, 1, 0, 1,

Когда у меня нет вызова к glViewport, программа отображает, как будто я звоню glViewport(0, 0, w, h); в моем resizeGL функция, которой я не являюсь. А именно, две вершины треугольника прикреплены к нижнему левому и верхнему правым углам окна независимо от того, как я изменяю размер окна.

Когда я на самом деле добавлять вызов glViewport в моем resizeGL функция, по-видимому, игнорируется — не имеет значения, если я передам w / 2, h / 2 или любое другое значение, рендеринг точно такой же, как если бы я вызвал glViewport(0, 0, w, h); (например, я ожидаю, что треугольник появится в нижней левой четверти окна в случае glViewport(0, 0, w/2, h/2);)

Когда я звоню glViewport(0, 0, width()/2, height()/2) в paingGL функция рендеринга, как и ожидалось — все рисуется в нижней левой четверти окна.

Таким образом, кажется, что glViewport переопределен где-то между resizeGL а также paintGL, Что происходит и как мне это исправить? Должен ли я прибегать к трансформации области просмотра в моем paintGL функционировать?

Одно из различий между QGLWidget и QOpenGLWidgets, перечисленных в документации, заключается в том, что последний визуализируется в кадровый буфер, а не прямо на экран. Может ли это содержать ключ к объяснению?

На всякий случай прилагаю полный код для справки.

//triangle.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;
}

3

Решение

Таким образом, кажется, что glViewport переопределен где-то между resizeGL и paintGL. Что происходит и как мне это исправить? Должен ли я прибегать к преобразованию области просмотра в моей функции paintGL?

Qt5 может использовать OpenGL для своего собственного чертежа. Кроме того, содержимое виджетов, являющихся дочерними для QOpenGLWindow, отображается в FBO. Это означает, что между вашим кодом и тем, что делает Qt, выполняется много вызовов glViewport.

Когда я на самом деле добавляю вызов glViewport в мою функцию resizeGL, она, по-видимому, игнорируется (…)

да. А твои ожидания чего именно? Единственное действительное место для звонка glViewport для того, чтобы программа OpenGL была надежной, в коде чертежа. Каждый урок там, что места glViewport в окне обработчик изменения размера неправильный и должен быть сожжен.

Когда я вызываю glViewport (0, 0, width () / 2, height () / 2) в функции paingGL, рендеринг происходит так, как ожидается

Да, вот как ты должен это использовать.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]