简体   繁体   中英

Texture doesn't get rendered when applying a shader in OpenGL

Following a tutorial, I'm trying to render text in OpenGL using FreeType. As such, a grayscale 8-bit image is used as texture for each character in a way that each byte of the image corresponds to the texture's red component.

In order to render the text in other colors, it's suggested that you use a Shader. However, when using the provided shader, instead of seeing a colored letter, I see a colored box, as if there was no texture involved at all.

Here's how it looks like with no Shader:

图像

And here's how it looks with the Shader:

图像

(the box also gets its position shifted)

Here's the Vertex Shader code:

#version 330 core
layout (location = 0) in vec4 vertex;
out vec2 TexCoords;
void main() {
    gl_Position = vec4(vertex.xy, 0.0, 1.0);
    TexCoords = vertex.zw;
}

Here's the Fragment Shader code:

#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec4 textColor;
void main() {
    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    color = textColor * sampled;
}

And here's the code that renders on the screen:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Shader here
glUseProgram(shaderProgram);
glUniform4f(
    glGetUniformLocation(shaderProgram, "textColor"),
    0.0f, 1.0f, 0.0f, 1.0f
);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);

// Draw here
glBegin(GL_QUADS);
glTexCoord2f(1., 0.);
glVertex2f(20. / WIDTH, 20. / HEIGHT);

glTexCoord2f(0., 0.);
glVertex2f(100. / WIDTH, 20. / HEIGHT);

glTexCoord2f(0., 1.);
glVertex2f(100. / WIDTH, 100. / HEIGHT);

glTexCoord2f(1., 1.);
glVertex2f(20. / WIDTH, 100. / HEIGHT);
glEnd();

And, also, here's the whole code:

#include <stdio.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype2/freetype/freetype.h>

const unsigned int WIDTH = 640;
const unsigned int HEIGHT= 480;

const char *vertex_shader_src =
"#version 330 core\n"
"layout (location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"void main() {\n"
"gl_Position = vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;}\0";

const char *frag_shader_src = 
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main() {\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;}\0";

int main() {

    // -------------------------------------------------------------------------
    // WINDOW INITIALIZATION

    GLFWwindow *window;

    glfwInit();
    window = glfwCreateWindow(640, 480, "SHADER", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    glClearColor(0., 0. , 0., 1.);
    glColor4f(1., 1., 1., 1.);
    glPointSize(1.);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, (WIDTH*1.)/HEIGHT, 1., 0, 1., -1.);
    glViewport(0, 0, WIDTH, HEIGHT);
    // -------------------------------------------------------------------------
    // SHADER INITIALIZATION

    glewInit();

    int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertex_shader_src, NULL);
    glCompileShader(vertexShader);

    int fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragShader, 1, &frag_shader_src, NULL);
    glCompileShader(fragShader);

    int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragShader);
    glLinkProgram(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragShader);
    // -------------------------------------------------------------------------
    // TEXTURE FOR A SINGLE CHARACTER
    FT_Library ft;
    if (FT_Init_FreeType(&ft)) {
        printf("Error in FT_Init_FreeType\n");
        return 1;
    }

    FT_Face face;
    if (FT_New_Face(ft, "Ubuntu-R.ttf", 0, &face)) {
        printf("Error in FT_New_Face\n");
        return 1;
    }

    FT_Set_Pixel_Sizes(face, 0, 96);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    if (FT_Load_Char(face, 'A', FT_LOAD_RENDER)) {
        printf("Error in FT_Load_Char\n");
        return 1;
    }

    unsigned int texID;
    glGenTextures(1, &texID);
    glBindTexture(GL_TEXTURE_2D, texID);

    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RED,
        face->glyph->bitmap.width,
        face->glyph->bitmap.rows,
        0, GL_RED, GL_UNSIGNED_BYTE,
        face->glyph->bitmap.buffer
    );

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);
    FT_Done_Face(face);
    FT_Done_FreeType(ft);

    // -------------------------------------------------------------------------
    // MAIN LOOP

    while (!glfwWindowShouldClose(window)) {

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // Shader here
        glUseProgram(shaderProgram);
        glUniform4f(
            glGetUniformLocation(shaderProgram, "textColor"),
            0.0f, 1.0f, 0.0f, 1.0f
        );

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texID);
        glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);

        // Draw here
        glBegin(GL_QUADS);
        glTexCoord2f(1., 0.);
        glVertex2f(20. / WIDTH, 20. / HEIGHT);

        glTexCoord2f(0., 0.);
        glVertex2f(100. / WIDTH, 20. / HEIGHT);

        glTexCoord2f(0., 1.);
        glVertex2f(100. / WIDTH, 100. / HEIGHT);

        glTexCoord2f(1., 1.);
        glVertex2f(20. / WIDTH, 100. / HEIGHT);
        glEnd();
        glUseProgram(0);

        glFlush();
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glDeleteProgram(shaderProgram);
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;

}

I suspect the problem is either because I'm not actually sending the texture to the shader or the shader is wrong.

You are using Legacy OpenGL OpenGL and you are drawing the geometry by immediate mode glBegin / glEnd sequences. You cannot access the texture coordinates which are set by glTexCoord by a general vertex shader input. See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile? .
You must downgrade the vertex shader to GLSL version 1.20 ( OpenGL Shading Language 1.20 Specification ) and you have to access the vertex coordinates by gl_Vertex and the texture coordinates by gl_MultiTexCoord0 :

#version 120

varying vec2 TexCoords;

void main() 
{
    gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
    TexCoords = gl_MultiTexCoord0.st;
}

If you want to use the shader from the question, then you have to specify the arrays of vertex attributes by glVertexAttribPointer (see Vertex Specification ) and you have to draw the geometry by glDrawArrays :

For instance:

float vertex_attributes[] = {
     20. / WIDTH,  20. / HEIGHT, 1., 0.,
    100. / WIDTH,  20. / HEIGHT, 0., 0.,
    100. / WIDTH, 100. / HEIGHT, 0., 1.,
     20. / WIDTH, 100. / HEIGHT, 1., 1.
};

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &vertex_attributes);
glEnableVertexAttribArray(0);
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(0);

Please note, that glewInit() has to be done after glfwMakeContextCurrent() but before any OpenGL instruction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM