Sebastian Karlsson
Sebastian Karlsson

Reputation: 745

OpenGL ortho projection is broken

So I just added ortho projection to my rendering and everything stopped rendering... If I remove it, it works again. This is my matrix code:

#include <stdlib.h>
#include <stdlib.h>
#include <math.h>


matrix4x4 init_matrix4x4() {
    matrix4x4 m = calloc(16, sizeof(float));

    m[0] = 1;    m[1] = 0;    m[2] = 0;    m[3] = 0;
    m[4] = 0;    m[5] = 1;    m[6] = 0;    m[7] = 0;
    m[8] = 0;    m[9] = 0;    m[10] = 1;   m[11] = 0;
    m[12] = 0;   m[13] = 0;   m[14] = 0;   m[15] = 1;

    return m;
}

void translate_matrix4x4(matrix4x4* matrix, float x, float y, float z) {
    matrix4x4 m = (*matrix);

    m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
    m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
    m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
    m[15] = m[3] * x + m[7] * y + m[11] * z + m[15]; 
}

void ortho_matrix4x4(matrix4x4* matrix, float left, float right, float bottom, float top, float near, float far) {
    matrix4x4 m = (*matrix);

    m[0] = 2 / (right-left);
    m[1] = 0;
    m[2] = 0;
    m[3] = 0;
    m[4] = 0;
    m[5] = 2 / (top - bottom);
    m[6] = 0;
    m[7] = 0;
    m[8] = 0;
    m[9] = 0;
    m[10] = 1 / (far - near);
    m[11] = 0;
    m[12] = (left + right) / (left - right);
    m[13] = (top + bottom) / (bottom - top);
    m[14] = near / (near - far);
    m[15] = 1;
}

void mat4_identity(matrix4x4* matrix) {
    matrix4x4 out = (*matrix);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[5] = 1;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[10] = 1;
    out[11] = 0;
    out[12] = 0;
    out[13] = 0;
    out[14] = 0;
    out[15] = 1;
}

void mat4_lookAtf(matrix4x4* matrix, float eye[3], float center[3], float up[3]) {
    matrix4x4 out = (*matrix);
    float x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
        eyex = eye[0],
        eyey = eye[1],
        eyez = eye[2],
        upx = up[0],
        upy = up[1],
        upz = up[2],
        centerx = center[0],
        centery = center[1],
        centerz = center[2];

    if (fabs(eyex - centerx) < 0.000001 &&
        fabs(eyey - centery) < 0.000001 &&
        fabs(eyez - centerz) < 0.000001) {
        mat4_identity(&out);
        return;
    }

    z0 = eyex - centerx;
    z1 = eyey - centery;
    z2 = eyez - centerz;

    len = 1 / sqrt/*f*/(z0 * z0 + z1 * z1 + z2 * z2);
    z0 *= len;
    z1 *= len;
    z2 *= len;

    x0 = upy * z2 - upz * z1;
    x1 = upz * z0 - upx * z2;
    x2 = upx * z1 - upy * z0;
    len = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
    if (!len) {
        x0 = 0;
        x1 = 0;
        x2 = 0;
    } else {
        len = 1 / len;
        x0 *= len;
        x1 *= len;
        x2 *= len;
    }

    y0 = z1 * x2 - z2 * x1;
    y1 = z2 * x0 - z0 * x2;
    y2 = z0 * x1 - z1 * x0;

    len = sqrt(y0 * y0 + y1 * y1 + y2 * y2);
    if (!len) {
        y0 = 0;
        y1 = 0;
        y2 = 0;
    } else {
        len = 1 / len;
        y0 *= len;
        y1 *= len;
        y2 *= len;
    }

    out[0] = x0;
    out[1] = y0;
    out[2] = z0;
    out[3] = 0;
    out[4] = x1;
    out[5] = y1;
    out[6] = z1;
    out[7] = 0;
    out[8] = x2;
    out[9] = y2;
    out[10] = z2;
    out[11] = 0;
    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
    out[15] = 1;
};

And here is the main.c , where I render things:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include "include/matrix.h"
#include "include/io.h"


const int WIDTH = 640;
const int HEIGHT = 480;

// called when user resizes window
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport(0, 0, width, height);
}

// called when we receive input
void processInput(GLFWwindow *window) {
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, 1);
}

GLuint get_checker_texture() {
    unsigned char texDat[64];
    for (int i = 0; i < 64; ++i)
        texDat[i] = ((i + (i / 8)) % 2) * 128 + 127;

    //upload to GPU texture
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, texDat);
    glGenerateMipmap(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    return tex;
}

//void render_box(renderable* this, unsigned int vbo, unsigned int vao, unsigned int ebo) {
//    draw_texture(this->texture, this->x, this->y, this->z, vbo, vao, ebo);
//}

int main(int argc, char* argv[]) {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    #ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // only on MACOS
    #endif

    // creating the window
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL App", NULL, NULL);
    if (window == NULL) {
        printf("Failed to create GLFW window");
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    // hook on window resize
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        printf("Failed to initialize GLAD");
        return -1;
    }

    printf("OpenGL %d.%d\n", GLVersion.major, GLVersion.minor);

    glEnable(GL_DEPTH_TEST);

    glViewport(0, 0, WIDTH, HEIGHT);

    unsigned int tex = get_checker_texture();

    const char* vertex_shader_src = read_file("res/shaders/textured_and_positioned.vs.glsl");

    unsigned int vertex_shader;
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_src, NULL);
    glCompileShader(vertex_shader); 

    int  success;
    char infoLog[512];
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);

    if (!success) {
        glGetShaderInfoLog(vertex_shader, 512, NULL, infoLog);
        printf("%s\n", infoLog);
    }

    const char* fragment_shader_src = read_file("res/shaders/textured_and_positioned.fs.glsl");

    unsigned int fragment_shader;
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_src, NULL);
    glCompileShader(fragment_shader);

    int  success0;
    char infoLog0[512];
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success0);

    if (!success0) {
        glGetShaderInfoLog(fragment_shader, 512, NULL, infoLog0);
        printf("%s\n", infoLog0);
    }

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertex_shader);
    glAttachShader(shaderProgram, fragment_shader);
    glLinkProgram(shaderProgram);

    unsigned uniform_sampler_ourTexture = glGetUniformLocation(shaderProgram, "ourTexture");
    unsigned uniform_mat4_model = glGetUniformLocation(shaderProgram, "model");
    unsigned uniform_mat4_view = glGetUniformLocation(shaderProgram, "view");
    unsigned uniform_mat4_perspective = glGetUniformLocation(shaderProgram, "perspective");

    int success1;
    char infoLog1[512];

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success1);
    if(!success1) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog1);
        printf("%s\n", infoLog1);
    }

    float vertices[] = {
         // positions          // colors           // texture coords
         0.1f,  0.1f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // top right
         0.1f, -0.1f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // bottom right
        -0.1f, -0.1f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // bottom left
        -0.1f,  0.1f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0     // top left 
    }; 

    unsigned elements[] = {
        0, 1, 2, // triangle
        2, 3, 0 // triangle
    };

    unsigned int vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    matrix4x4 model = init_matrix4x4();
    matrix4x4 view = init_matrix4x4();
    translate_matrix4x4(&view, 0.0f, 0.0f, 0.0f);


    float x = 0.0f;
    float y = 0.0f;
    float z = 0.0f;

    matrix4x4 perspective = calloc(16, sizeof(float));
    ortho_matrix4x4(&perspective, 0.0f, 640.0f, 0.0f, 480.0f, 0.1f, 100.0f);

    unsigned int vbo;
    glGenBuffers(1, &vbo);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(0 * sizeof(float)));
    glEnableVertexAttribArray(0);

    // colors
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // texture coords
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    unsigned int ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    glUseProgram(shaderProgram);

    glUniformMatrix4fv(uniform_mat4_view, 1, GL_FALSE, view);
    glUniformMatrix4fv(uniform_mat4_perspective, 1, GL_FALSE, perspective);


    // render loop
    while(!glfwWindowShouldClose(window)) {
        processInput(window);

        // render here
        glClearColor(
            0, 0, 0, 0
        );

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, tex);
        glUniform1i(uniform_sampler_ourTexture, 0);



        translate_matrix4x4(&model, x, y, z);
        glUniformMatrix4fv(uniform_mat4_model, 1, GL_FALSE, model);
        //x += 0.0001f;
        //y += 0.0001f;



        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();    
    }

    glfwTerminate();
    return 0;
}

Here is the vertex shader:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = perspective * view * model * vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}

Here is the fragment shader:

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D ourTexture;

void main()
{
    FragColor = vec4(vec3(texture(ourTexture, TexCoord).r), 1.);
}

Now, if I remove the perspective value from the shader, which is the ortho matrix, the checkered texture is rendered as it should. What is wrong here? Is it my shader or is it the matrix ortho function?

Upvotes: 1

Views: 184

Answers (1)

datenwolf
datenwolf

Reputation: 162174

Your matrices are stored in row-major, submit them to the uniforms without transposing and do calculations left-associative in the shader.

You can either

  • store in column major order

or

  • transpose upon loading into the uniform

or

  • switch to left-associative multiplication in the shader

Each to the same effect.

Upvotes: 1

Related Questions