If you use any game engine or a 3D software like Blender/Maya. Probably you know every componentz on scene/viewport have tranforms and some data. I will call this components as “Actor” -like Unreal did-.
Actor Class
// Actor.h
#pragma once
#include <vector>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
class Actor {
public: // everything is public - for now -
std::vector<float> points; // vertex
std::vector<unsigned int> indicies;
glm::vec3 location;
glm::vec3 rotation;
glm::vec3 scale;
glm::mat4 transform; // model matrix
Actor() {
location = glm::vec3(0, 0, 0);
rotation = glm::vec3(0, 0, 0);
scale = glm::vec3(1, 1, 1);
calculateTransform();
}
Actor(float size) : Actor() {
setCube(size);
}
void setCube(float size) {
// erticies of a cube
points = {
-size, -size, -size, 0.0f, 0.0f,
size, -size, -size, 1.0f, 0.0f,
size, size, -size, 1.0f, 1.0f,
-size, size, -size, 0.0f, 1.0f,
-size, -size, size, 0.0f, 0.0f,
size, -size, size, 1.0f, 0.0f,
size, size, size, 1.0f, 1.0f,
-size, size, size, 0.0f, 1.0f,
-size, size, size, 1.0f, 0.0f,
-size, size, -size, 1.0f, 1.0f,
-size, -size, -size, 0.0f, 1.0f,
-size, -size, size, 0.0f, 0.0f,
size, size, size, 1.0f, 0.0f,
size, size, -size, 1.0f, 1.0f,
size, -size, -size, 0.0f, 1.0f,
size, -size, size, 0.0f, 0.0f,
-size, -size, -size, 0.0f, 1.0f,
size, -size, -size, 1.0f, 1.0f,
size, -size, size, 1.0f, 0.0f,
-size, -size, size, 0.0f, 0.0f,
-size, size, -size, 0.0f, 1.0f,
size, size, -size, 1.0f, 1.0f,
size, size, size, 1.0f, 0.0f,
-size, size, size, 0.0f, 0.0f,
};
// calculate indicies
for (int i = 0; i < 6; i++) {
int offsset = i * 4;
indicies.push_back(offsset);
indicies.push_back(offsset + 1);
indicies.push_back(offsset + 2);
indicies.push_back(offsset);
indicies.push_back(offsset + 2);
indicies.push_back(offsset + 3);
}
}
void setLocation(glm::vec3 location) {
this->location = location;
calculateTransform();
}
void setLocation(float x, float y, float z) {
setLocation(glm::vec3(x, y, z));
}
void setRotation(glm::vec3 rotation) {
this->rotation = rotation;
calculateTransform();
}
void setRotation(float x, float y, float z){
setRotation(glm::vec3(x, y, z));
}
void setScale(glm::vec3 scale) {
this->scale = scale;
calculateTransform();
}
void setScale(float x, float y, float z) {
setScale(glm::vec3(x, y, z));
}
glm::mat4 modelMatrix() {
return transform;
}
void calculateTransform() {
transform = glm::mat4(1.0f);
transform = glm::scale(transform, scale);
transform = glm::rotate(transform, glm::radians(rotation.x), glm::vec3(1, 0, 0));
transform = glm::rotate(transform, glm::radians(rotation.y), glm::vec3(0, 1, 0));
transform = glm::rotate(transform, glm::radians(rotation.z), glm::vec3(0, 0, 1));
transform = glm::translate(transform, location);
}
std::vector<float> getPoints() {
return points;
}
std::vector<unsigned int> getIndicies() {
return indicies;
}
};
Main.cpp
Summary:
#include "Actor.h"
int main() {
// |>----------<>----------<>----------<>----------<>----------<|
// |> DEFINE VERTICES <|
// |>----------<>----------<>----------<>----------<>----------<|
Actor actor(50),actor2(100);
actor.setRotation(45,0,0);
actor2.setLocation(200, 300, 0);
unsigned int layout[]{ 3, GL_FLOAT,2,GL_FLOAT };
VertexArray va; va.Bind();
VertexBuffer vb(actor.getPoints().data(), sizeof(float) * actor.getPoints().size());
IndexBuffer ib(actor.getIndicies().data(), sizeof(unsigned int) * actor.getIndicies().size());
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);
proj = glm::perspective(glm::degrees(35.0f), w / h, 0.1f, 1000.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 <|
// |>----------<>----------<>----------<>----------<>----------<|
glEnable(GL_DEPTH_TEST);
va.Bind();
while (!glfwWindowShouldClose(window)) {
// Now we are also clean depth buffer.
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// show actor 1
vb.SetBufferData(actor.getPoints().data(), sizeof(float) * actor.getPoints().size());
ib.SetBufferData(actor.getIndicies().data(), sizeof(unsigned int) * actor.getIndicies().size());
model = actor.modelMatrix();
glm::mat4 mvp = proj * view * model;
shader.setUniformMat4f("u_MVP", mvp);
glDrawElements(GL_TRIANGLES, actor.getIndicies().size(), GL_UNSIGNED_INT, 0);
// show actor 2
vb.SetBufferData(actor2.getPoints().data(), sizeof(float) * actor2.getPoints().size());
ib.SetBufferData(actor2.getIndicies().data(), sizeof(unsigned int) * actor2.getIndicies().size());
model = actor2.modelMatrix();
mvp = proj * view * model;
shader.setUniformMat4f("u_MVP", mvp);
glDrawElements(GL_TRIANGLES, actor.getIndicies().size(), GL_UNSIGNED_INT, 0);
}
}
Non-summary
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <string>
#include <iostream>
#include "Shader.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Actor.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.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 <|
// |>----------<>----------<>----------<>----------<>----------<|
Actor actor(50),actor2(100);
actor.setRotation(45,0,0);
actor2.setLocation(200, 300, 0);
unsigned int layout[]{ 3, GL_FLOAT,2,GL_FLOAT };
VertexArray va; va.Bind();
VertexBuffer vb(actor.getPoints().data(), sizeof(float) * actor.getPoints().size());
IndexBuffer ib(actor.getIndicies().data(), sizeof(unsigned int) * actor.getIndicies().size());
vb.setLayout(layout,sizeof(layout));
va.Unbind();
// |>----------<>----------<>----------<>----------<>----------<|
// |> TEXTURE <|
// |>----------<>----------<>----------<>----------<>----------<|
// load and create a texture
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
unsigned char* data = stbi_load("res/horse-face.png", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
shader.SetUniform1i("texture1", 0);
// enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// |>----------<>----------<>----------<>----------<>----------<|
// |> 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);
proj = glm::perspective(glm::degrees(35.0f), w / h, 0.1f, 1000.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
// |>----------<>----------<>----------<>----------<>----------<|
// |> ImGUI <|
// |>----------<>----------<>----------<>----------<>----------<|
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 440");
//ImGui variables:
//bool show_demo_window = true;
//bool show_another_window = false;
float clear_color[]{ 0.45f, 0.55f, 0.60f, 1.00f };
// |>----------<>----------<>----------<>----------<>----------<|
// |> RENDER LOOP <|
// |>----------<>----------<>----------<>----------<>----------<|
glEnable(GL_DEPTH_TEST);
va.Bind();
while (!glfwWindowShouldClose(window)) {
// per-frame time logic
// --------------------
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
// clear
glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// show actor 1
vb.SetBufferData(actor.getPoints().data(), sizeof(float) * actor.getPoints().size());
ib.SetBufferData(actor.getIndicies().data(), sizeof(unsigned int) * actor.getIndicies().size());
model = actor.modelMatrix();
glm::mat4 mvp = proj * view * model;
shader.setUniformMat4f("u_MVP", mvp);
glDrawElements(GL_TRIANGLES, actor.getIndicies().size(), GL_UNSIGNED_INT, 0);
// show actor 2
vb.SetBufferData(actor2.getPoints().data(), sizeof(float) * actor2.getPoints().size());
ib.SetBufferData(actor2.getIndicies().data(), sizeof(unsigned int) * actor2.getIndicies().size());
model = actor2.modelMatrix();
mvp = proj * view * model;
shader.setUniformMat4f("u_MVP", mvp);
glDrawElements(GL_TRIANGLES, actor.getIndicies().size(), GL_UNSIGNED_INT, 0);
// render imgui
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("test");
ImGui::ColorEdit4("bg color", clear_color);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwPollEvents();
}
}
void processInput(GLFWwindow* window){
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = static_cast<float>(250 * deltaTime);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
view = glm::translate(view, glm::vec3(0, 0, 1) * cameraSpeed);
else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
view = glm::translate(view, glm::vec3(0, 0, -1) * 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);
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
view = glm::translate(view, glm::vec3(0, -1, 0) * cameraSpeed);
else if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
view = glm::translate(view, glm::vec3(0, 1, 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 w = width, h = height;
//proj = glm::ortho(0.0f, f, 0.0f, h, -1.0f, 1.0f);
proj = glm::perspective(glm::degrees(35.0f), w/h, 0.1f, 1000.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){
//...
}
void init_glad(){
//...
}
Vertex/Index Buffer
void IndexBuffer::SetBufferData(const void* data, unsigned int size){
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
void VertexBuffer::SetBufferData(const void* data, unsigned int size) {
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
Leave a Reply