Search code examples
c++qtopenglqmlshader

Why always produce 4 pictures in my qt opengl program?


Here is my code: modify from qt example: Examples\Qt-5.14.2\quick\scenegraph\openglunderqml

void SquircleRenderer::init()
{
    unsigned char* data = (unsigned char*)malloc(1200*4);
    for(int i=0;i<600;i++)
    {
        data[i*4] = 0;
        data[i*4+1] = 255;
        data[i*4+2] = 0;
        data[i*4+3] = 255;
    }
    for(int i=600;i<1200;i++)
    {
        data[i*4] = 0;
        data[i*4+1] = 0;
        data[i*4+2] = 255;
        data[i*4+3] = 255;
    }

    if (!m_program) {
        QSGRendererInterface *rif = m_window->rendererInterface();
        Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi);

        initializeOpenGLFunctions();
        if (texs[0])
        {
            glDeleteTextures(1, texs);
        }
        glGenTextures(1, texs);

        glBindTexture(GL_TEXTURE_2D, texs[0]);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 30, 40, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);


        m_program = new QOpenGLShaderProgram();
        m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,
                                                    "attribute highp vec4 vertices;"
                                                    "varying highp vec2 coords;"
                                                    "void main() {"
                                                    "    gl_Position = vertices;"
                                                    "    coords = vertices.xy;"
                                                    "}");
        m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,
                                                    "varying highp vec2 coords;"
                                                    "uniform sampler2D inputImageTexture;"
                                                    "void main() {"
                                                    "    gl_FragColor = texture2D(inputImageTexture, coords);"
                                                    "}");

        m_program->bindAttributeLocation("vertices", 0);
        m_program->link();

        arrUni[0] = m_program->uniformLocation("inputImageTexture");
    }
}

//! [4] //! [5]
void SquircleRenderer::paint()
{
    // Play nice with the RHI. Not strictly needed when the scenegraph uses
    // OpenGL directly.
    m_window->beginExternalCommands();

    m_program->bind();

    m_program->enableAttributeArray(0);

    float values[] = {
        -1, 1,
        1, 1,
        -1, -1,
        1, -1
    };

    // This example relies on (deprecated) client-side pointers for the vertex
    // input. Therefore, we have to make sure no vertex buffer is bound.
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    m_program->setAttributeArray(0, GL_FLOAT, values, 2);//values
    //m_program->setUniformValue("t", (float) m_t);

    qDebug()<<m_viewportSize.width()<<m_viewportSize.height()<<"\n";
    glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());

    glDisable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texs[0]);

    glUniform1i(arrUni[0], 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    m_program->disableAttributeArray(0);
    m_program->release();

    m_window->endExternalCommands();
}

As the picture you can see,it produces 4 same pictures,could you tell me how to produce 1 picture fill the whole window?:
As the picture you can see,it produces 4 same pictures,could you tell me how to produce 1 picture  fill the whole window? I tried so many methods, but it didn't work, I guess the problem exists in the values array or the glTexImage2D function.


Solution

  • Textures are mapped accross the [0, 1] range, and values outside of that range are modulo-looped back into it, which creates a repeating pattern. Interpreting the texture over the [-1, 1] range leads to what you are seeing since you are mapping exactly twice the UV range in both axises.

    There's a few ways to fix this. But my personal preference for a full-framebuffer pass like this is to have the attribute be normalized, and then have it converted to the expected [-1, 1] range for the clip-space coordinate in the vertex shader:

    float values[] = {
      0.f, 1.f,
      1.f, 1.f,
      0.f, 0.f,
      1.f, 0.f
    };
    
    gl_Position = vertices * 2.0 - vec4(1.0, 1.0,0.0,1.0);
    

    Another common technique is to do away with the attribute buffer altogether, and use gl_VertexID to directly generate both the UVs and coordinates.