Question

I'm following a tutorial to set up some VBOs for the modern OpenGL. I managed to get a mesh and shader running (shader set to make each pixel red).

The problem is, as soon as I push back texture coordinates. I see nothing! With them commented out, I see a dark cyan triangle on the center of the screen. With the texture I expect a white brick texture to appear on that triangle, but nope...

I really have no idea what's wrong here! Hope some more experienced people have a clue. ;)

This is my mesh code (or VBO code):

Mesh::Mesh() {
    //Generate vertex array
    glGenVertexArrays(1, &arrayObject);

    //Generate buffers
    glGenBuffers(VBO_COUNT, buffers);
}

Mesh::Mesh(ObjectData *obj) {
    //Initialize first
    Mesh();

    //Set object to parameter
    setObject(obj);
}

Mesh::~Mesh() {
    //Delete buffer
    glDeleteBuffers(VBO_COUNT, buffers);

    //Delete array
    glDeleteVertexArrays(1, &arrayObject);
}

void Mesh::draw() {
    //Tell OpenGL which array to use
    glBindVertexArray(arrayObject);

    glDrawArrays(GL_TRIANGLES, 0, object->vertices.size());

    glBindVertexArray(NULL);
}

void Mesh::updateVBO() {
    //Tell OpenGL which vertex array to use from now
    glBindVertexArray(arrayObject);

    //Set buffer data
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_VERTEX]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * object->vertices.size(), &object->vertices.front(), GL_STATIC_DRAW);

    //Set shader attribute data
    glEnableVertexAttribArray(VBO_VERTEX);
    glVertexAttribPointer(VBO_VERTEX, 3, GL_FLOAT, GL_FALSE, NULL, NULL);

    if (object->texCoords.size()) {
        //Set buffer data
        glBindBuffer(GL_ARRAY_BUFFER, buffers[VBO_TEXCORD]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * object->texCoords.size(), &object->texCoords.front(), GL_STATIC_DRAW);

        //Set shader attribute data
        glEnableVertexAttribArray(VBO_TEXCORD);
        glVertexAttribPointer(VBO_TEXCORD, 2, GL_FLOAT, GL_FALSE, NULL, NULL);
    }

    //Unbind vertex array
    glBindVertexArray(NULL);
}

void Mesh::setObject(ObjectData *obj) {
    object = obj;
    updateVBO();
}

Here is my shader code:

Shader::Shader(string fileName) {
    m_program = glCreateProgram();
    m_shaders[SHA_VERTEX] = createShader(loadShader(fileName + ".vs"), GL_VERTEX_SHADER);
    m_shaders[SHA_FRAGMENT] = createShader(loadShader(fileName + ".fs"), GL_FRAGMENT_SHADER);

    for (int i = 0; i < SHA_COUNT; i++) {
        glAttachShader(m_program, m_shaders[i]);
    }

    glBindAttribLocation(m_program, VBO_VERTEX, "vertices");
    glBindAttribLocation(m_program, VBO_TEXCORD, "texCoords");

    glLinkProgram(m_program);
    checkShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program");

    glValidateProgram(m_program);
    checkShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program");
}

Shader::~Shader() {
    for (int i = 0; i < SHA_COUNT; i++) {
        glDetachShader(m_program, m_shaders[i]);
        glDeleteShader(m_shaders[i]);
    }

    glDeleteProgram(m_program);
}

string Shader::loadShader(string filePath) {
    ifstream file;
    file.open((filePath).c_str());

    string output;
    string line;

    if(file.is_open()) {
        while(file.good()) {
            getline(file, line);
            output.append(line + "\n");
        }
    }
    else {
        printf("Unable to load shader: %s\n", filePath.c_str());
    }

    return output;
}

void Shader::checkShaderError(GLuint shader, GLuint flag, bool isProgram, string errorMessage) {
    GLint success = 0;
    GLchar error[1024] = {0};

    if (isProgram) {
        glGetProgramiv(shader, flag, &success);
    }
    else {
        glGetShaderiv(shader, flag, &success);
    }

    if (success == GL_FALSE) {
        if(isProgram) {
            glGetProgramInfoLog(shader, sizeof(error), NULL, error);
        }
        else {
            glGetShaderInfoLog(shader, sizeof(error), NULL, error);
        }

        printf("%s: '%s'\n", errorMessage.c_str(), error);
    }
}

GLuint Shader::createShader(string text, unsigned int type) {
    GLuint shader = glCreateShader(type);
    if (shader == 0) {
        printf("Error compiling shader type %i\n", type);
    }

    const GLchar *p[1];
    p[0] = text.c_str();
    GLint lengths[1];
    lengths[0] = text.length();

    glShaderSource(shader, 1, p, lengths);
    glCompileShader(shader);

    checkShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!");

    return shader;
}

void Shader::bind() {
    glUseProgram(m_program);
}

Here is my vertices and texCoords:

//Create test objects
ObjectData *obj = new ObjectData();

obj->vertices.push_back(glm::vec3(-0.5, -0.5, 0));
obj->vertices.push_back(glm::vec3(0, 0.5, 0));
obj->vertices.push_back(glm::vec3(0.5, -0.5, 0));
//obj->texCoords.push_back(glm::vec2(0, 0));
//obj->texCoords.push_back(glm::vec2(0.5, 1));
//obj->texCoords.push_back(glm::vec2(1, 0));

Here is my object data:

struct ObjectData {
    vector <glm::vec3> vertices;
    vector <glm::vec2> texCoords;

    ObjectData();
};

Vertex shader:

#version 120

attribute vec3 vertices;
attribute vec2 texCoords;

varying vec2 shared_texCoords;

void main() {
    gl_Position = vec4(vertices, 1.0);
    shared_texCoords = texCoords;
}

Fragment shader:

#version 120

uniform sampler2D diffuse;

varying vec2 shared_texCoords;

void main() {
    gl_FragColor = texture2D(diffuse, shared_texCoords); //vec4(1.0, 0.0, 0.0, 1.0);
}

EDIT: Texture loading:

Texture::Texture(string fileName) {
    SDL_Surface *rawImage = IMG_Load(fileName.c_str());

    if (rawImage == NULL) {
        printf("Unable to load texture: %s\n", fileName.c_str());
    }
    else {
        //Convert to a texture of pure color pixels for OpenGL
        SDL_Surface *image = SDL_CreateRGBSurface(0, rawImage->w, rawImage->h, 24, 0xff000000, 0x00ff0000, 0x0000ff00, 0);
        SDL_BlitSurface(rawImage, NULL, image, NULL);

        glGenTextures(1, &m_texture);
        glBindTexture(GL_TEXTURE_2D, m_texture);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

        SDL_FreeSurface(rawImage);
        SDL_FreeSurface(image);
    }
}

Texture::~Texture() {
    glDeleteTextures(1, &m_texture);
}

void Texture::bind() {
    glBindTexture(GL_TEXTURE_2D, m_texture);
}
Was it helpful?

Solution

It seems that you are not loading the texture.

Once loaded, you need to bind it during rendering, using the texture id received when creating the GL texture, like this:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);

About on how to load a texture, there are many tutorials around the web, like this: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/

Note:

This might be a possible duplicate of OpenGL Texture Sampling not working

Edit: The problem lies in your texture loading. here glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); OpenGL expects a 4 channel image, but here SDL_CreateRGBSurface(0, rawImage->w, rawImage->h, 24, 0xff000000, 0x00ff0000, 0x0000ff00, 0); You are creating a 3 channel image, setting the alpha channel to zero. Alpha = 0 means full transparency. You need to change that to 0x000000FF, or do as below:

From http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlcreatergbsurface.html :

    Uint32 rmask, gmask, bmask, amask;

    /* SDL interprets each pixel as a 32-bit number, so our masks must depend
       on the endianness (byte order) of the machine */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif

    surface = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 32,
                                   rmask, gmask, bmask, amask);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top