OpenGL 纹理显示为黑色

OpenGL texture displaying as black

我第一次将 OpenGL 与 GLFW、GLEW 和 GLM 一起使用。我或多或少地遵循了一个教程,但也转移了注意力以专注于我目前感兴趣的方面。

目前,我正在尝试将像素绘制到纹理上,然后将其作为全屏四边形显示在屏幕上。但是,纹理总是显示为黑色,我不确定哪里出错了。

在此处初始化纹理(以及全屏四边形):

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;
}

在此处绘制纹理:

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);
}

在此处绘制屏幕:

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();
}

主循环:

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;
}

顶点着色器:

#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;
}

最后是片段着色器:

#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);
}

我相当确定我正在将四边形正确地绘制到屏幕上,因为我在片段着色器中使用注释掉的线来制作漂亮的彩色渐变效果。 但是,我可能没有正确绑定纹理。

我确认 particleColors 数组确实包含正确的浮点值。我尝试将所有红色设置为 1.0f,将所有值设置为 1.0f,将所有值设置为 255.0f(以防万一)。

我尝试添加如下行:

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);

基于我看到的其他一些帖子,但我还没有看到任何明显的效果。

我还尝试更改顶点和片段着色器计算和使用 UV 的方式,但这只会让事情变得更糟,因为此时甚至不会出现渐变效果。

希望你能弄清楚我错过了什么。感谢您的帮助。

您使用的 glTexSubImage2D 完全错误。第二个和第三个参数是偏移量,第四个和第五个参数是大小:

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);只有在使用固定功能管线且没有着色器程序时才有意义。

我想通了。 Rabbid76 的修正是重要的第一步。

之后我对我的像素阵列进行了一些调整,在缩小它之后发现我的纹理底部确实有一条小像素线。更多的探索,我发现我实际上填错了我的像素数据。修复我循环中的错误逻辑,正确填充纹理。