1

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

1 Answer 1

1

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...

Sign up to request clarification or add additional context in comments.

1 Comment

@AleksanderFimreite: There is also glProgramUniform4fv (...), which started out life in the Direct State Access extension but became core when Separate Shader Objects did (GL 4.1) and does not require you to bind a program to set a uniform. Since you're using GLSL 1.20 it's safe to assume you have access to neither of these things. You might seriously consider renaming your class Program or ShaderProgram instead of Shader, since that's really what it is. You even have a member variable called m_shaders, which points out that the class is not a shader, but rather contains shaders.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.