Question

I have successfully set up a shader and a test triangle for OpenGL. And I want to set up a transformation uniform that can be applied in the vertex shader. Problem is, I can't see my object anymore after I multiply my vec4 position with the mat4 transform. Where am I doing something wrong?

Vertex shader:

#version 120

attribute vec3 vertices;
attribute vec3 colors;
attribute vec2 texCoords;

uniform mat4 transform;

varying vec3 shared_colors;
varying vec2 shared_texCoords;

void main() {
    gl_Position = transform * vec4(vertices, 1.0);

    //Send data to fragment shader
    shared_colors = colors;
    shared_texCoords = texCoords;
}

Fragment shader:

#version 120

uniform sampler2D diffuse;

varying vec3 shared_colors;
varying vec2 shared_texCoords;

void main() {
    gl_FragColor = vec4(shared_colors, 1);
    //gl_FragColor = texture2D(diffuse, shared_texCoords); //vec4(1, 0, 0, 1);
}

Shader class:

#include "Shader.h"



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_COLOR, "colors");
    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");

    m_uniforms[UNI_TRANSFORM] = glGetUniformLocation(m_program, "transform");
}

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::update(Transform *matrix) {
    glm::mat4 model = matrix->getModel();
    glUniformMatrix4fv(m_uniforms[UNI_TRANSFORM], 1, GL_FALSE, &model[0][0]);
}

void Shader::enable(bool state) {
    if (state) {
        glUseProgram(m_program);
    }
    else {
        glUseProgram(NULL);
    }
}

Mesh class (or, my object class if you rather call it that):

#include "Mesh.h"



Mesh::Mesh() {
    initMesh();
}

Mesh::Mesh(ObjectData *obj) {
    initMesh();

    //Set object to parameter
    object = obj;
    initVBO();
}

Mesh::~Mesh() {
    delete transform;

    //Delete buffer
    glDeleteBuffers(VBO_COUNT, buffers);

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

void Mesh::draw() {
    if (initialized) {
        shader->update(transform);
        shader->enable(true);
        texture->enable(true);

        //Tell OpenGL which array to use
        glBindVertexArray(arrayObject);

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

        glBindVertexArray(NULL);
        shader->enable(false);
        texture->enable(false);
    }
}

void Mesh::initMesh() {
    initialized = false;
    shader = new Shader(DIR_SHADERS + "BasicShader");
    transform = new Transform();
}

void Mesh::initVBO() {
    glGenVertexArrays(1, &arrayObject);

    //Tell OpenGL which vertex array to use from now
    glBindVertexArray(arrayObject);

    glGenBuffers(VBO_COUNT, buffers);

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

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

    //Set shader attribute data
    glEnableVertexAttribArray(VBO_COLOR);
    glVertexAttribPointer(VBO_COLOR, 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);
    initialized = true;
}

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

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

    //Set shader attribute data
    glEnableVertexAttribArray(VBO_COLOR);
    glVertexAttribPointer(VBO_COLOR, 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::setShader(string file) {
    shader = new Shader(file);
}

void Mesh::setTexture(string file) {
    texture = new Texture(file);
}

void Mesh::loadObject(string file) {
    //Example object
    object = new ObjectData();

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

    //object->vertices.push_back(glm::vec3(0.5, 0.5, 0));
    //object->vertices.push_back(glm::vec3(0.75, 1, 0));
    //object->vertices.push_back(glm::vec3(1, 0.5, 0));
    //object->texCoords.push_back(glm::vec2(0, 0));
    //object->texCoords.push_back(glm::vec2(0.5, 1));
    //object->texCoords.push_back(glm::vec2(1, 0));
    //object->colors.push_back(glm::vec3(0, 255, 0));
    //object->colors.push_back(glm::vec3(0, 255, 0));
    //object->colors.push_back(glm::vec3(0, 255, 0));

    if (initialized) {
        updateVBO();
    }
    else {
        initVBO();
    }
}

Transform class:

#include "Transform.h"



Transform::Transform() {
    position = glm::vec3();
    rotation = glm::vec3();
    scale = glm::vec3(1, 1, 1);
}

Transform::~Transform() {

}

void Transform::setPosition(glm::vec3 pos) {
    position = pos;
}

void Transform::setRotation(glm::vec3 rot) {
    rotation = rot;
}

void Transform::setScale(glm::vec3 sca) {
    scale = sca;
}

glm::vec3 Transform::getPosition() {
    return position;
}

glm::vec3 Transform::getRotation() {
    return rotation;
}

glm::vec3 Transform::getScale() {
    return scale;
}

glm::mat4 Transform::getModel() {
    glm::mat4 pos = glm::translate(position);
    glm::mat4 rotX = glm::rotate(rotation.x, glm::vec3(1, 0, 0));
    glm::mat4 rotY = glm::rotate(rotation.y, glm::vec3(0, 1, 0));
    glm::mat4 rotZ = glm::rotate(rotation.z, glm::vec3(0, 0, 1));
    glm::mat4 sca = glm::scale(scale);

    glm::mat4 rot = rotZ * rotY * rotX;
    glm::mat4 finalMatrix = pos * rot * sca;

    return finalMatrix;
}
Was it helpful?

Solution

From your code:

void Mesh::draw() {
    if (initialized) {
        shader->update(transform);
        shader->enable(true);

GL uniforms are per program state, and setting a uniform will affect the currently bound program object. Since you do not have the program object bound at the time you try to set the uniform, the uniform is left at its default state (all zeros). Just switch these two lines...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top