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

时间:2014-07-22 18:10:27

标签: qt opengl qml qt5

我需要制作它,因此我的Qml视图的一部分被一些非Qt OpenGL渲染“接管”,并且我在获取纹理以正确显示时遇到问题所以我想我会画一条线并得到它在开始使用更复杂的代码之前要先工作。

对于那些不熟悉Qt5的人来说,整个窗口是使用OpenGL绘制的,我使用他们的QQuickWindow :: beforeRendering()信号挂钩到Qt的OpenGL绘图机制,这意味着我的绘画代码被执行每次重绘(每次垂直同步)。

我使用了Squircle示例代码(http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html)并对其进行了稍微修改,以便在屏幕的指定部分(而不是整个屏幕)进行绘制,这样就完美了。然后,我只修改了渲染器:: 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之间的一些交互。我接下来可以尝试什么?

P.S。我在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秒,然后线条消失,我只有黄色背景。

3 个答案:

答案 0 :(得分:3)

我发现了答案:我必须告诉Qt我使用旧的固定功能管道。在进行任何绘图之前进行一次函数调用可以解决问题:

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

答案 1 :(得分:1)

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

  1. 您可以在(全部)QML下绘制(参见http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html
  2. 您可以在(整个)QML
  3. 上绘制
  4. 您可以提供在QML元素上绘制的OpenGL纹理(请参阅http://qt-project.org/doc/qt-5/qsgsimpletexturenode.html
  5. 或者,你可以构建一个QWidget应用程序,在QWidget窗口中使用OpenGL,在另一个窗口中使用QML(QML小部件窗口)。

答案 2 :(得分:0)

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留在历史书中。即使它适用于像这样的虚拟着色器,它也可以省去管理任何矩阵的麻烦,而且你知道发生了什么。

PS:代码尚未经过测试,只是对Squircle代码进行了调整。如果有问题请告诉我,但我宁愿继续使用这段代码进行故障排除。