Search code examples
c++openglsfmlglm-math

Why does using a program cause my shape to disappear?


The following code draws a white square to the screen. If I uncomment the line that uses the program, the square disappears.

When I debug the program with GLIntercept, the texture appears in a folder called Images, and the log says that the shaders compiled. However, it also says that the program links, but doesn't validate.

I've been poring over this for hours and I have no idea where to go from here.

// Vertex.vert
#version 150 core

in vec3 in_position;
in vec2 in_texture;

out vec2 Texture;

uniform mat4 in_model;
uniform mat4 in_view;
uniform mat4 in_projection;

void main()
{
    gl_Position = in_projection * in_view * in_model * vec4(in_position, 1.0);
    Texture = in_texture;
}

// Fragment.frag
#version 150 core

in vec2 Texture;

out vec4 Colour;

uniform sampler2D Sampler2D;

void main()
{
    Colour = texture(Sampler2D, Texture);
}

// Source.cpp
#include <cfloat>
#include <iostream>
#include <string>
#include <vector>

#include <GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

#include "Archive.h"

using namespace glm;
using namespace sf;
using namespace std;

struct Camera
{
    vec3 Position = { 0.0f, 0.0f, 1.0f };
    vec3 Target = { 0.0f, 0.0f, 0.0f };
    vec3 Up = { 0.0f, 1.0f, 0.0f };

    float Fovy = 74.0f;
    float Aspect = 16.0f / 9.0f;
    float ZNear = FLT_MIN;
    float ZFar = FLT_MAX;

    mat4 View;
    mat4 Projection;
};

struct Actor
{
    vec3 Scale = { 1.0f, 1.0f, 1.0f };
    vec3 Rotation = { 0.0f, 0.0f, 0.0f };
    vec3 Position = { 0.0f, 0.0f, 0.0f };

    vector<GLfloat> Vertices;
    vector<GLuint> Elements;

    GLuint Texture;

    Actor(string fileName)
    {
        Image image;

        if (!image.loadFromFile(fileName + ".png"))
        {
            cerr << "ERROR: Unable to load texture" << endl;
        }

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

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glGenerateMipmap(GL_TEXTURE_2D);

        // Draw a square instead of the actual model
        Vertices.push_back(-1.0f); Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(0.0f);
        Vertices.push_back(1.0f);  Vertices.push_back(-1.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(0.0f);
        Vertices.push_back(1.0f);  Vertices.push_back(1.0f);  Vertices.push_back(0.0f); Vertices.push_back(1.0f); Vertices.push_back(1.0f);
        Vertices.push_back(-1.0f); Vertices.push_back(1.0f);  Vertices.push_back(0.0f); Vertices.push_back(0.0f); Vertices.push_back(1.0f);

        Elements.push_back(0); Elements.push_back(1); Elements.push_back(2);
        Elements.push_back(2); Elements.push_back(3); Elements.push_back(0);
    }
};

GLuint CreateShader(GLenum shaderType, string fileName, Archive& archive)
{
    string source;

    archive.open(fileName);
    source.resize(archive.getSize());
    archive.read(&source[0], archive.getSize());

    GLuint shader = glCreateShader(shaderType);
    const char* pointer = source.c_str();

    glShaderSource(shader, 1, &pointer, nullptr);
    glCompileShader(shader);

    GLsizei length;

    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);

    if (length > 1)
    {
        GLchar* infoLog = new GLchar[length];

        glGetShaderInfoLog(shader, length, &length, infoLog);

        cerr << infoLog << endl;

        delete[] infoLog;
    }

    return shader;
}

GLuint CreateProgram(GLuint vertex, GLuint fragment)
{
    GLuint program = glCreateProgram();

    glAttachShader(program, vertex);
    glAttachShader(program, fragment);

    glLinkProgram(program);

    GLsizei length;

    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);

    if (length > 1)
    {
        GLchar* infoLog = new GLchar[length];

        glGetProgramInfoLog(program, length, &length, infoLog);

        cerr << infoLog << endl;

        delete[] infoLog;
    }

    return program;
}

int main(int argc, char* argv[])
{
    Window window(VideoMode(1920, 1080), "");

    window.setVerticalSyncEnabled(true);

    if (!window.setActive(true))
    {
        cerr << "ERROR: Unable to set the window as the current target for OpenGL rendering" << endl;

        return 1;
    }

    glewExperimental = GL_TRUE;

    if (glewInit() != GLEW_OK)
    {
        cerr << "ERROR: Unable to initialise GLEW" << endl;

        return 1;
    }

    Archive shaders("Shaders.lea");
    Archive models("Models.lea");

    Actor actor("tree01");

    GLuint vertex = CreateShader(GL_VERTEX_SHADER, "Vertex.vert", shaders);
    GLuint fragment = CreateShader(GL_FRAGMENT_SHADER, "Fragment.frag", shaders);
    GLuint program = CreateProgram(vertex, fragment);

    GLuint vertexArray;
    GLuint vertexBuffer;
    GLuint elementBuffer;

    glGenVertexArrays(1, &vertexArray);
    glBindVertexArray(vertexArray);

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    glGenBuffers(1, &elementBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);

    // glUseProgram(program);

    GLint position = glGetAttribLocation(program, "in_position");

    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
    glEnableVertexAttribArray(position);

    GLint texture = glGetAttribLocation(program, "in_texture");

    glVertexAttribPointer(texture, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 3));
    glEnableVertexAttribArray(texture);

    GLint projection = glGetUniformLocation(program, "in_projection");
    GLint view = glGetUniformLocation(program, "in_view");
    GLint model = glGetUniformLocation(program, "in_model");

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    Camera camera;

    while (window.isOpen())
    {
        // Input handling code omitted

        camera.View = lookAt(camera.Position, camera.Target, camera.Up);
        camera.Projection = perspective(radians(camera.Fovy), camera.Aspect, camera.ZNear, camera.ZFar);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUniformMatrix4fv(projection, 1, GL_FALSE, value_ptr(camera.Projection));
        glUniformMatrix4fv(view, 1, GL_FALSE, value_ptr(camera.View));

        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * actor.Vertices.size(), &actor.Vertices[0], GL_STATIC_DRAW);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * actor.Elements.size(), &actor.Elements[0], GL_STATIC_DRAW);

        mat4 transform = translate(mat4(), actor.Position);
        transform *= rotate(transform, actor.Rotation.z, vec3(0.0f, 0.0f, 1.0f));
        transform *= rotate(transform, actor.Rotation.y, vec3(0.0f, 1.0f, 0.0f));
        transform *= rotate(transform, actor.Rotation.x, vec3(1.0f, 0.0f, 0.0f));
        transform *= scale(transform, actor.Scale);

        glUniformMatrix4fv(model, 1, GL_FALSE, value_ptr(transform));

        glBindTexture(GL_TEXTURE_2D, actor.Texture);

        glDrawElements(GL_TRIANGLES, actor.Elements.size(), GL_UNSIGNED_INT, 0);

        window.display();
    }

    glUseProgram(0);

    glDisableVertexAttribArray(texture);
    glDisableVertexAttribArray(position);

    glDeleteBuffers(1, &elementBuffer);
    glDeleteBuffers(1, &vertexBuffer);

    glDeleteVertexArrays(1, &vertexArray);

    glDetachShader(program, fragment);
    glDetachShader(program, vertex);

    glDeleteShader(fragment);
    glDeleteShader(vertex);

    glDeleteProgram(program);

    return 0;
}

Solution

  • It was a combination of two things.

    When I last used this code, it was with GLM 0.9.7.6, and mat4() generated an identity matrix. However, at some point between that version of GLM and the one I'm currently using (0.9.9.5), mat4() started generating an empty matrix. Instead, you need mat4(1.0f).

    Also, I used bad values for the near and far planes. I did think that the values I had would work, but clearly I don't quite understand what's going on behind the scenes.