Home > front end >  OpenGL texture displaying as black
OpenGL texture displaying as black

Time:04-23

I am using OpenGL for the first time with GLFW, GLEW, and GLM. I've been more or less following a tutorial but also diverted in order to focus on the aspects I'm interested in at the moment.

Currently, I'm trying to draw pixels to a texture and then display that on the screen as a fullscreen quad. However, the texture is always displaying as black and I'm unsure where I went wrong.

Initializing the texture here (as well as the fullscreen quad):

int InitializeRenderTarget(GameManager* gameManager)
{
    // Vertex Array Object
    GLuint vertexArrayID;
    glGenVertexArrays(1, &vertexArrayID);
    glBindVertexArray(vertexArrayID);

    programID = LoadShaders("Source/Graphics/SimpleVertexShader.vert", "Source/Graphics/RenderTextureFragmentShader.frag");

    // The texture we're going to render to
    glGenTextures(1, &renderedTexture);
    glBindTexture(GL_TEXTURE_2D, renderedTexture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
        gameManager->GRID_SIZE, gameManager->GRID_SIZE,
        0, GL_RGB, GL_UNSIGNED_BYTE, 0);
    glGenerateMipmap(GL_TEXTURE_2D);

    // The fullscreen quad's FBO
    static const GLfloat g_quad_vertex_buffer_data[] = {
        -1.0f, -1.0f, 0.0f, //0.0f, 0.0f,
         1.0f, -1.0f, 0.0f, //1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f, //0.0f, 1.0f,
        -1.0f,  1.0f, 0.0f, //0.0f, 1.0f,
         1.0f, -1.0f, 0.0f, //1.0f, 0.0f,
         1.0f,  1.0f, 0.0f, //1.0f, 1.0f
    };

    glGenBuffers(1, &quad_vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);

    texID = glGetUniformLocation(programID, "renderedTexture");

    glEnable(GL_TEXTURE_2D);

    return 0;
}

Drawing onto the texture here:

void RenderToTexture(GameManager* gameManager)
{
    glBindTexture(GL_TEXTURE_2D, renderedTexture);

    float* particleColors = gameManager->getParticleColors();
    glTexSubImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
        gameManager->GRID_SIZE, gameManager->GRID_SIZE,
        0, GL_RGB, GL_FLOAT, (GLvoid*)particleColors);
    glGenerateMipmap(GL_TEXTURE_2D);
    
    // Poor filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

Drawing to screen here:

void RenderToScreen()
{
    // Render to the screen
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // Render on the whole framebuffer, complete from the lower left corner to the upper right
    glViewport(100, 100, screenWidth-200, screenHeight-200);

    // Clear the screen
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Use our shader
    glUseProgram(programID);

    // Bind our texture in Texture Unit 0
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, renderedTexture);
    // Set our "renderedTexture" sampler to use Texture Unit 0
    glUniform1i(texID, 0);

    // 1rst attribute buffer : vertices
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
    glVertexAttribPointer(
        0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,  // stride
        (void*)0            // array buffer offset
    );

    // Draw the triangles !
    glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles

    glDisableVertexAttribArray(0);

    // Swap buffers
    glfwSwapBuffers(window);
    glfwPollEvents();
}

The main loop:

int main(void)
{
    if (InitializeWindow() != 0) {
        fprintf(stderr, "Failed to open GLFW window.\n");
        getchar();
        glfwTerminate();
        return -1;
    }
    
    GameManager* gameManager = gameManager->getInstance();

    if (InitializeRenderTarget(gameManager) != 0) {
        fprintf(stderr, "Failed to initialize render target.\n");
        getchar();
        glfwTerminate();
        return -1;
    }

    do {
        gameManager->Update();
        RenderToTexture(gameManager);
        RenderToScreen();
    } // Check if the ESC key was pressed or the window was closed
    while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
        glfwWindowShouldClose(window) == 0);

    CleanUp();

    return 0;
}

Vertex shader:

#version 460 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;

// Output data ; will be interpolated for each fragment.
out vec2 UV;

void main(){
    gl_Position =  vec4(vertexPosition_modelspace, 1);
    UV = (vertexPosition_modelspace.xy vec2(1,1))/2.0;
}

and finally fragment shader:

#version 460 core

in vec2 UV;

out vec4 color;

uniform sampler2D renderedTexture;

void main(){
    color = texture(renderedTexture, UV);
    //color = vec4(UV.x, UV.y, 0, 1);
}

I'm fairly certain that I am drawing the quad to the screen correctly as I used the commented out line in the fragment shader to make a nice colorful gradient effect. However, I might not be binding the texture correctly.

I confirmed that the particleColors array does contain float values correctly. I've tried setting all the reds to 1.0f, and all the values to 1.0f, as well as all values to 255.0f (just in case).

I tried adding lines like:

glEnable(GL_TEXTURE_2D);

glGenerateMipmap(GL_TEXTURE_2D);

// Poor filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

based on some other posts I saw but I have yet to see any visible effect.

I also tried changing how the vertex and fragment shader were calculating and using the UVs but that only made things worse as the gradient effect wouldn't even appear at that point.

Hopefully you can figure out what I've missed. Thank you for any help.

CodePudding user response:

You're using glTexSubImage2D completely wrong. The 2nd and 3rd arguments are the offsets and the 4th and 5th arguments are the size:

glTexSubImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gameManager->GRID_SIZE, gameManager->GRID_SIZE, 0, GL_RGB, GL_FLOAT, (GLvoid*)particleColors);

glTexSubImage2D(
    GL_TEXTURE_2D, 0, 
    0, 0, gameManager->GRID_SIZE, gameManager->GRID_SIZE,
    GL_RGB, GL_FLOAT, (GLvoid*)particleColors);

glEnable(GL_TEXTURE_2D); only has meaning when using the fixed function pipeline and no shader program.

CodePudding user response:

I have figured it out. The correction by Rabbid76, was a big first step.

Afterwards I played some with my pixel array, and after making it smaller found that I did have a small line of pixels at the bottom of my texture. More poking around and I found I had actually filled my pixel data wrong. Fixing my logic in error in my loop filled the texture properly.

  • Related