需要帮助使用Qt5 Qml+OpenGL进行简单渲染



我需要制作它,这样我的Qml视图的一部分就被一些非Qt OpenGL渲染"接管"了,而且我在正确显示纹理方面遇到了问题,所以我想我只需要画一条线,然后再处理更复杂的代码。

对于那些不熟悉Qt5的人来说,整个窗口都是使用OpenGL绘制的,我正在使用QQuickWindow::beforeRendering((信号连接Qt的OpenGL绘制机制,这意味着我的绘制代码在每次重绘(每次垂直同步(时都会执行。

我取了Squircle样本代码(http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html(,并对其进行了轻微修改,使其能够绘制屏幕的指定部分(而不是整个屏幕(,这是完美的。然后,我只修改了renderer::paint((函数,最初画三条绿色线,2秒钟后改为画一条蓝色线:

void CtRenderer::paint()
{
static int n = 0;
if (n == 0)
{
    glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    glEnable(GL_SCISSOR_TEST);
    glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    // glClearColor(1, 0, 0, 1);
    // glClear(GL_COLOR_BUFFER_BIT);
    glLineWidth(10);
    glColor4f(0.0, 1.0, 0.0, 1);
    glBegin(GL_LINES);
    glVertex3f(0.0, 0.0, 1);        glVertex3f(1, 0.5, 1);
    glVertex3f(0.0, 0.0, 1);        glVertex3f(0.5, 0.5, 1);
    glVertex3f(0.0, 0.0, 1);        glVertex3f(0.5, 1, 1);
    glEnd();
}
else if (n == 120)
{
    glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    glEnable(GL_SCISSOR_TEST);
    glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    // glClearColor(1, 0, 0, 1);
    // glClear(GL_COLOR_BUFFER_BIT);
    glLineWidth(10);
    glColor4f(0.0, 0.0, 1.0, 1);
    glBegin(GL_LINES);
    glVertex3f(0.0, 0.0, 1);        glVertex3f(0.4, 0.8, 1);
    glEnd();
}
n++;
return;

}`

相反,我得到的是三条灰色的线,它们不断闪烁,永远不会变成一条线。经过一些在线研究,我认为也许我不应该使用glBegin((/glEnd((,所以我更改了代码:

void CtRenderer::paint()
{
static bool bOnce = true;
if (bOnce)
{
    glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    glEnable(GL_SCISSOR_TEST);
    glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
    float vertices[] = {-0.5f, -0.5f, 0.5f, 0.5f};
    glLineWidth(10);
    glColor4f(0.0, 1.0, 0.0, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, vertices);
    glDrawArrays(GL_LINES, 0, 2);
    glDisableClientState(GL_VERTEX_ARRAY);
    bOnce = false;
}
return;
}

这仍然给我一条闪烁的灰色线。

当我在Qt之外的一个简单的GLUT应用程序中尝试这个代码时,它运行得很好,所以OpenGL和Qt5-Qml之间似乎有一些交互。我下一步可以尝试什么?

附言:我在Linux Ubuntu盒子上使用Qt 5.3版本

p.p.s.为了回应一些评论,我更新了我的代码,如下所示:

void dumpGlErrors(int iLine)
{
for (;;)
{
    GLenum err = glGetError();
    if (err == GL_NO_ERROR)
        return;
    std::cout << "GL error " << err << " detected in line " << iLine << std::endl;
}
}
void CtRenderer::paint()
{
glPushMatrix();
glLoadIdentity();
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
dumpGlErrors(__LINE__);
glClearColor(1, 0, 1, 1);       // Magenta
glClear(GL_COLOR_BUFFER_BIT);
bool bDepth = glIsEnabled(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
bool bLighting = glIsEnabled(GL_LIGHTING);
glDisable(GL_LIGHTING);
bool bTexture = glIsEnabled(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_2D);
dumpGlErrors(__LINE__);
float vertices[] = { -0.5f, -0.5f, 0.1f,  0.5f, 0.5f, 0.1f,  0.5f, 0.5f, 1.0f,  0.5f, -0.5f, 1.0f };
float colors[] = { 0.0f, 1.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f, 1.0f, 1.0f,  1.0f, 1.0f, 0.0f, 1.0f };
glLineWidth(10);
glColor4f(0.0, 0.0, 1.0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, colors);
dumpGlErrors(__LINE__);
glDrawArrays(GL_LINES, 0, 4);       // 4, not 2.
dumpGlErrors(__LINE__);
// glFlush();
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
if (bTexture)
    glEnable(GL_TEXTURE_2D);
if (bLighting)
    glEnable(GL_LIGHTING);
if (bDepth)
    glEnable(GL_DEPTH_TEST);
glPopMatrix();
dumpGlErrors(__LINE__);
// In case somebody else calls glClear()
glClearColor(0, 1, 1, 1);       // Cyan
}

现在我得到了一个很好的品红色背景,我看到我的线闪烁了一次,然后它消失了,我只剩下品红色。

p.p.p.s.我尝试使用VBO类型的函数:

class Point
{
public:
float m_vertex[3];
float m_color[4];
};
void SquircleRenderer::drawBuffer()
{
QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
if (!m_bBufInit)
{
    std::cout << "SquircleRenderer::drawBuffer()" << std::endl;
    // Adding these two lines doesn't change anything
    /*
    glFuncs.initializeOpenGLFunctions();
    glFuncs.glUseProgram(0);
    */
    // Create a new VBO
    glFuncs.glGenBuffers(1, &m_buf);
    // Make the new VBO active
    glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_buf);
    static const Point points[4] = {
        { { -0.5f, -0.5f, 0.1f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
        { {  0.5f,  0.5f, 0.1f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
        { {  0.5f,  0.5f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } },
        { {  0.5f, -0.5f, 1.0f }, { 1.0f, 1.0f, 0.0f, 1.0f } }
    };
    // Upload vertex data to the video device
    glFuncs.glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Point), points, GL_STATIC_DRAW);
    dumpGlErrors(__LINE__);
    m_bBufInit = true;
}
glPushMatrix();
glLoadIdentity();
glViewport(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glEnable(GL_SCISSOR_TEST);
glScissor(m_rect.x() + 10, m_rect.y() + 10, m_rect.width() - 20, m_rect.height() - 20);
glClearColor(1, 1, 0, 1);       // Yellow
glClear(GL_COLOR_BUFFER_BIT);
glFuncs.glBindBuffer(GL_ARRAY_BUFFER, m_buf);
dumpGlErrors(__LINE__);
/*
 * "If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target
 *  (see glBindBuffer) while a vertex array is
 *  specified, pointer is treated as a byte offset into the buffer object's data store"
 */
glLineWidth(10);
glColor4f(0.0, 0.0, 1.0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Point), 0);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(Point), (void*)offsetof(Point, m_color));
dumpGlErrors(__LINE__);
glDrawArrays(GL_LINES, 0, 4);       // 4, not 2.
dumpGlErrors(__LINE__);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// In case somebody else calls glClear()
glClearColor(0, 1, 1, 1);       // Cyan
glPopMatrix();
dumpGlErrors(__LINE__);
}

和我所有的其他努力一样,我得到了一个黄色背景,我的线条出现了1/60秒,然后线条消失了,我只有黄色背景。

我发现了答案:我必须告诉Qt我正在使用旧的固定函数管道。在绘制任何图形之前调用一个函数就可以了:

QOpenGLFunctions glFuncs(QOpenGLContext::currentContext());
glFuncs.glUseProgram(0);

使用Qt Quick有三种方法可以混合OpenGL:

  1. 您可以在下绘制(整个(QML(请参阅http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html)
  2. 您可以在(整个(QML上绘制
  3. 您可以提供绘制在QML元素上的OpenGL纹理(请参见http://qt-project.org/doc/qt-5/qsgsimpletexturenode.html)

或者,您可以构建一个QWidget应用程序,并在QWidget窗口中使用OpenGL,在另一个窗口(QML窗口小部件窗口(中使用QML。

void SquircleRenderer::paint()
{
    if (!m_program) {
        m_program = new QOpenGLShaderProgram();
        m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                           "attribute highp vec4 aVertices;"
                                           "attribute highp vec4 aColors;"
                                           "varying highp vec4 vColors;"
                                           "void main() {"
                                           "    gl_Position = aVertices;"
                                           "    vColors= aColors;"
                                           "}");
        m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                           "varying highp vec4 vColors;"
                                           "void main() {"
                                           "    gl_FragColor = vColors;"
                                           "}");
        m_program->bindAttributeLocation("aVertices", 0);
        m_program->bindAttributeLocation("aColors", 1);
        m_program->link();
    }
    m_program->bind();
    m_program->enableAttributeArray(0);
    m_program->enableAttributeArray(1);
    float vertices[] = {
        -1, -1, //Diag bottom left to top right
        1, 1,
        -1, 1, //Diag top left to bottom right
        1, -1,
        -1, 0, //Horizontal line
        1, 0
    };
    float colors[] = {
        1, 1, 0, 1, 
        1, 0, 1, 1,
        0, 1, 1, 1,
        1, 0, 0, 1,
        0, 0, 1, 1,
        0, 1, 0, 1
    };
    m_program->setAttributeArray(0, GL_FLOAT, vertices, 2); //3rd to 0, 4th to 1 by default
    m_program->setAttributeArray(1, GL_FLOAT, colors, 4); 
    glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
    glDisable(GL_DEPTH_TEST);
    glClearColor(0, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    //Here I draw 3 lines, reduce to 2 instead of 6 to draw only one.
    //Change second param to choose which line to draw
    glDrawArrays(GL_LINES, 0, 6);
    m_program->disableAttributeArray(0);
    m_program->disableAttributeArray(1);
    m_program->release();
}

我的结论是将OpenGL的遗留版本留在历史书中。即使是像这样的虚拟着色器,也可以省去管理任何矩阵的麻烦,而且您知道发生了什么。

附言:这个代码还没有经过测试,它只是Squircle代码的一个调整。如果有问题,请告诉我,但我宁愿从这段代码继续进行故障排除会话。

最新更新