Strange texture display

Good day, need your help. I am trying to do simple hello world texture app using QT. I am trying to display simple generated image in my full screen rectangle, but got weird result.

If I visualize my UV coordinates all looks good, but when I try to sample texture I got total mess.

So here what I’ve got (from left to right ):

  1. UV coordinates visualization
  2. Generated image texture
  3. Result using texture sampler (should be more or less like 2 )

Here is generated texture image

And here is my result

Here is my code

    #include "viewportwidget.h"
    #include <QOpenGLWidget>
    #include <QDebug>
    #include <QOpenGLContext>
    #include "lib/gimg/CImg.h"

    using namespace cimg_library;

    ViewportWidget::ViewportWidget(QWidget *parent)
        :QOpenGLWidget(parent)
    {
        qDebug() << "Viewport Ctor";
    }

    ViewportWidget::~ViewportWidget()
    {

    }

    void ViewportWidget::initializeGL()
    {
        qDebug() << "Initializing OpenGL context...";

        // requested format
        QSurfaceFormat requestedFormat = QSurfaceFormat();
        requestedFormat.setMajorVersion(4);
        requestedFormat.setMinorVersion(5);
        requestedFormat.setProfile(QSurfaceFormat::CoreProfile);
        requestedFormat.setRenderableType(QSurfaceFormat::OpenGL);

        // create context
        QOpenGLContext *oglContext = new QOpenGLContext(this);

        oglContext->setFormat(requestedFormat);

        // init context
        bool ok = oglContext->create();

        if (!ok) {
            qDebug() << "Can not initialize OpenGL context";
            exit(1);
        }

        QSurfaceFormat actualFormat = oglContext->format();
        qDebug("Inited OpenGL version: %d.%d. Profile: %d. Render type: %d", actualFormat.majorVersion(), actualFormat.minorVersion(), actualFormat.profile(), actualFormat.renderableType());

        oglF = oglContext->functions();


        if (!oglF) {
            qDebug() << "Can not get OpenGL functions pointer";
            exit(1);
        }



        // X, Y, Z      U, V
        float vertices[] = {
             1.0f,  1.0f, 0.0f,      1.0f, 1.0f,  // top right
             1.0f, -1.0f, 0.0f,      1.0f, 0.0f, // bottom right
            -1.0f, -1.0f, 0.0f,      0.0f, 0.0f, // bottom left
            -1.0f,  1.0f, 0.0f,       0.0f, 1.0f // top left
        };

        uint indices[] = {  // note that we start from 0!
            0, 1, 3,   // first triangle
            1, 2, 3    // second triangle
        };

        oglF->glGenBuffers(1, &VBO);
        oglF->glBindBuffer(GL_ARRAY_BUFFER, VBO);
        oglF->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


        oglF->glGenBuffers(1, &EBO);
        oglF->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        oglF->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

        // compile vertex shader
        const char *vertexShaderSource = "#version 320 es\n layout (location = 0) in vec3 aPos;\n layout (location = 1) in vec2 aTexCoord;\n \n out vec2 TexCoord;\n \n void main()\n {\n     gl_Position = vec4(aPos, 1.0);\n     TexCoord = aTexCoord;\n }";
        unsigned int vertexShader;
        vertexShader = oglF->glCreateShader(GL_VERTEX_SHADER);
        oglF->glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        oglF->glCompileShader(vertexShader);

        int  success;
        char infoLog[512];
        oglF->glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

        if (!success) {
            oglF->glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            qDebug("Vertex shader compilation error: %s", infoLog);
            exit(1);
        }

        // compile fragment shader
        const char *fragmentShaderSource = "#version 320 es\n \n in highp vec2 TexCoord;\n uniform sampler2D ourTexture;\n \n out highp vec4 FragColor;\n \n void main()\n {\n     //FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n     //FragColor = vec4(TexCoord.x, TexCoord.y, 0.0f, 1.0f);\n     FragColor = texture(ourTexture, TexCoord);\n }";
        unsigned int fragmentShader;
        fragmentShader = oglF->glCreateShader(GL_FRAGMENT_SHADER);
        oglF->glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        oglF->glCompileShader(fragmentShader);
        oglF->glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);

        if (!success) {
            oglF->glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            qDebug("Fragment shader compilation error: %s", infoLog);
            exit(1);
        }

        // shader program
        shaderProgram = oglF->glCreateProgram();

        oglF->glAttachShader(shaderProgram, vertexShader);
        oglF->glAttachShader(shaderProgram, fragmentShader);
        oglF->glLinkProgram(shaderProgram);
        oglF->glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);

        if(!success) {
            oglF->glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
            qDebug("Link shader program error: %s", infoLog);
            exit(1);
        }

        oglF->glUseProgram(shaderProgram);

        //oglF->glDeleteShader(vertexShader);
        //oglF->glDeleteShader(fragmentShader);


        // link vertex buffer to vertex shader
        uint posAttribute = oglF->glGetAttribLocation(shaderProgram, "aPos");
        qDebug("Pos attribute: %d", posAttribute);
        oglF->glVertexAttribPointer(posAttribute, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        oglF->glEnableVertexAttribArray(posAttribute);

        // link vertex buffer to vertex shader
        uint textCoordAttribute = oglF->glGetAttribLocation(shaderProgram, "aTexCoord");
        qDebug("TextCoordAttribute attribute: %d", textCoordAttribute);
        oglF->glVertexAttribPointer(textCoordAttribute, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
        oglF->glEnableVertexAttribArray(textCoordAttribute);


        // ##################### TEXTURE ######################
        oglF->glGenTextures(1, &texture);

        // create image of size 256x256  3 channels, fill color 255(white)
        CImg<uchar> img(256, 256, 1, 3, 255);
        const unsigned char color[] = { 0,0,0 };
        // draw black line
        img.draw_line(10, 10, 100, 100, color, 1.0f);

        // get pointer to pixels data
        textureData = img.data();

        qDebug("Image width: %d", img.width());
        qDebug("Image height: %d", img.height());
        qDebug("Image spectrum: %d", img.spectrum());

        // save image to debug
        img.save("image.jpg");

        oglF->glActiveTexture(GL_TEXTURE0);
        oglF->glBindTexture(GL_TEXTURE_2D, texture);

        oglF->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        oglF->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        oglF->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        oglF->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        uint textureAttribute = oglF->glGetUniformLocation(shaderProgram, "ourTexture");
        qDebug("Texture attribute: %d", textureAttribute);
        oglF->glUniform1i(textureAttribute, 0);
        oglF->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);
        oglF->glGenerateMipmap(GL_TEXTURE_2D);
    }


    void ViewportWidget::paintGL()
    {
        qDebug() << "PaintGL";

        oglF->glClear(GL_COLOR_BUFFER_BIT);

        oglF->glBindBuffer(GL_ARRAY_BUFFER, VBO);
        oglF->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        oglF->glUseProgram(shaderProgram);

        oglF->glActiveTexture(GL_TEXTURE0);
        oglF->glBindTexture(GL_TEXTURE_2D, texture);

        // draw
        oglF->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        qDebug("Error: %d", oglF->glGetError());
    }

Fragment shader:

    #version 320 es

    in highp vec2 TexCoord;
    uniform sampler2D ourTexture;

    out highp vec4 FragColor;

    void main()
    {
    //FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    //FragColor = vec4(TexCoord.x, TexCoord.y, 0.0f, 1.0f);
    FragColor = texture(ourTexture, TexCoord);
    }

Spend two days tweaking different parameters, no luck. What is wrong?

Searching for “cimg_library” lead me to this:

Whereas glTexImage2D wants the data interleaved: R1G1B1R2G2B2…

If you’re only using the CImg library to generate test data, just forget it and generate the data yourself. If you actually want to do 2D drawing (and for whatever reason don’t want to use OpenGL for that), considre something more appropriate (e.g. cairo or Skia. If for some reason you’re stuck with using CImg, you can either convert the data to the appropriate format before passing it to glTexImage2D, or you can use a separate single-channel texture for each component (R, G, B), or a separate layer of a 2D array texture (that has the advantage that you only need one texture handle and one glTexImage3D call. The latter options would require the fragment shader to make three calls to texture; there’s no way to make OpenGL read RGB values from planar-storage images directly.

1 Like

Thanks that’s the reason! Also I notice that CImg can make grayscale image if it sees that there is only gray colors in the image, leading to wrong display.

The first problem is fixed by permute_axes mehod which make RGBRGBRGB format.
Cairo and Skaia is more for drawing, but I need something more for image processing, more like photoshop filters. CImg looks good for this purpose.

Thanks for quick answer!