我想在 QT 中使用 QOpenGLWidget 来创建快速线图。这些图将带有一些标签,我目前正在使用带有drawText()的QPainter。在各种示例中,OpenGL命令首先在paintGL方法中使用,然后在Qpainter中使用。 例如。这里:
如何在QOpenGlWidget的paintGL中使用QPainter
QOpenGLWidget 类中的 QPainter 和 OpenGL 原生代码
QOpenGLWidget 类中的 QPainter 和 OpenGL 原生代码
我编写了一个小示例小部件(C++),其中在paintGL中绘制线条,然后绘制文本(见下文)。我现在的问题是,第一次绘制线条和文本时都可以正确看到。 如果第二次调用paintGL方法(例如调整大小后),则只有文本仍然可见,线条不再可见。
我在 Windows 10 下使用带有 OpenGL 4.6.0 的 QT 6.4.2 和 64 位应用程序。
这是小部件的声明:
struct ColorVertex_t {
float x = 0, y = 0, z = 0, r = 0, g = 0, b = 0, a = 0.8f;
// OpenGL Helpers
static const int PositionTupleSize = 3;
static const int ColorTupleSize = 4;
static Q_DECL_CONSTEXPR inline int positionOffset() { return offsetof(ColorVertex_t, x); }
static Q_DECL_CONSTEXPR inline int colorOffset() { return offsetof(ColorVertex_t, r); }
static Q_DECL_CONSTEXPR inline int stride() { return sizeof(ColorVertex_t); }
};
class OpenGLLinePlotWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
QOpenGLShaderProgram* m_program;
QOpenGLVertexArrayObject vao_lines_; // vertex array object for the lines
unsigned int vbo_lines_ = 0; // vertex buffer object for the lines, type GL_ARRAY_BUFFER
/// vector of vertex coordinates and colors (RGB) for the lines
std::vector<ColorVertex_t> vertices_lines_;
public:
OpenGLLinePlotWidget(QWidget* parent = nullptr);
~OpenGLLinePlotWidget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
};
以下是定义:
const char* vertexShaderSourceLine = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec4 aColor; // the color variable has attribute position 1\n"
"\n"
"out vec4 ourColor; // output a color to the fragment shader\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" ourColor = aColor;\n"
"}\0";
const char* fragmentShaderSourceLine = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec4 ourColor;\n"
"void main()\n"
"{\n"
" FragColor = ourColor;\n"
"}\n\0";
OpenGLLinePlotWidget::OpenGLLinePlotWidget(QWidget* parent) : QOpenGLWidget(parent), m_program(nullptr)
{
// Define some line coordinates
size_t num_vertices = 100;
vertices_lines_.resize(num_vertices);
ColorVertex_t vertex;
for (size_t i = 0; i < num_vertices; ++i) {
vertex.x = -1. + i * 0.016;
vertex.y = sin(i * 0.314);
vertices_lines_[i] = vertex;
}
}
OpenGLLinePlotWidget::~OpenGLLinePlotWidget()
{
// Make sure the context is current and then explicitly destroy all underlying OpenGL resources.
makeCurrent();
// Actually destroy our OpenGL information
vao_lines_.destroy();
delete m_program;
doneCurrent();
}
/* This function is called by OpenGL and must not be called manually! */
void OpenGLLinePlotWidget::initializeGL()
{
// Initialize OpenGL Backend
initializeOpenGLFunctions();
glClearColor(1.f, 1.f, 1.f, 1.0f); // white background
// Create Shader (Do not release until VAO is created)
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSourceLine);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSourceLine);
m_program->link();
m_program->bind();
// ------------- cursor sample mesh buffers ---------------
vao_lines_.create();
vao_lines_.bind();
glGenBuffers(1, &vbo_lines_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_lines_);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, ColorVertex_t::stride(), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, ColorVertex_t::stride(), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
vao_lines_.release();
}
void OpenGLLinePlotWidget::resizeGL(int w, int h)
{
}
void OpenGLLinePlotWidget::paintGL()
{
if (!isValid()) return;
glClear(GL_COLOR_BUFFER_BIT);
// draw lines with OpenGL
vao_lines_.bind();
glLineWidth(2.0f);
glBindBuffer(GL_ARRAY_BUFFER, vbo_lines_);
glBufferData(GL_ARRAY_BUFFER, sizeof(ColorVertex_t) * vertices_lines_.size(), vertices_lines_.data(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINE_STRIP, 0, static_cast<GLsizei>(vertices_lines_.size()));
vao_lines_.release();
// draw some text with QPainter
QPainter painter(this);
painter.drawText(10, 20, "Hello World from QPainter in OpenGL!");
}
我尝试过以下方法:
经过大量搜索和反复试验,我不知所措,希望得到任何帮助!谢谢!
[移自评论]
当在
QPainter
中使用 paintGL
时,请务必注意底层 Qt
代码可以在当前 OpenGL 上下文上执行各种操作。因此,恢复“所有”相关状态非常重要。在所示的代码中...
vao_lines_.bind();
glLineWidth(2.0f);
glBindBuffer(GL_ARRAY_BUFFER, vbo_lines_);
glBufferData(GL_ARRAY_BUFFER, sizeof(ColorVertex_t) * vertices_lines_.size(), vertices_lines_.data(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINE_STRIP, 0, static_cast<GLsizei>(vertices_lines_.size()));
vao_lines_.release();
仅恢复 VAO。在这种情况下,还需要使用以下任一方法恢复着色器程序...
m_program->bind();
或者...
glUseProgram(m_program->programId());
void OpenGLLinePlotWidget::paintEvent(QPaintEvent* e) {
paintGL();
}
如果没有这个实现,什么也画不出来。