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);
}
}
Leave a Reply