https://jsantell.com/model-view-projection/

basic.shader

#shader vertex
#version 330 core                                                                               
layout (location = 0) in vec2 aPos;             
uniform float time;

uniform mat4 u_MVP; //we add MVP matrix as an uniform

                                                                                                
void main() {                                   
   gl_Position = u_MVP * vec4(aPos.x, aPos.y, 0.0, 1.0);
}                                               

#shader fragment
#version 330 core                                                                                   
out vec4 FragColor;                                                                                 
                                                  
void main() {                                     
   FragColor = vec4(0.9f, 0.2f, 0.2f, 1.0f);      
}                                                 

// Shader.h 
#include <glm/glm.hpp>

void setUniformMat4f(const std::string& name, const glm::mat4& mat);


// Shader.cpp
void Shader::setUniformMat4f(const std::string& name, const glm::mat4& mat) {
    glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, &mat[0][0]);
}

// main.cpp
#include <glad/glad.h> 
#include <GLFW/glfw3.h> 
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include <string>
#include <iostream>

#include "Shader.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"

void processInput(GLFWwindow* window);
void size_callback(GLFWwindow* window, int width, int height);
GLFWwindow* create_GLFWwindow(float width, float height, std::string title);
void init_glad();


Shader shader; 

float SCR_WIDTH = 640, SCR_HEIGHT = 480;
std::string SCR_TITLE = "My 3D App";

glm::mat4 proj, view, model;
float currentFrame, lastFrame, deltaTime;


int main() {
    GLFWwindow* window = create_GLFWwindow(SCR_WIDTH, SCR_HEIGHT, SCR_TITLE);
    init_glad();

    shader.Compile();
    shader.Bind();

    // |>----------<>----------<>----------<>----------<>----------<|
    // |>                      DEFINE VERTICES                     <|
    // |>----------<>----------<>----------<>----------<>----------<|

    float vertices[]{
        -0.5f, -0.5f, // 0 - bottom left 
            0.5f, -0.5f, // 1 - bottom right
            0.5f,  0.5f, // 2 - top right
        -0.5f,  0.5f, // 3 - top left

    };
    for (float& i : vertices) i *= 200; // we scale our shape 
    unsigned int indices[] = { 
        0, 1, 2,  // first Triangle
        0, 2, 3   // second Triangle
    };
    unsigned int layout[]{ 2, GL_FLOAT };

    VertexArray va; va.Bind();
    VertexBuffer vb(&vertices[0], sizeof(vertices));
    IndexBuffer ib(indices, sizeof(indices));

    vb.setLayout(layout,sizeof(layout));
    va.Unbind();
        


    // |>----------<>----------<>----------<>----------<>----------<|
    // |>                          CAMERA                          <|
    // |>----------<>----------<>----------<>----------<>----------<|
    // set our initial values 
    float w = SCR_WIDTH;
    float h = SCR_HEIGHT;
    proj = glm::ortho(0.0f, w, 0.0f, h, -1.0f, 1.0f);
    view = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0));
    model = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0));
    glm::mat4 mvp = proj * view * model;
    shader.setUniformMat4f("u_MVP", mvp); // update our uniform 

    // |>----------<>----------<>----------<>----------<>----------<|
    // |>                       RENDER LOOP                        <|
    // |>----------<>----------<>----------<>----------<>----------<|

    va.Bind();

    while (!glfwWindowShouldClose(window)) {
        // per-frame time logic
        // --------------------
        float currentFrame = static_cast<float>(glfwGetTime());
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        processInput(window);
        

        glClearColor(0.2f, 0.2f, 0.2f, 1.0f); 
        glClear(GL_COLOR_BUFFER_BIT); 

        // update and redraw model matrix 9 times
        for(int i = 0; i<3; i++)
            for (int j = 0; j < 3; j++) {
                model = glm::translate(glm::mat4(1.0f), glm::vec3(i * 250, j * 250, 0));
                glm::mat4 mvp = proj * view * model;
                shader.setUniformMat4f("u_MVP", mvp);
                glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);

            }

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

}


void processInput(GLFWwindow* window){
    // exit with ESC key 
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);


    // update the view matrix 
    float cameraSpeed = static_cast<float>(250 * deltaTime);

    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        view = glm::translate(view, glm::vec3(0, -1, 0) * cameraSpeed);
    else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        view = glm::translate(view, glm::vec3(0, 1, 0) * cameraSpeed);

    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        view = glm::translate(view, glm::vec3(1, 0, 0) * cameraSpeed);
    else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        view = glm::translate(view, glm::vec3(-1, 0, 0) * cameraSpeed);

    
    glm::mat4 mvp = proj * view * model;
    shader.setUniformMat4f("u_MVP", mvp);
}


void size_callback(GLFWwindow* window, int width, int height) {
    std::cout << "New width: " << width << "\theight: " << height << std::endl;

    // update the projection matrix 
    float f = width, h = height;
    proj = glm::ortho(0.0f, f, 0.0f, h, -1.0f, 1.0f);
    glm::mat4 mvp = proj * view * model;
    shader.setUniformMat4f("u_MVP", mvp);

    glViewport(0, 0, width, height);
}

GLFWwindow* create_GLFWwindow(float width, float height, std::string title){
    // |>----------<>----------<>----------<>----------<>----------<|
    // |>                    CREATE GLFW WINDOW                    <|
    // |>----------<>----------<>----------<>----------<>----------<|

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        //return EXIT_FAILURE;
    }
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1); // VSYNC
    //This function sets the swap interval for the current OpenGL or OpenGL ES context, i.e. the number of screen updates to wait from the time glfwSwapBuffers was called before swapping the buffers and returning. This is sometimes called vertical synchronization, vertical retrace synchronization or just vsync. 
    // https://www.glfw.org/docs/3.3/group__context.html#ga6d4e0cdf151b5e579bd67f13202994ed

    glfwSetFramebufferSizeCallback(window, size_callback); // we bind callback to our size_callback func. 

    return window;
}

void init_glad(){
    // |>----------<>----------<>----------<>----------<>----------<|
    // |>               LOAD OPENGL FUNCTION POINTERS              <|
    // |>----------<>----------<>----------<>----------<>----------<|

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        exit(EXIT_FAILURE);
    }

}


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *