Search code examples
c++openglglsltransformation

How to add a rotation to a simple triangle, using GLSL?


I work on a OpenGL application in C++. I have come to the point where I render a colored triangle in the window. This works. Now that I have added some uniform transformation, the triangle is no longer renderered and I only see the black background of the window. My GLSL is set up as follows:

#version 450 core

layout (location = 0) in vec3 aPos;   // the position variable has attribute position 0
layout (location = 1) in vec3 aColor; // the color variable has attribute position 1

out vec3 ourColor; // output a color to the fragment shader

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(aPos, 1.0f);
    ourColor = aColor; // set ourColor to the input color we got from the vertex data
}  

In the code for my triangle, I add a transformation according to this tutorial. The entire code (that includes setting up a shader program and more) is set up like this:

void Triangle::create() {
    ExtensionController::getInstance().glGenVertexArrays(1, &getVAO());
    ExtensionController::getInstance().glBindVertexArray(getVAO());

    // Vertex Buffer in GPU memory with vertex input data.
    ExtensionController::getInstance().glGenBuffers(1, &getVBO());
    ExtensionController::getInstance().glBindBuffer(GL_ARRAY_BUFFER, getVBO());
    ExtensionController::getInstance().glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);

    Shader shader{ "vertexShader.glsl", "fragmentShader.glsl" };
    setShaderProgram(shader.load());


    glm::mat4 trans = glm::mat4(1.0f);
    trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 1.0f));
    trans = glm::scale(trans, glm::vec3(0.9, 0.9, 0.9));
    GLuint program = getShaderProgram();
    unsigned int transformLoc = ExtensionController::getInstance().glGetUniformLocation(program, "transform");
    ExtensionController::getInstance().glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

    ExtensionController::getInstance().glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    ExtensionController::getInstance().glEnableVertexAttribArray(0);

    ExtensionController::getInstance().glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    ExtensionController::getInstance().glEnableVertexAttribArray(1);
}

Lastly, my vertices look like this:

vertices = {
    0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,
    0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f
};

A lot of code for the simplicity of a rotated triangle, but that is how core OpenGL in C++ is. I don't use any library like GLFW, GLUT or GLEW.

As I stated earlier, removing the transform from the code in create() and removing it from vertexShader.glsl makes the triangle visible and rendered again. Setting the transform to the identity matrix also does not render the triangle in the window, so it looks like the transform is not passed on to the shader correctly, but I'm not sure.

I hope someone can help me identify what the underlying problem is here. Thanks in advance.


Solution

  • First, set which shader program should be used for the current rendering state (with glUseProgram). Only afterwards can the uniform values be set (e.g. with glUniformMatrix4fv).

    The other way around, OpenGL doesn't know which shader program the uniform location belongs to and the glUniform* call will fail. As a result, transform in the vertex shader will most likely contain uninitialized values, which explains the black screen.