์ด์ 3D ์ขํ๋ฅผ 2D ์ขํ๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ํตํด ์ค์ 3D ๊ฐ์ฒด๋ฅผ ๋ ๋๋งํ ์ ์๋ค.
โ ๋ณํ ํ๋ ฌ ์ ์
3D ๊ฐ์ฒด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ํด ๋จผ์ ๋ชจ๋ธ ํ๋ ฌ์ ์์ฑํ๋ค. ๋ชจ๋ธ ํ๋ ฌ์ ๊ฐ์ฒด์ ๋ชจ๋ ์ ์ ์ Global World Space๋ก ๋ณํํ๊ธฐ ์ํด ์ ์ฉํ๊ณ ์ ํ๋ ํํ์ด๋, ์ค์ผ์ผ๋ง, ํ์ ๋ฑ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
- Model Matrix (๋ชจ๋ธ ํ๋ ฌ)
glm::mat4 model = glm::mat4(1.0f);
// ํ๋ฉด์ x์ถ์ ๊ธฐ์ค์ผ๋ก ํ์ ์์ผ ๋ฐ๋ฅ์ ๋์ธ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ฒ ํ๋ค.
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
์ด ๋ชจ๋ธ ํ๋ ฌ๊ณผ ์ ์ ์ขํ๋ฅผ ๊ณฑํจ์ผ๋ก์จ ์ ์ ์ขํ๋ฅผ ์๋ ์ขํ๋ก ๋ณํํ๋ค.
๋ค์์ผ๋ก ๊ฐ์ฒด๊ฐ ๋ณด์ด๋๋ก ํ๊ธฐ ์ํด ์ฌ์์ ์ฝ๊ฐ ๋ค๋ก ๋ฌผ๋ฌ๋๋ ค ํ๋๋ฐ, ์นด๋ฉ๋ผ๋ฅผ ๋ค๋ก ์ด๋์ํค๋ ๊ฒ์ ์ ์ฒด ์ฌ์ ์์ผ๋ก ์ด๋์ํค๋ ๊ฒ๊ณผ ๊ฐ๋ค.
์ด๋ฅผ ์ํด View Matrix (๋ทฐ ํ๋ ฌ)์ ์์ฑํ์ฌ ์นด๋ฉ๋ผ๊ฐ ์ด๋ํ๊ณ ์ ํ๋ ๋ฐฉํฅ์ ๋ฐ๋๋ก ์ ์ฒด ์ฌ์ ์ด๋์ํจ๋ค.
์ฐ๋ฆฌ(์นด๋ฉ๋ผ)๊ฐ ๋ค๋ก ์ด๋ํ๋ ค๋ฉด ์์ z์ถ ๋ฐฉํฅ์ผ๋ก ์ด๋ํด์ผ ํ๋ค. ๋ฐ๋ผ์ ์ฌ์ ์์ z์ถ ๋ฐฉํฅ์ผ๋ก ์ด๋์ํฌ ๊ฒ์ด๋ค.
- View Matrix (๋ทฐ ํ๋ ฌ)
glm::mat4 view = glm::mat4(1.0f);
// ์ ์ฒด ์ฌ์ ์์ z์ถ ๋ฐฉํฅ์ผ๋ก ํํ์ด๋์ํจ๋ค.
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
- Projection Matrix (ํฌ์ ํ๋ ฌ)
glm::mat4 projection;
// Perspective Projection ์ฌ์ฉ
projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
โ ์ ฐ์ด๋์ ์ ๋ฌ
์ด์ ๋ณํ ํ๋ ฌ๋ค์ ์์ฑํ์ผ๋, ์ด๋ฅผ ์
ฐ์ด๋์ ์ ๋ฌํด์ผ ํ๋ค. ๋จผ์ ๋ณํ ํ๋ ฌ์ Vertex Shader์์ uniform์ผ๋ก ์ ์ธํ๊ณ , ๊ทธ๊ฒ๋ค์ ์ ์ ์ขํ์ ๊ณฑํ๋ค.
- Vertex Shader
#version 330 core
layout (location = 0) in vec3 aPos;
...
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
// ํ๋ ฌ์ ๊ณฑ์
์ด๋ฏ๋ก ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์์ผ๋ก ๊ณฑํ๋ค.
gl_Position = projection * view * model * vec4(aPos, 1.0);
...
}
๊ทธ๋ฆฌ๊ณ ๋ณํ ํ๋ ฌ์ ์ ฐ์ด๋์ ๋ณด๋ธ๋ค. (๋ณํ ํ๋ ฌ์ ์์ฃผ ๋ณ๋๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก ๋งค ํ๋ ์๋ง๋ค ์ํ๋๋ค)
// ๋ชจ๋ธ ํ๋ ฌ
int modelLoc = glGetUniformLocation(ourShader.ID, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
// ๋ทฐ ํ๋ ฌ
int viewLoc = glGetUniformLocation(ourShader.ID, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
// ํฌ์ ํ๋ ฌ
int projectionLoc = glGetUniformLocation(ourShader.ID, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
* ํฌ์ ํ๋ ฌ์ ํํ๊ฒ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฏ๋ก ๋ฃจํ ๋ฐ์์ ํ ๋ฒ๋ง ์ค์ ํ๋ ๊ฒ์ด ์ข๋ค.

โ ์์ค ์ฝ๋
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <Shader.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
float mixPercent = 0.0f;
int main()
{
// ---------- [ 1. GLFW, GLAD ์ธํ
] ----------
// GLFW ์ด๊ธฐํ ๋ฐ ์ค์
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// GLFW ์๋์ฐ ์์ฑ
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// GLAD - OpenGL ํจ์ ํฌ์ธํฐ๋ฅผ ๋ก๋
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// ์
ฐ์ด๋ ํ๋ก๊ทธ๋จ ๋น๋ ๋ฐ ์ปดํ์ผ
Shader ourShader("Shaders/Shader.vert", "Shaders/Shader.frag");
// ---------- [ 2. ์ ์ ๋ฐ์ดํฐ ์
๋ ฅ / ์ ์ ์์ฑ ๊ตฌ์ฑ ] ----------
float vertices[] = {
// ์์น // ์ปฌ๋ฌ // ํ
์ค์ฒ ์ขํ
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // ์ฐ์ธก ์๋จ
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, // ์ฐ์ธก ํ๋จ
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // ์ข์ธก ํ๋จ
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 2.0f // ์ข์ธก ์๋จ
};
unsigned int indices[] = {
0, 1, 3, // ์ฒซ ๋ฒ์งธ ์ผ๊ฐํ
1, 2, 3 // ๋ ๋ฒ์งธ ์ผ๊ฐํ
};
// VAO, VBO, EBO ์์ฑ
// VAO: VBO์ ์ ์ ์์ฑ ํฌ์ธํฐ์ ์ํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๊ฐ์ฒด
// VBO: GPU ๋ฉ๋ชจ๋ฆฌ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฒํผ ๊ฐ์ฒด
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// ์ ์ ๋ฐฐ์ด ๊ฐ์ฒด(VAO) ๋ฐ์ธ๋ฉ
glBindVertexArray(VAO);
// ์ ์ ๋ฒํผ ๊ฐ์ฒด(VBO)๋ฅผ ๋ฐ์ธ๋ฉ
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// ๋ฐ์ธ๋ฉ๋ ๋ฒํผ ๊ฐ์ฒด์ vertices ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ๊ณ ,๋ฒํผ ๊ฐ์ฒด์ ํฌ๊ธฐ์ ๋ฐ์ดํฐ ์ค์
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Position Attribute ๊ตฌ์ฑ
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Color Attribute ๊ตฌ์ฑ
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Texture coord Attribute ๊ตฌ์ฑ
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// ๋ค๋ฅธ VAO ํธ์ถ์ด ์ด VAO๋ฅผ ์ค์๋ก ์์ ํ์ง ์๋๋ก VAO๋ฅผ ๋ฐ์ธ๋ฉ ํด์ ํ ์ ์์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก๋ VAO(๋ฐ VBO)๋ฅผ ๋ฐ์ธ๋ฉ ํด์ ํ์ง ์๋๋ค.
// glBindVertexArray(0);
// ---------- [ 3. ํ
์ค์ฒ ๋ก๋ ๋ฐ ์์ฑ ] ----------
// ํ
์ค์ฒ ๊ฐ์ฒด ์์ฑ (2๊ฐ)
unsigned int texture1, texture2;
// ์ํ ๋ฐ์ ์ค์
stbi_set_flip_vertically_on_load(true);
// < ํ
์ค์ฒ 1 >
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// Wrapping ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Filtering ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// ์ด๋ฏธ์ง ๋ก๋ (jpg)
int width, height, nrChannels;
unsigned char* data = stbi_load("Textures/container.jpg", &width, &height, &nrChannels, 0);
// ํ
์ค์ฒ ์์ฑ (RGB)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// ๋ฉ๋ชจ๋ฆฌ ๋ฐํ
stbi_image_free(data);
// < ํ
์ค์ฒ 2 >
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// Wrapping ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Filtering ์ต์
์ค์
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// ์ด๋ฏธ์ง ๋ก๋ (png)
data = stbi_load("Textures/awesomeface.png", &width, &height, &nrChannels, 0);
// ํ
์ค์ฒ ์์ฑ (RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// ๋ฉ๋ชจ๋ฆฌ ๋ฐํ
stbi_image_free(data);
// ์
ฐ์ด๋ ํ์ฑํ
ourShader.use();
// ์
ฐ์ด๋ ํ๋ก๊ทธ๋จ์ uniform ๋ณ์ ์ค์ (๋งค๊ฐ ๋ณ์ : 1.location, 2.ํ
์ค์ฒ ์ ๋ ์ธ๋ฑ์ค)
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0);
ourShader.setInt("texture2", 1); // ๋๋ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง shader ํด๋์ค ์ฌ์ฉ
// ---------- [ 4. ๋ ๋ ๋ฃจํ ] ----------
while (!glfwWindowShouldClose(window))
{
// ์
๋ ฅ ์ฒ๋ฆฌ
processInput(window);
ourShader.setFloat("mixPercent", mixPercent);
// ๋ฐฐ๊ฒฝ ๋ ๋
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// ๊ฐ๊ฐ์ ํ
์ค์ฒ ์ ๋์ ํ
์ค์ฒ ๋ฐ์ธ๋ฉ
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
// ๋ํ์ ํ
์ค์ฒ ๋ ๋
ourShader.use();
// ---------- [ 5. 3D ๋ณํ ] ----------
// ๋ชจ๋ธ ํ๋ ฌ
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
// ๋ทฐ ํ๋ ฌ
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
// ํฌ์ ํ๋ ฌ
glm::mat4 projection = glm::mat4(1.0f);
projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
// pass them to the shaders
unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");
unsigned int viewLoc = glGetUniformLocation(ourShader.ID, "view");
unsigned int projectionLoc = glGetUniformLocation(ourShader.ID, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
// ๋ณํ ํ๋ ฌ์ ์ด์ฉํด ๋ณํ๋ ์ ์ ๋ค์ ๊ทธ๋ฆฐ๋ค
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// ํ๋ก ํธ, ๋ฐฑ ๋ฒํผ ๊ต์ฒด
glfwSwapBuffers(window);
// ์ด๋ฒคํธ ์ฒ๋ฆฌ
glfwPollEvents();
}
// VAO, VBO, EBO ๋ฉ๋ชจ๋ฆฌ ํด์
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// ์ฌ์ฉ๋ ๋ฆฌ์์ค ํด์ , ์ด๊ธฐํ ๋ฐ ์ ๋ฆฌ ์์
glfwTerminate();
return 0;
}
// ์
๋ ฅ ์ฒ๋ฆฌ ํจ์
void processInput(GLFWwindow* window)
{
// ESC๊ฐ ๋๋ฆฌ๋ฉด ์๋์ฐ ๋ซ๊ธฐ
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
{
mixPercent += 0.05f;
}
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
{
mixPercent -= 0.05f;
}
}
// ์๋์ฐ ์ฌ์ด์ฆ ๋ณ๊ฒฝ ์ ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
- ๋งํฌ
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] ์์ผ๊ฐ(FOV), ํ๋ฉด๋น(Aspect Ratio) (0) | 2024.08.08 |
|---|---|
| [OpenGL] 3์ฐจ์ ๊ฐ์ฒด ๋ ๋ 2 (0) | 2024.08.08 |
| [OpenGL] ์ขํ๊ณ (Coordinate System) (0) | 2024.08.02 |
| [OpenGL] ๋ณํ (Transformation) (0) | 2024.07.30 |
| [OpenGL] ํ๋ ฌ (Matrix) (0) | 2024.07.30 |