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);
}


Comments

Leave a Reply

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