我正在尝试新的QOpenGLWidget类(请注意,这是不是 QGLWidget类)。
我正画一个三角形。我有一个简单的顶点着色器,它接收剪辑空间中的坐标,因此不涉及矩阵或投影。其中一个顶点的坐标为-1, -1, 0, 1
,另一个顶点的坐标为1, 1, 0, 1
。
当我没有调用glViewport时,程序呈现就像我在 resizeGL 函数中调用glViewport(0, 0, w, h);
一样,我不是。也就是说,无论我如何调整窗口大小,三角形的两个顶点都附着在窗口的左下角和右上角。
当我在我的glViewport
函数中实际添加对resizeGL
的调用时,显然会被忽略 - 如果我通过w / 2,则无关紧要或任何其他值,渲染与我调用glViewport(0, 0, w, h);
时的渲染完全相同(例如,我希望在{{1}的情况下三角形出现在窗口的左下角四分之一处})
当我在glViewport(0, 0, w/2, h/2);
函数中调用glViewport(0, 0, width()/2, height()/2)
时,呈现符合预期 - 所有内容都在窗口的左下角绘制。
因此似乎glViewport被覆盖在paingGL
和resizeGL
之间的某处。发生了什么,我该如何解决?我是否必须在我的paintGL
函数中进行视口转换?
文档中列出的QGLWidget和QOpenGLWidgets之间的区别之一是后者渲染到帧缓冲区而不是直接渲染到屏幕上。这可能是解释的关键吗?
以防万一,我附上完整的代码供参考。
// triangle.h
paintGL
// triangle.cpp
#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
// widget.h
#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.cpp
#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
// main.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
}
//顶点着色器
#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;
}
答案 0 :(得分:2)
因此似乎在resizeGL和paintGL之间的某处覆盖了glViewport。发生了什么,我该如何解决?我是否必须在paintGL函数中进行视口转换?
Qt5可能会将OpenGL用于自己的绘图。此外,作为QOpenGLWindow的子项的小部件的内容也会呈现给FBO。这意味着,在你的代码和Qt之间进行了大量的glViewport调用。
当我在resizeGL函数中实际添加对glViewport的调用时,它显然被忽略了(...)
是肯定的。你的期望究竟是什么?调用glViewport
以使OpenGL程序健壮的唯一有效位置是绘图代码。那里的每一个教程都将glViewport
放在窗口调整大小处理程序中是错误的,应该刻录。
当我在paingGL函数中调用glViewport(0,0,width()/ 2,height()/ 2)时,呈现符合预期
是的,这就是你应该如何使用它。